Autopsy  4.4.1
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-2017 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;
36 import org.sleuthkit.datamodel.AbstractFile;
37 import org.sleuthkit.datamodel.BlackboardArtifact;
38 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
39 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
40 import org.sleuthkit.datamodel.BlackboardAttribute;
41 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
42 import org.sleuthkit.datamodel.Content;
43 import org.sleuthkit.datamodel.TskCoreException;
44 
49 @ServiceProvider(service = DataContentViewer.class, position = 4)
50 public class ExtractedContentViewer implements DataContentViewer {
51 
52  private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName());
53 
54  private static final long INVALID_DOCUMENT_ID = 0L;
55  private static final BlackboardAttribute.Type TSK_ASSOCIATED_ARTIFACT_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
56 
57  private ExtractedContentPanel panel;
58  private volatile Node currentNode = null;
59  private IndexedText currentSource = null;
60 
67  }
68 
74  @Override
75  public void setNode(final Node node) {
76  // Clear the viewer.
77  if (node == null) {
78  currentNode = null;
79  resetComponent();
80  return;
81  }
82 
83  /*
84  * This deals with the known bug with an unknown cause where setNode is
85  * sometimes called twice for the same node.
86  */
87  if (node == currentNode) {
88  return;
89  } else {
90  currentNode = node;
91  }
92 
93  Lookup nodeLookup = node.getLookup();
94  AbstractFile content = nodeLookup.lookup(AbstractFile.class);
95 
96  /*
97  * Assemble a collection of all of the indexed text "sources" for the
98  * node.
99  */
100  List<IndexedText> sources = new ArrayList<>();
101  IndexedText highlightedHitText = null;
102  IndexedText rawContentText = null;
103 
104  if (null != content && solrHasContent(content.getId())) {
105  QueryResults hits = nodeLookup.lookup(QueryResults.class);
106  BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class);
107  if (hits != null) {
108  /*
109  * if there is a QueryReslt object, in the lookup use that. This
110  * happens when a user selects a row in an ad-hoc search result
111  */
112  highlightedHitText = new HighlightedText(content.getId(), hits);
113  } else if (artifact != null
114  && artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) {
115  try {
116  // if the artifact is an account artifact, get an account text .
117  highlightedHitText = getAccountsText(content, nodeLookup);
118  } catch (TskCoreException ex) {
119  logger.log(Level.SEVERE, "Failed to create AccountsText for " + content, ex); //NON-NLS
120 
121  }
122  } else if (artifact != null
123  && artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
124  try {
125  //if there is kwh artifact use that to construct the HighlightedText
126  highlightedHitText = new HighlightedText(artifact);
127  } catch (TskCoreException ex) {
128  logger.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS
129  }
130  }
131 
132  if (highlightedHitText != null) {
133  sources.add(highlightedHitText);
134  }
135 
136  /*
137  * Next, add the "raw" (not highlighted) text, if any, for any
138  * content associated with the node.
139  */
140  rawContentText = new RawText(content, content.getId());
141  sources.add(rawContentText);
142  }
143 
144  /*
145  * Finally, add the "raw" (not highlighted) text, if any, for any
146  * artifact associated with the node.
147  */
148  IndexedText rawArtifactText = null;
149  try {
150  rawArtifactText = getRawArtifactText(nodeLookup);
151  } catch (TskCoreException ex) {
152  logger.log(Level.SEVERE, "Error creating RawText for " + content, ex); //NON-NLS
153 
154  }
155  if (rawArtifactText != null) {
156  sources.add(rawArtifactText);
157  }
158 
159  // Now set the default source to be displayed.
160  if (null != highlightedHitText) {
161  currentSource = highlightedHitText;
162  } else if (null != rawContentText) {
163  currentSource = rawContentText;
164  } else {
165  currentSource = rawArtifactText;
166  }
167 
168  // Push the text sources into the panel.
169  for (IndexedText source : sources) {
170  int currentPage = source.getCurrentPage();
171  if (currentPage == 0 && source.hasNextPage()) {
172  source.nextPage();
173  }
174  }
175  panel.updateControls(currentSource);
176  setPanel(content.getName(), sources);
177  }
178 
179  static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException {
180  IndexedText rawArtifactText = null;
181  BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class);
182  if (null != artifact) {
183  /*
184  * For keyword hit artifacts, add the text of the artifact that hit,
185  * not the hit artifact; otherwise add the text for the artifact.
186  */
187  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()
188  || artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) {
189 
190  BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE);
191  if (attribute != null) {
192  long artifactId = attribute.getValueLong();
193  BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactId);
194  rawArtifactText = new RawText(associatedArtifact, associatedArtifact.getArtifactID());
195 
196  }
197 
198  } else {
199  rawArtifactText = new RawText(artifact, artifact.getArtifactID());
200  }
201  }
202  return rawArtifactText;
203  }
204 
205  static private IndexedText getAccountsText(Content content, Lookup nodeLookup) throws TskCoreException {
206  /*
207  * get all the credit card artifacts
208  */
209  //if the node had artifacts in the lookup use them, other wise look up all credit card artifacts for the content.
210  Collection<? extends BlackboardArtifact> artifacts = nodeLookup.lookupAll(BlackboardArtifact.class);
211  artifacts = (artifacts == null || artifacts.isEmpty())
212  ? content.getArtifacts(TSK_ACCOUNT)
213  : artifacts;
214 
215  return new AccountsText(content.getId(), artifacts);
216  }
217 
218  private void scrollToCurrentHit() {
219  final IndexedText source = panel.getSelectedSource();
220  if (source == null || !source.isSearchable()) {
221  return;
222  }
223 
224  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(source.currentItem()));
225  }
226 
227  @Override
228  public String getTitle() {
229  return NbBundle.getMessage(this.getClass(), "ExtractedContentViewer.getTitle");
230  }
231 
232  @Override
233  public String getToolTip() {
234  return NbBundle.getMessage(this.getClass(), "ExtractedContentViewer.toolTip");
235  }
236 
237  @Override
238  public DataContentViewer createInstance() {
239  return new ExtractedContentViewer();
240  }
241 
242  @Override
243  public synchronized Component getComponent() {
244  if (panel == null) {
245  panel = new ExtractedContentPanel();
246  panel.addPrevMatchControlListener(new PrevFindActionListener());
247  panel.addNextMatchControlListener(new NextFindActionListener());
248  panel.addPrevPageControlListener(new PrevPageActionListener());
249  panel.addNextPageControlListener(new NextPageActionListener());
250  panel.addSourceComboControlListener(new SourceChangeActionListener());
251  }
252  return panel;
253  }
254 
255  @Override
256  public void resetComponent() {
257 
258  panel.resetDisplay();
259  currentNode = null;
260  currentSource = null;
261  }
262 
263  @Override
264  public boolean isSupported(Node node) {
265  if (node == null) {
266  return false;
267  }
268 
269  /*
270  * Is there a credit card artifact in the lookup
271  */
272  Collection<? extends BlackboardArtifact> artifacts = node.getLookup().lookupAll(BlackboardArtifact.class);
273  if (artifacts != null) {
274  for (BlackboardArtifact art : artifacts) {
275  final int artifactTypeID = art.getArtifactTypeID();
276  if (artifactTypeID == TSK_ACCOUNT.getTypeID()
277  || artifactTypeID == TSK_KEYWORD_HIT.getTypeID()) {
278  return true;
279  }
280  }
281  }
282 
283  /*
284  * No highlighted text for a keyword hit, so is there any indexed text
285  * at all for this node?
286  */
287  long documentID = getDocumentId(node);
288  if (INVALID_DOCUMENT_ID == documentID) {
289  return false;
290  }
291 
292  return solrHasContent(documentID);
293  }
294 
295  @Override
296  public int isPreferred(Node node) {
297  BlackboardArtifact art = node.getLookup().lookup(BlackboardArtifact.class);
298 
299  if (art == null) {
300  return 4;
301  } else if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
302  || art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
303  return 6;
304  } else {
305  return 4;
306  }
307  }
308 
317  private void setPanel(String contentName, List<IndexedText> sources) {
318  if (panel != null) {
319  panel.setSources(contentName, sources);
320  }
321  }
322 
330  private boolean solrHasContent(Long objectId) {
331  final Server solrServer = KeywordSearch.getServer();
332  if (solrServer.coreIsOpen() == false) {
333  return false;
334  }
335 
336  try {
337  return solrServer.queryIsIndexed(objectId);
339  logger.log(Level.SEVERE, "Error querying Solr server", ex); //NON-NLS
340  return false;
341  }
342  }
343 
352  private Long getDocumentId(Node node) {
361  BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
362  if (null != artifact) {
363  if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
364  return artifact.getArtifactID();
365  } else {
366  try {
367  // Get the associated artifact attribute and return its value as the ID
368  BlackboardAttribute blackboardAttribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE);
369  if (blackboardAttribute != null) {
370  return blackboardAttribute.getValueLong();
371  }
372  } catch (TskCoreException ex) {
373  logger.log(Level.SEVERE, "Error getting associated artifact attributes", ex); //NON-NLS
374  }
375  }
376  }
377 
378  /*
379  * For keyword search hit artifact nodes and all other nodes, the
380  * document ID for the extracted text is the ID of the associated
381  * content, if any, unless there is an associated artifact, which is
382  * handled above.
383  */
384  Content content = node.getLookup().lookup(Content.class);
385  if (content != null) {
386  return content.getId();
387  }
388 
389  /*
390  * No extracted text, return an invalid docuemnt ID.
391  */
392  return 0L;
393  }
394 
395  private class NextFindActionListener implements ActionListener {
396 
397  @Override
398  public void actionPerformed(ActionEvent e) {
399  IndexedText source = panel.getSelectedSource();
400  if (source == null) {
401  // reset
402  panel.updateControls(null);
403  return;
404  }
405  final boolean hasNextItem = source.hasNextItem();
406  final boolean hasNextPage = source.hasNextPage();
407  int indexVal;
408  if (hasNextItem || hasNextPage) {
409  if (!hasNextItem) {
410  //flip the page
411  nextPage();
412  indexVal = source.currentItem();
413  } else {
414  indexVal = source.nextItem();
415  }
416 
417  //scroll
418  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(indexVal));
419 
420  //update display
421  panel.updateCurrentMatchDisplay(source.currentItem());
422  panel.updateTotaMatcheslDisplay(source.getNumberHits());
423 
424  //update controls if needed
425  if (!source.hasNextItem() && !source.hasNextPage()) {
426  panel.enableNextMatchControl(false);
427  }
428  if (source.hasPreviousItem() || source.hasPreviousPage()) {
429  panel.enablePrevMatchControl(true);
430  }
431  }
432  }
433  }
434 
435  private class PrevFindActionListener implements ActionListener {
436 
437  @Override
438  public void actionPerformed(ActionEvent e) {
439  IndexedText source = panel.getSelectedSource();
440  final boolean hasPreviousItem = source.hasPreviousItem();
441  final boolean hasPreviousPage = source.hasPreviousPage();
442  int indexVal;
443  if (hasPreviousItem || hasPreviousPage) {
444  if (!hasPreviousItem) {
445  //flip the page
446  previousPage();
447  indexVal = source.currentItem();
448  } else {
449  indexVal = source.previousItem();
450  }
451 
452  //scroll
453  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(indexVal));
454 
455  //update display
456  panel.updateCurrentMatchDisplay(source.currentItem());
457  panel.updateTotaMatcheslDisplay(source.getNumberHits());
458 
459  //update controls if needed
460  if (!source.hasPreviousItem() && !source.hasPreviousPage()) {
461  panel.enablePrevMatchControl(false);
462  }
463  if (source.hasNextItem() || source.hasNextPage()) {
464  panel.enableNextMatchControl(true);
465  }
466  }
467  }
468  }
469 
470  private class SourceChangeActionListener implements ActionListener {
471 
472  @Override
473  public void actionPerformed(ActionEvent e) {
474  currentSource = panel.getSelectedSource();
475 
476  if (currentSource == null) {
477  //TODO might need to reset something
478  return;
479  }
480 
481  panel.updateControls(currentSource);
482  panel.updateSearchControls(currentSource);
483  }
484  }
485 
486  private void nextPage() {
487  // we should never have gotten here -- reset
488  if (currentSource == null) {
489  panel.updateControls(null);
490  return;
491  }
492 
493  if (currentSource.hasNextPage()) {
494  currentSource.nextPage();
495 
496  //set new text
497  panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
498  panel.refreshCurrentMarkup();
499  panel.setCursor(null);
500 
501  //update display
502  panel.updateCurrentPageDisplay(currentSource.getCurrentPage());
503 
504  //scroll to current selection
506 
507  //update controls if needed
508  if (!currentSource.hasNextPage()) {
509  panel.enableNextPageControl(false);
510  }
511  if (currentSource.hasPreviousPage()) {
512  panel.enablePrevPageControl(true);
513  }
514 
515  panel.updateSearchControls(currentSource);
516  }
517  }
518 
519  private void previousPage() {
520  // reset, we should have never gotten here if null
521  if (currentSource == null) {
522  panel.updateControls(null);
523  return;
524  }
525 
526  if (currentSource.hasPreviousPage()) {
527  currentSource.previousPage();
528 
529  //set new text
530  panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
531  panel.refreshCurrentMarkup();
532  panel.setCursor(null);
533 
534  //update display
535  panel.updateCurrentPageDisplay(currentSource.getCurrentPage());
536 
537  //scroll to current selection
539 
540  //update controls if needed
541  if (!currentSource.hasPreviousPage()) {
542  panel.enablePrevPageControl(false);
543  }
544  if (currentSource.hasNextPage()) {
545  panel.enableNextPageControl(true);
546  }
547 
548  panel.updateSearchControls(currentSource);
549 
550  }
551  }
552 
553  private class NextPageActionListener implements ActionListener {
554 
555  @Override
556  public void actionPerformed(ActionEvent e) {
557  nextPage();
558  }
559  }
560 
561  private class PrevPageActionListener implements ActionListener {
562 
563  @Override
564  public void actionPerformed(ActionEvent e) {
565  previousPage();
566  }
567  }
568 }
static IndexedText getAccountsText(Content content, Lookup nodeLookup)
void setPanel(String contentName, List< IndexedText > sources)
boolean queryIsIndexed(long contentID)
Definition: Server.java:947
synchronized static Logger getLogger(String name)
Definition: Logger.java:161

Copyright © 2012-2016 Basis Technology. Generated on: Fri Sep 29 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.