Autopsy  4.5.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractedContentViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2018 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.keywordsearch;
20 
21 import java.awt.Component;
22 import java.awt.Cursor;
23 import java.awt.event.ActionEvent;
24 import java.awt.event.ActionListener;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.logging.Level;
29 import org.openide.nodes.Node;
30 import org.openide.util.Lookup;
31 import org.openide.util.NbBundle;
32 import org.openide.util.lookup.ServiceProvider;
37 import org.sleuthkit.datamodel.AbstractFile;
38 import org.sleuthkit.datamodel.Account;
39 import org.sleuthkit.datamodel.BlackboardArtifact;
40 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
41 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
42 import org.sleuthkit.datamodel.BlackboardAttribute;
43 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
44 import org.sleuthkit.datamodel.Content;
45 import org.sleuthkit.datamodel.TskCoreException;
46 
51 @ServiceProvider(service = DataContentViewer.class, position = 4)
52 public class ExtractedContentViewer implements DataContentViewer {
53 
54  private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName());
55 
56  private static final BlackboardAttribute.Type TSK_ASSOCIATED_ARTIFACT_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
57  public static final BlackboardAttribute.Type TSK_ACCOUNT_TYPE = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE);
58 
59  private ExtractedContentPanel panel;
60  private volatile Node currentNode = null;
61  private IndexedText currentSource = null;
62 
69  }
70 
76  @Override
77  public void setNode(final Node node) {
78  // Clear the viewer.
79  if (node == null) {
80  currentNode = null;
81  resetComponent();
82  return;
83  }
84 
85  /*
86  * This deals with the known bug with an unknown cause where setNode is
87  * sometimes called twice for the same node.
88  */
89  if (node == currentNode) {
90  return;
91  } else {
92  currentNode = node;
93  }
94 
95  /*
96  * Assemble a collection of all of the indexed text "sources" for the
97  * node.
98  */
99  List<IndexedText> sources = new ArrayList<>();
100  Lookup nodeLookup = node.getLookup();
101 
102  AdHocQueryResult adHocQueryResult = nodeLookup.lookup(AdHocQueryResult.class);
103  AbstractFile file = null;
104  BlackboardArtifact artifact;
105 
106  /*
107  * If we have an ad hoc query result, pull the file and artifact objects
108  * from that. Otherwise, pull them from the lookup.
109  */
110  if (adHocQueryResult != null) {
111  artifact = adHocQueryResult.getArtifact();
112  Content content = adHocQueryResult.getContent();
113  if (content instanceof AbstractFile) {
114  file = (AbstractFile) content;
115  }
116  } else {
117  artifact = nodeLookup.lookup(BlackboardArtifact.class);
118  file = nodeLookup.lookup(AbstractFile.class);
119  }
120 
121  /*
122  * First, get text with highlighted hits if this node is for a search
123  * result.
124  */
125  IndexedText highlightedHitText = null;
126  if (adHocQueryResult != null) {
127  /*
128  * The node is an ad hoc search result node.
129  */
130  highlightedHitText = new HighlightedText(adHocQueryResult.getSolrObjectId(), adHocQueryResult.getResults());
131  } else if (artifact != null) {
132  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
133  /*
134  * The node is a keyword hit artifact node.
135  */
136  try {
137  highlightedHitText = new HighlightedText(artifact);
138  } catch (TskCoreException ex) {
139  logger.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS
140  }
141  } else if (artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID() && file != null) {
142  try {
143  BlackboardAttribute attribute = artifact.getAttribute(TSK_ACCOUNT_TYPE);
144  if (attribute != null && Account.Type.CREDIT_CARD.getTypeName().equals(attribute.getValueString())) {
145  /*
146  * The node is an credit card account node.
147  */
148  highlightedHitText = getAccountsText(file, nodeLookup);
149  }
150  } catch (TskCoreException ex) {
151  logger.log(Level.SEVERE, "Failed to create AccountsText for " + file, ex); //NON-NLS
152  }
153  }
154  }
155  if (highlightedHitText != null) {
156  sources.add(highlightedHitText);
157  }
158 
159  /*
160  * Next, add the "raw" (not highlighted) text, if any, for any file
161  * associated with the node.
162  */
163  IndexedText rawContentText = null;
164  if (file != null) {
165  rawContentText = new RawText(file, file.getId());
166  sources.add(rawContentText);
167  }
168 
169  /*
170  * Finally, add the "raw" (not highlighted) text, if any, for any
171  * artifact associated with the node.
172  */
173  IndexedText rawArtifactText = null;
174  try {
175  rawArtifactText = getRawArtifactText(artifact);
176  if (rawArtifactText != null) {
177  sources.add(rawArtifactText);
178  }
179  } catch (TskCoreException ex) {
180  logger.log(Level.SEVERE, "Error creating RawText for " + file, ex); //NON-NLS
181  }
182 
183  // Now set the default source to be displayed.
184  if (highlightedHitText != null) {
185  currentSource = highlightedHitText;
186  } else if (rawArtifactText != null) {
187  currentSource = rawArtifactText;
188  } else {
189  currentSource = rawContentText;
190  }
191 
192  // Push the text sources into the panel.
193  for (IndexedText source : sources) {
194  int currentPage = source.getCurrentPage();
195  if (currentPage == 0 && source.hasNextPage()) {
196  source.nextPage();
197  }
198  }
199  panel.updateControls(currentSource);
200 
201  String contentName = "";
202  if (file != null) {
203  contentName = file.getName();
204  }
205  setPanel(contentName, sources);
206 
207  }
208 
209  static private IndexedText getRawArtifactText(BlackboardArtifact artifact) throws TskCoreException {
210  IndexedText rawArtifactText = null;
211  if (null != artifact) {
212  /*
213  * For keyword hit artifacts, add the text of the artifact that hit,
214  * not the hit artifact; otherwise add the text for the artifact.
215  */
216  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()
217  || artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) {
218 
219  BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE);
220  if (attribute != null) {
221  long artifactId = attribute.getValueLong();
222  BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactId);
223  rawArtifactText = new RawText(associatedArtifact, associatedArtifact.getArtifactID());
224 
225  }
226 
227  } else {
228  rawArtifactText = new RawText(artifact, artifact.getArtifactID());
229  }
230  }
231  return rawArtifactText;
232  }
233 
234  static private IndexedText getAccountsText(Content content, Lookup nodeLookup) throws TskCoreException {
235  /*
236  * get all the credit card artifacts
237  */
238  //if the node had artifacts in the lookup use them, other wise look up all credit card artifacts for the content.
239  Collection<? extends BlackboardArtifact> artifacts = nodeLookup.lookupAll(BlackboardArtifact.class);
240  artifacts = (artifacts == null || artifacts.isEmpty())
241  ? content.getArtifacts(TSK_ACCOUNT)
242  : artifacts;
243 
244  return new AccountsText(content.getId(), artifacts);
245  }
246 
247  private void scrollToCurrentHit() {
248  final IndexedText source = panel.getSelectedSource();
249  if (source == null || !source.isSearchable()) {
250  return;
251  }
252 
253  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(source.currentItem()));
254  }
255 
256  @Override
257  public String getTitle() {
258  return NbBundle.getMessage(this.getClass(), "ExtractedContentViewer.getTitle");
259  }
260 
261  @Override
262  public String getToolTip() {
263  return NbBundle.getMessage(this.getClass(), "ExtractedContentViewer.toolTip");
264  }
265 
266  @Override
267  public DataContentViewer createInstance() {
268  return new ExtractedContentViewer();
269  }
270 
271  @Override
272  public synchronized Component getComponent() {
273  if (panel == null) {
274  panel = new ExtractedContentPanel();
275  panel.addPrevMatchControlListener(new PrevFindActionListener());
276  panel.addNextMatchControlListener(new NextFindActionListener());
277  panel.addPrevPageControlListener(new PrevPageActionListener());
278  panel.addNextPageControlListener(new NextPageActionListener());
279  panel.addSourceComboControlListener(new SourceChangeActionListener());
280  }
281  return panel;
282  }
283 
284  @Override
285  public void resetComponent() {
286 
287  panel.resetDisplay();
288  currentNode = null;
289  currentSource = null;
290  }
291 
292  @Override
293  public boolean isSupported(Node node) {
294  if (node == null) {
295  return false;
296  }
297 
298  /*
299  * If the lookup of the node contains an ad hoc search result object,
300  * then there must be indexed text that produced the hit.
301  */
302  AdHocQueryResult adHocQueryResult = node.getLookup().lookup(AdHocQueryResult.class);
303  if (adHocQueryResult != null) {
304  return true;
305  }
306 
307  /*
308  * If the lookup of the node contains either a keyword hit artifact or a
309  * credit card account artifact from a credit card account numbers
310  * search, then there must be indexed text that produced the hit(s).
311  */
312  BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
313  if (artifact != null) {
314  final int artifactTypeID = artifact.getArtifactTypeID();
315  if (artifactTypeID == TSK_KEYWORD_HIT.getTypeID()) {
316  return true;
317  } else if (artifactTypeID == TSK_ACCOUNT.getTypeID()) {
318  try {
319  BlackboardAttribute attribute = artifact.getAttribute(TSK_ACCOUNT_TYPE);
320  if (attribute != null && Account.Type.CREDIT_CARD.getTypeName().equals(attribute.getValueString())) {
321  return true;
322  }
323  } catch (TskCoreException ex) {
324  /*
325  * If there was an error checking the account type, fall
326  * back to the check below for the file associated with the
327  * account (if there is one).
328  */
329  logger.log(Level.SEVERE, "Error getting TSK_ACCOUNT_TYPE attribute from artifact " + artifact.getArtifactID(), ex);
330  }
331  }
332  }
333 
334  /*
335  * If the lookup of the node contains a file, check to see if there is
336  * indexed text for the file. Note that there should be a file in the
337  * lookup of all nodes except artifact nodes that are associated with a
338  * data source instead of a file.
339  */
340  AbstractFile file = node.getLookup().lookup(AbstractFile.class);
341  if (file != null && solrHasContent(file.getId())) {
342  return true;
343  }
344 
345  /*
346  * If the lookup of the node contains an artifact that is neither a
347  * keyword hit artifact nor a credit card account artifact, and the
348  * artifact is not associated with a file, check to see if there is
349  * indexed text for the artifact.
350  */
351  if (artifact != null) {
352  return solrHasContent(artifact.getArtifactID());
353  }
354 
355  return false;
356  }
357 
358  @Override
359  public int isPreferred(Node node) {
360  BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
361  if (artifact == null) {
362  return 4;
363  } else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
364  return 6;
365  } else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
366  try {
367  BlackboardAttribute attribute = artifact.getAttribute(TSK_ACCOUNT_TYPE);
368  if (attribute != null && Account.Type.CREDIT_CARD.getTypeName().equals(attribute.getValueString())) {
369  return 6;
370  } else {
371  return 4;
372  }
373  } catch (TskCoreException ex) {
374  logger.log(Level.SEVERE, "Error getting TSK_ACCOUNT_TYPE attribute from artifact " + artifact.getArtifactID(), ex);
375  return 4;
376  }
377  } else {
378  return 4;
379  }
380  }
381 
390  private void setPanel(String contentName, List<IndexedText> sources) {
391  if (panel != null) {
392  panel.setSources(contentName, sources);
393  }
394  }
395 
403  private boolean solrHasContent(Long objectId) {
404  final Server solrServer = KeywordSearch.getServer();
405  if (solrServer.coreIsOpen() == false) {
406  return false;
407  }
408 
409  try {
410  return solrServer.queryIsIndexed(objectId);
412  logger.log(Level.SEVERE, "Error querying Solr server", ex); //NON-NLS
413  return false;
414  }
415  }
416 
417  private class NextFindActionListener implements ActionListener {
418 
419  @Override
420  public void actionPerformed(ActionEvent e) {
421  IndexedText source = panel.getSelectedSource();
422  if (source == null) {
423  // reset
424  panel.updateControls(null);
425  return;
426  }
427  final boolean hasNextItem = source.hasNextItem();
428  final boolean hasNextPage = source.hasNextPage();
429  int indexVal;
430  if (hasNextItem || hasNextPage) {
431  if (!hasNextItem) {
432  //flip the page
433  nextPage();
434  indexVal = source.currentItem();
435  } else {
436  indexVal = source.nextItem();
437  }
438 
439  //scroll
440  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(indexVal));
441 
442  //update display
443  panel.updateCurrentMatchDisplay(source.currentItem());
444  panel.updateTotaMatcheslDisplay(source.getNumberHits());
445 
446  //update controls if needed
447  if (!source.hasNextItem() && !source.hasNextPage()) {
448  panel.enableNextMatchControl(false);
449  }
450  if (source.hasPreviousItem() || source.hasPreviousPage()) {
451  panel.enablePrevMatchControl(true);
452  }
453  }
454  }
455  }
456 
457  private class PrevFindActionListener implements ActionListener {
458 
459  @Override
460  public void actionPerformed(ActionEvent e) {
461  IndexedText source = panel.getSelectedSource();
462  final boolean hasPreviousItem = source.hasPreviousItem();
463  final boolean hasPreviousPage = source.hasPreviousPage();
464  int indexVal;
465  if (hasPreviousItem || hasPreviousPage) {
466  if (!hasPreviousItem) {
467  //flip the page
468  previousPage();
469  indexVal = source.currentItem();
470  } else {
471  indexVal = source.previousItem();
472  }
473 
474  //scroll
475  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(indexVal));
476 
477  //update display
478  panel.updateCurrentMatchDisplay(source.currentItem());
479  panel.updateTotaMatcheslDisplay(source.getNumberHits());
480 
481  //update controls if needed
482  if (!source.hasPreviousItem() && !source.hasPreviousPage()) {
483  panel.enablePrevMatchControl(false);
484  }
485  if (source.hasNextItem() || source.hasNextPage()) {
486  panel.enableNextMatchControl(true);
487  }
488  }
489  }
490  }
491 
492  private class SourceChangeActionListener implements ActionListener {
493 
494  @Override
495  public void actionPerformed(ActionEvent e) {
496  currentSource = panel.getSelectedSource();
497 
498  if (currentSource == null) {
499  //TODO might need to reset something
500  return;
501  }
502 
503  panel.updateControls(currentSource);
504  panel.updateSearchControls(currentSource);
505  }
506  }
507 
508  private void nextPage() {
509  // we should never have gotten here -- reset
510  if (currentSource == null) {
511  panel.updateControls(null);
512  return;
513  }
514 
515  if (currentSource.hasNextPage()) {
516  currentSource.nextPage();
517 
518  //set new text
519  panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
520  panel.refreshCurrentMarkup();
521  panel.setCursor(null);
522 
523  //update display
524  panel.updateCurrentPageDisplay(currentSource.getCurrentPage());
525 
526  //scroll to current selection
528 
529  //update controls if needed
530  if (!currentSource.hasNextPage()) {
531  panel.enableNextPageControl(false);
532  }
533  if (currentSource.hasPreviousPage()) {
534  panel.enablePrevPageControl(true);
535  }
536 
537  panel.updateSearchControls(currentSource);
538  }
539  }
540 
541  private void previousPage() {
542  // reset, we should have never gotten here if null
543  if (currentSource == null) {
544  panel.updateControls(null);
545  return;
546  }
547 
548  if (currentSource.hasPreviousPage()) {
549  currentSource.previousPage();
550 
551  //set new text
552  panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
553  panel.refreshCurrentMarkup();
554  panel.setCursor(null);
555 
556  //update display
557  panel.updateCurrentPageDisplay(currentSource.getCurrentPage());
558 
559  //scroll to current selection
561 
562  //update controls if needed
563  if (!currentSource.hasPreviousPage()) {
564  panel.enablePrevPageControl(false);
565  }
566  if (currentSource.hasNextPage()) {
567  panel.enableNextPageControl(true);
568  }
569 
570  panel.updateSearchControls(currentSource);
571 
572  }
573  }
574 
575  private class NextPageActionListener implements ActionListener {
576 
577  @Override
578  public void actionPerformed(ActionEvent e) {
579  nextPage();
580  }
581  }
582 
583  private class PrevPageActionListener implements ActionListener {
584 
585  @Override
586  public void actionPerformed(ActionEvent e) {
587  previousPage();
588  }
589  }
590 }
static IndexedText getAccountsText(Content content, Lookup nodeLookup)
static IndexedText getRawArtifactText(BlackboardArtifact artifact)
void setPanel(String contentName, List< IndexedText > sources)
boolean queryIsIndexed(long contentID)
Definition: Server.java:947
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

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