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

Copyright © 2012-2020 Basis Technology. Generated on: Wed Apr 8 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.