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

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