Autopsy  4.13.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
MessageContentViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2017-2019 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;
20 
22 import com.google.gson.Gson;
23 import java.awt.Color;
24 import java.awt.Component;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Optional;
30 import java.util.Set;
31 import java.util.logging.Level;
32 import javax.swing.text.JTextComponent;
33 import org.apache.commons.lang3.StringUtils;
34 import org.jsoup.Jsoup;
35 import org.jsoup.nodes.Document;
36 import org.openide.explorer.ExplorerManager;
37 import org.openide.nodes.AbstractNode;
38 import org.openide.nodes.Children;
39 import org.openide.nodes.Node;
40 import org.openide.util.NbBundle;
41 import org.openide.util.lookup.ServiceProvider;
50 import org.sleuthkit.datamodel.AbstractFile;
51 import org.sleuthkit.datamodel.BlackboardArtifact;
52 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
53 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
54 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
55 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
56 import org.sleuthkit.datamodel.BlackboardAttribute;
57 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
58 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
59 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_RCVD;
60 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION;
61 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CC;
62 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML;
63 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN;
64 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF;
65 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM;
66 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO;
67 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HEADERS;
68 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM;
69 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
70 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
71 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT;
72 import org.sleuthkit.datamodel.Content;
73 import org.sleuthkit.datamodel.SleuthkitCase;
74 import org.sleuthkit.datamodel.TskCoreException;
75 import org.sleuthkit.datamodel.blackboardutils.FileAttachment;
76 import org.sleuthkit.datamodel.blackboardutils.MessageAttachments;
77 import org.sleuthkit.datamodel.blackboardutils.Attachment;
78 import org.sleuthkit.datamodel.blackboardutils.URLAttachment;
79 
83 @ServiceProvider(service = DataContentViewer.class, position = 5)
84 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
85 public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
86 
87  private static final long serialVersionUID = 1L;
88  private static final Logger LOGGER = Logger.getLogger(MessageContentViewer.class.getName());
89  private static final BlackboardAttribute.Type TSK_ASSOCIATED_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
90 
91  private static final int HDR_TAB_INDEX = 0;
92  private static final int TEXT_TAB_INDEX = 1;
93  private static final int HTML_TAB_INDEX = 2;
94  private static final int RTF_TAB_INDEX = 3;
95  private static final int ATTM_TAB_INDEX = 4;
96 
97  private final List<JTextComponent> textAreas;
102  private BlackboardArtifact artifact;
103  private final DataResultPanel drp;
104  private ExplorerManager drpExplorerManager;
105 
109  @NbBundle.Messages("MessageContentViewer.AtrachmentsPanel.title=Attachments")
111  initComponents();
112  htmlPane.add(htmlPanel);
113  envelopePanel.setBackground(new Color(0, 0, 0, 38));
114  drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
115  attachmentsScrollPane.setViewportView(drp);
116  msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
117 
118  /*
119  * HTML tab uses the HtmlPanel instead of an internal text pane, so we
120  * use 'null' for that index.
121  */
122  textAreas = Arrays.asList(headersTextArea, textbodyTextArea, null, rtfbodyTextPane);
123 
124  Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
125  resetComponent();
126 
127  }
128 
129  @Override
130  public void addNotify() {
131  super.addNotify(); //To change body of generated methods, choose Tools | Templates.
132 
133  drp.open();
134  drpExplorerManager = drp.getExplorerManager();
135  drpExplorerManager.addPropertyChangeListener(evt
136  -> viewInNewWindowButton.setEnabled(drpExplorerManager.getSelectedNodes().length == 1));
137  }
138 
144  @SuppressWarnings("unchecked")
145  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
146  private void initComponents() {
147 
148  envelopePanel = new javax.swing.JPanel();
149  fromLabel = new javax.swing.JLabel();
150  datetimeText = new javax.swing.JLabel();
151  fromText = new javax.swing.JLabel();
152  toLabel = new javax.swing.JLabel();
153  toText = new javax.swing.JLabel();
154  ccLabel = new javax.swing.JLabel();
155  ccText = new javax.swing.JLabel();
156  subjectLabel = new javax.swing.JLabel();
157  subjectText = new javax.swing.JLabel();
158  directionText = new javax.swing.JLabel();
159  msgbodyTabbedPane = new javax.swing.JTabbedPane();
160  headersScrollPane = new javax.swing.JScrollPane();
161  headersTextArea = new javax.swing.JTextArea();
162  textbodyScrollPane = new javax.swing.JScrollPane();
163  textbodyTextArea = new javax.swing.JTextArea();
164  htmlPane = new javax.swing.JPanel();
165  rtfbodyScrollPane = new javax.swing.JScrollPane();
166  rtfbodyTextPane = new javax.swing.JTextPane();
167  attachmentsPanel = new javax.swing.JPanel();
168  viewInNewWindowButton = new javax.swing.JButton();
169  attachmentsScrollPane = new javax.swing.JScrollPane();
170 
171  envelopePanel.setBackground(new java.awt.Color(204, 204, 204));
172 
173  org.openide.awt.Mnemonics.setLocalizedText(fromLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.fromLabel.text")); // NOI18N
174 
175  datetimeText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
176  org.openide.awt.Mnemonics.setLocalizedText(datetimeText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.datetimeText.text")); // NOI18N
177 
178  org.openide.awt.Mnemonics.setLocalizedText(fromText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.fromText.text")); // NOI18N
179 
180  org.openide.awt.Mnemonics.setLocalizedText(toLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.toLabel.text")); // NOI18N
181 
182  org.openide.awt.Mnemonics.setLocalizedText(toText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.toText.text")); // NOI18N
183  toText.setAutoscrolls(true);
184  toText.setMinimumSize(new java.awt.Dimension(27, 14));
185 
186  org.openide.awt.Mnemonics.setLocalizedText(ccLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.ccLabel.text")); // NOI18N
187 
188  org.openide.awt.Mnemonics.setLocalizedText(ccText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.ccText.text")); // NOI18N
189  ccText.setMinimumSize(new java.awt.Dimension(27, 14));
190 
191  org.openide.awt.Mnemonics.setLocalizedText(subjectLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.subjectLabel.text")); // NOI18N
192 
193  org.openide.awt.Mnemonics.setLocalizedText(subjectText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.subjectText.text")); // NOI18N
194  subjectText.setMinimumSize(new java.awt.Dimension(26, 14));
195 
196  directionText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
197  org.openide.awt.Mnemonics.setLocalizedText(directionText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.directionText.text")); // NOI18N
198 
199  javax.swing.GroupLayout envelopePanelLayout = new javax.swing.GroupLayout(envelopePanel);
200  envelopePanel.setLayout(envelopePanelLayout);
201  envelopePanelLayout.setHorizontalGroup(
202  envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
203  .addGroup(envelopePanelLayout.createSequentialGroup()
204  .addGap(5, 5, 5)
205  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
206  .addGroup(envelopePanelLayout.createSequentialGroup()
207  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
208  .addComponent(fromLabel)
209  .addComponent(toLabel))
210  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
211  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
212  .addGroup(envelopePanelLayout.createSequentialGroup()
213  .addComponent(toText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
214  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
215  .addComponent(directionText, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE))
216  .addGroup(envelopePanelLayout.createSequentialGroup()
217  .addComponent(fromText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
218  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
219  .addComponent(datetimeText, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE))))
220  .addGroup(envelopePanelLayout.createSequentialGroup()
221  .addComponent(ccLabel)
222  .addGap(26, 26, 26)
223  .addComponent(ccText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
224  .addGroup(envelopePanelLayout.createSequentialGroup()
225  .addComponent(subjectLabel)
226  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
227  .addComponent(subjectText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
228  .addGap(5, 5, 5))
229  );
230  envelopePanelLayout.setVerticalGroup(
231  envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
232  .addGroup(envelopePanelLayout.createSequentialGroup()
233  .addGap(5, 5, 5)
234  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
235  .addComponent(fromLabel)
236  .addComponent(datetimeText)
237  .addComponent(fromText))
238  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
239  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
240  .addComponent(toLabel)
241  .addComponent(toText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
242  .addComponent(directionText))
243  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
244  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
245  .addComponent(ccLabel)
246  .addComponent(ccText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
247  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
248  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
249  .addComponent(subjectLabel)
250  .addComponent(subjectText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
251  .addGap(5, 5, 5))
252  );
253 
254  headersScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
255  headersScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
256 
257  headersTextArea.setEditable(false);
258  headersTextArea.setColumns(20);
259  headersTextArea.setLineWrap(true);
260  headersTextArea.setRows(5);
261  headersTextArea.setWrapStyleWord(true);
262  headersScrollPane.setViewportView(headersTextArea);
263 
264  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.headersScrollPane.TabConstraints.tabTitle"), headersScrollPane); // NOI18N
265 
266  textbodyScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
267  textbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
268 
269  textbodyTextArea.setEditable(false);
270  textbodyTextArea.setLineWrap(true);
271  textbodyTextArea.setRows(5);
272  textbodyTextArea.setWrapStyleWord(true);
273  textbodyScrollPane.setViewportView(textbodyTextArea);
274 
275  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N
276 
277  htmlPane.setLayout(new java.awt.BorderLayout());
278  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
279 
280  rtfbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
281 
282  rtfbodyTextPane.setEditable(false);
283  rtfbodyScrollPane.setViewportView(rtfbodyTextPane);
284 
285  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.rtfbodyScrollPane.TabConstraints.tabTitle"), rtfbodyScrollPane); // NOI18N
286 
287  org.openide.awt.Mnemonics.setLocalizedText(viewInNewWindowButton, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.viewInNewWindowButton.text")); // NOI18N
288  viewInNewWindowButton.addActionListener(new java.awt.event.ActionListener() {
289  public void actionPerformed(java.awt.event.ActionEvent evt) {
290  viewInNewWindowButtonActionPerformed(evt);
291  }
292  });
293 
294  javax.swing.GroupLayout attachmentsPanelLayout = new javax.swing.GroupLayout(attachmentsPanel);
295  attachmentsPanel.setLayout(attachmentsPanelLayout);
296  attachmentsPanelLayout.setHorizontalGroup(
297  attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
298  .addGroup(attachmentsPanelLayout.createSequentialGroup()
299  .addGap(0, 0, 0)
300  .addGroup(attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
301  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, attachmentsPanelLayout.createSequentialGroup()
302  .addComponent(viewInNewWindowButton)
303  .addGap(3, 3, 3))
304  .addComponent(attachmentsScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)))
305  );
306  attachmentsPanelLayout.setVerticalGroup(
307  attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
308  .addGroup(attachmentsPanelLayout.createSequentialGroup()
309  .addGap(0, 0, 0)
310  .addComponent(viewInNewWindowButton)
311  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
312  .addComponent(attachmentsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
313  .addGap(0, 0, 0))
314  );
315 
316  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle"), attachmentsPanel); // NOI18N
317 
318  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
319  this.setLayout(layout);
320  layout.setHorizontalGroup(
321  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
322  .addGroup(layout.createSequentialGroup()
323  .addGap(5, 5, 5)
324  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
325  .addComponent(msgbodyTabbedPane)
326  .addComponent(envelopePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
327  .addGap(5, 5, 5))
328  );
329  layout.setVerticalGroup(
330  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
331  .addGroup(layout.createSequentialGroup()
332  .addGap(5, 5, 5)
333  .addComponent(envelopePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
334  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
335  .addComponent(msgbodyTabbedPane)
336  .addGap(5, 5, 5))
337  );
338  }// </editor-fold>//GEN-END:initComponents
339 
340  private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed
341  new NewWindowViewAction("View in new window", drpExplorerManager.getSelectedNodes()[0]).actionPerformed(evt);
342  }//GEN-LAST:event_viewInNewWindowButtonActionPerformed
343 
344 
345  // Variables declaration - do not modify//GEN-BEGIN:variables
346  private javax.swing.JPanel attachmentsPanel;
347  private javax.swing.JScrollPane attachmentsScrollPane;
348  private javax.swing.JLabel ccLabel;
349  private javax.swing.JLabel ccText;
350  private javax.swing.JLabel datetimeText;
351  private javax.swing.JLabel directionText;
352  private javax.swing.JPanel envelopePanel;
353  private javax.swing.JLabel fromLabel;
354  private javax.swing.JLabel fromText;
355  private javax.swing.JScrollPane headersScrollPane;
356  private javax.swing.JTextArea headersTextArea;
357  private javax.swing.JPanel htmlPane;
358  private javax.swing.JTabbedPane msgbodyTabbedPane;
359  private javax.swing.JScrollPane rtfbodyScrollPane;
360  private javax.swing.JTextPane rtfbodyTextPane;
361  private javax.swing.JLabel subjectLabel;
362  private javax.swing.JLabel subjectText;
363  private javax.swing.JScrollPane textbodyScrollPane;
364  private javax.swing.JTextArea textbodyTextArea;
365  private javax.swing.JLabel toLabel;
366  private javax.swing.JLabel toText;
367  private javax.swing.JButton viewInNewWindowButton;
368  // End of variables declaration//GEN-END:variables
369 
370  @Override
371  public void setNode(Node node) {
372  if (node == null) {
373  resetComponent();
374  return;
375  }
376 
377  artifact = getNodeArtifact(node);
378  if (artifact == null) {
379  resetComponent();
380  return;
381  }
382 
383  /*
384  * If the artifact is a keyword hit, use the associated artifact as the
385  * one to show in this viewer
386  */
387  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
388  try {
389  getAssociatedArtifact(artifact).ifPresent(associatedArtifact -> {
390  artifact = associatedArtifact;
391  });
392  } catch (TskCoreException ex) {
393  LOGGER.log(Level.SEVERE, "error getting associated artifact", ex);
394  }
395  }
396 
397  if (artifact.getArtifactTypeID() == TSK_MESSAGE.getTypeID()) {
398  displayMsg();
399  } else if (artifact.getArtifactTypeID() == TSK_EMAIL_MSG.getTypeID()) {
400  displayEmailMsg();
401  } else {
402  resetComponent();
403  }
404  }
405 
416  private static Optional<BlackboardArtifact> getAssociatedArtifact(final BlackboardArtifact artifact) throws TskCoreException {
417  BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_TYPE);
418  if (attribute != null) {
419  return Optional.of(artifact.getSleuthkitCase().getArtifactByArtifactId(attribute.getValueLong()));
420  }
421  return Optional.empty();
422  }
423 
424  @Override
425  @NbBundle.Messages("MessageContentViewer.title=Message")
426  public String getTitle() {
427  return Bundle.MessageContentViewer_title();
428  }
429 
430  @Override
431  @NbBundle.Messages("MessageContentViewer.toolTip=Displays messages.")
432  public String getToolTip() {
433  return Bundle.MessageContentViewer_toolTip();
434  }
435 
436  @Override
437  public DataContentViewer createInstance() {
438  return new MessageContentViewer();
439  }
440 
441  @Override
442  public Component getComponent() {
443  return this;
444  }
445 
446  @Override
447  final public void resetComponent() {
448  // reset all fields
449  fromText.setText("");
450  fromLabel.setEnabled(false);
451  toText.setText("");
452  toLabel.setEnabled(false);
453  ccText.setText("");
454  ccLabel.setEnabled(false);
455  subjectText.setText("");
456  subjectLabel.setEnabled(false);
457  datetimeText.setText("");
458  datetimeText.setEnabled(false);
459  directionText.setText("");
460  directionText.setEnabled(false);
461 
462  headersTextArea.setText("");
463  rtfbodyTextPane.setText("");
464  htmlPanel.reset();
465  textbodyTextArea.setText("");
466  msgbodyTabbedPane.setEnabled(false);
467  drp.setNode(null);
468  }
469 
470  @Override
471  public boolean isSupported(Node node) {
472  BlackboardArtifact nodeArtifact = getNodeArtifact(node);
473 
474  if (nodeArtifact == null) {
475  return false;
476  }
477  //if the artifact is a keyword hit, check if its associated artifact is a message or email.
478  if (nodeArtifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
479  try {
480  if (getAssociatedArtifact(nodeArtifact).map(MessageContentViewer::isMessageArtifact).orElse(false)) {
481  return true;
482  }
483  } catch (TskCoreException ex) {
484  LOGGER.log(Level.SEVERE, "error getting associated artifact", ex);
485  }
486  }
487  return isMessageArtifact(nodeArtifact);
488  }
489 
499  private static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
500  final int artifactTypeID = nodeArtifact.getArtifactTypeID();
501  return artifactTypeID == TSK_EMAIL_MSG.getTypeID()
502  || artifactTypeID == TSK_MESSAGE.getTypeID();
503  }
504 
516  private BlackboardArtifact getNodeArtifact(Node node) {
517  BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
518 
519  if (nodeArtifact == null) {
520  try {
521  SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
522  AbstractFile file = node.getLookup().lookup(AbstractFile.class);
523  if (file != null) {
524  List<BlackboardArtifact> artifactsList = tskCase.getBlackboardArtifacts(TSK_ASSOCIATED_OBJECT, file.getId());
525 
526  for (BlackboardArtifact fileArtifact : artifactsList) {
527  BlackboardAttribute associatedArtifactAttribute = fileArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
528  if (associatedArtifactAttribute != null) {
529  BlackboardArtifact associatedArtifact = fileArtifact.getSleuthkitCase().getBlackboardArtifact(associatedArtifactAttribute.getValueLong());
530  if (isMessageArtifact(associatedArtifact)) {
531  nodeArtifact = associatedArtifact;
532  }
533  }
534  }
535  }
536  } catch (NoCurrentCaseException | TskCoreException ex) {
537  LOGGER.log(Level.SEVERE, "Failed to get file for selected node.", ex); //NON-NLS
538  }
539  }
540 
541  return nodeArtifact;
542  }
543 
544  @Override
545  public int isPreferred(Node node) {
546  // For message artifacts this is a high priority viewer,
547  // but for attachment files, this a lower priority vewer.
548  if (isSupported(node)) {
549  BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
550  if (nodeArtifact != null) {
551  return 7;
552  } else {
553  return 1;
554  }
555  }
556  return 0;
557  }
558 
568  private void configureTextArea(BlackboardAttribute.ATTRIBUTE_TYPE type, int index) throws TskCoreException {
569  String attributeText = getAttributeValueSafe(artifact, type);
570 
571  if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
572  htmlPanel.setHtmlText(attributeText);
573  } else {
574  JTextComponent textComponent = textAreas.get(index);
575  if (textComponent != null) {
576  textComponent.setText(attributeText);
577  textComponent.setCaretPosition(0); //make sure we start at the top
578  }
579  }
580 
581  final boolean hasText = attributeText.length() > 0;
582 
583  msgbodyTabbedPane.setEnabledAt(index, hasText);
584  if (hasText) {
585  msgbodyTabbedPane.setSelectedIndex(index);
586  }
587  }
588 
589  private void enableCommonFields() {
590  msgbodyTabbedPane.setEnabled(true);
591  fromLabel.setEnabled(true);
592  toLabel.setEnabled(true);
593  subjectLabel.setEnabled(true);
594  datetimeText.setEnabled(true);
595  }
596 
597  private void configureAttachments() throws TskCoreException {
598 
599  final Set<Attachment> attachments;
600 
601  // Attachments are specified in an attribute TSK_ATTACHMENTS as JSON attribute
602  BlackboardAttribute attachmentsAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
603  if(attachmentsAttr != null) {
604 
605  attachments = new HashSet<>();
606  String jsonVal = attachmentsAttr.getValueString();
607  MessageAttachments msgAttachments = new Gson().fromJson(jsonVal, MessageAttachments.class);
608 
609  Collection<FileAttachment> fileAttachments = msgAttachments.getFileAttachments();
610  for (FileAttachment fileAttachment: fileAttachments) {
611  attachments.add(fileAttachment);
612  }
613  Collection<URLAttachment> urlAttachments = msgAttachments.getUrlAttachments();
614  for (URLAttachment urlAttachment: urlAttachments) {
615  attachments.add(urlAttachment);
616  }
617  } else { // For backward compatibility - email attachements are derived files and children of the email message artifact
618  attachments = new HashSet<>();
619  for (Content child: artifact.getChildren()) {
620  if (child instanceof AbstractFile) {
621  attachments.add(new FileAttachment((AbstractFile)child));
622  }
623  }
624  }
625 
626  final int numberOfAttachments = attachments.size();
627 
628  msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
629  msgbodyTabbedPane.setTitleAt(ATTM_TAB_INDEX, "Attachments (" + numberOfAttachments + ")");
630  drp.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(
631  new AttachmentsChildren(attachments))), true));
632  }
633 
634  private static String wrapInHtmlBody(String htmlText) {
635  return "<html><body>" + htmlText + "</body></html>";
636  }
637 
638  private void displayEmailMsg() {
639  enableCommonFields();
640 
641  directionText.setEnabled(false);
642  ccLabel.setEnabled(true);
643 
644  try {
645  this.fromText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
646  this.fromText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
647  this.toText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
648  this.toText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
649  this.directionText.setText("");
650  this.ccText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
651  this.ccText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
652  this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
653  this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME_RCVD));
654 
655  configureTextArea(TSK_HEADERS, HDR_TAB_INDEX);
656  configureTextArea(TSK_EMAIL_CONTENT_PLAIN, TEXT_TAB_INDEX);
657  configureTextArea(TSK_EMAIL_CONTENT_HTML, HTML_TAB_INDEX);
658  configureTextArea(TSK_EMAIL_CONTENT_RTF, RTF_TAB_INDEX);
659  configureAttachments();
660  } catch (TskCoreException ex) {
661  LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS
662  }
663  }
664 
665  private void displayMsg() {
666  enableCommonFields();
667 
668  directionText.setEnabled(true);
669  ccLabel.setEnabled(false);
670 
671  try {
672  this.fromText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_FROM));
673  this.toText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_TO));
674  this.directionText.setText(getAttributeValueSafe(artifact, TSK_DIRECTION));
675  this.ccText.setText("");
676  this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
677  this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME));
678 
679  msgbodyTabbedPane.setEnabledAt(HTML_TAB_INDEX, false);
680  msgbodyTabbedPane.setEnabledAt(RTF_TAB_INDEX, false);
681  msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
682  msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
683  configureTextArea(TSK_TEXT, TEXT_TAB_INDEX);
684  configureAttachments();
685  } catch (TskCoreException ex) {
686  LOGGER.log(Level.WARNING, "Failed to get attributes for message.", ex); //NON-NLS
687  }
688  }
689 
690  private static String getAttributeValueSafe(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException {
691  return Optional.ofNullable(artifact.getAttribute(new BlackboardAttribute.Type(type)))
692  .map(BlackboardAttribute::getDisplayString)
693  .orElse("");
694  }
695 
703  static private String cleanseHTML(String htmlInString) {
704 
705  Document doc = Jsoup.parse(htmlInString);
706 
707  //fix all img tags
708  doc.select("img[src]").forEach(img -> img.attr("src", ""));
709 
710  return doc.html();
711  }
712 
713 
717  private static class AttachmentsChildren extends Children.Keys<Attachment> {
718 
719  private final Set<Attachment> attachments;
720 
721  AttachmentsChildren(Set<Attachment> attachments) {
722  this.attachments = attachments;
723  }
724 
725  @Override
726  protected Node[] createNodes(Attachment t) {
727  return new Node[]{new AttachmentNode(t)};
728  }
729 
730  @Override
731  protected void addNotify() {
732  super.addNotify();
733  setKeys(attachments);
734  }
735  }
736 }
static void configureTextPaneAsRtf(JTextPane pane)
Definition: Utilities.java:52
static String getAttributeValueSafe(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type)
void configureTextArea(BlackboardAttribute.ATTRIBUTE_TYPE type, int index)
static boolean isMessageArtifact(BlackboardArtifact nodeArtifact)
static DataResultPanel createInstanceUninitialized(String title, String description, Node currentRootNode, int childNodeCount, DataContent customContentView)
static Optional< BlackboardArtifact > getAssociatedArtifact(final BlackboardArtifact artifact)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt)

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