Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ResultFile.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019-2020 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.discovery.search;
20 
22 import org.sleuthkit.datamodel.AbstractFile;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.logging.Level;
27 import org.openide.util.NbBundle;
33 import org.sleuthkit.datamodel.BlackboardArtifact;
34 import org.sleuthkit.datamodel.Content;
35 import org.sleuthkit.datamodel.ContentTag;
36 import org.sleuthkit.datamodel.HashUtility;
37 import org.sleuthkit.datamodel.Tag;
38 import org.sleuthkit.datamodel.TskCoreException;
39 import org.sleuthkit.datamodel.TskData;
40 
44 public class ResultFile extends Result {
45 
46  private final static Logger logger = Logger.getLogger(ResultFile.class.getName());
47  private final List<String> keywordListNames;
48  private final List<String> hashSetNames;
49  private final List<String> interestingSetNames;
50  private final List<String> objectDetectedNames;
51  private final List<AbstractFile> instances = new ArrayList<>();
53  private String scoreDescription = null;
54  private boolean deleted = false;
55  private Type fileType;
56 
62  public ResultFile(AbstractFile abstractFile) {
63  try {
64  //call get uniquePath to cache the path
65  abstractFile.getUniquePath();
66  } catch (TskCoreException ignored) {
67  //path wasnt cached will likely be called on EDT later JIRA-5972
68  }
69  //store the file the ResultFile was created for as the first value in the instances list
70  instances.add(abstractFile);
71  if (abstractFile.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
72  deleted = true;
73  }
74  updateScoreAndDescription(abstractFile);
75  keywordListNames = new ArrayList<>();
76  hashSetNames = new ArrayList<>();
77  interestingSetNames = new ArrayList<>();
78  objectDetectedNames = new ArrayList<>();
79  fileType = fromMIMEtype(abstractFile.getMIMEType());
80  }
81 
88  public void addDuplicate(AbstractFile duplicate) {
89  if (deleted && !duplicate.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
90  deleted = false;
91  }
92  if (fileType == Type.OTHER) {
93  fileType = fromMIMEtype(duplicate.getMIMEType());
94  }
95  updateScoreAndDescription(duplicate);
96  try {
97  //call get uniquePath to cache the path
98  duplicate.getUniquePath();
99  } catch (TskCoreException ignored) {
100  //path wasnt cached will likely be called on EDT later JIRA-5972
101  }
102  instances.add(duplicate);
103  }
104 
112  return currentScore;
113  }
114 
120  public String getScoreDescription() {
121  return scoreDescription;
122  }
123 
130  public boolean isDeleted() {
131  return deleted;
132  }
133 
141  public List<AbstractFile> getAllInstances() {
142  return Collections.unmodifiableList(instances);
143  }
144 
150  public Type getFileType() {
151  return fileType;
152  }
153 
159  public void addKeywordListName(String keywordListName) {
160  if (!keywordListNames.contains(keywordListName)) {
161  keywordListNames.add(keywordListName);
162  }
163 
164  // Sort the list so the getKeywordListNames() will be consistent regardless of the order added
165  Collections.sort(keywordListNames);
166  }
167 
173  public List<String> getKeywordListNames() {
174  return Collections.unmodifiableList(keywordListNames);
175  }
176 
182  public void addHashSetName(String hashSetName) {
183  if (!hashSetNames.contains(hashSetName)) {
184  hashSetNames.add(hashSetName);
185  }
186 
187  // Sort the list so the getHashHitNames() will be consistent regardless of the order added
188  Collections.sort(hashSetNames);
189  }
190 
196  public List<String> getHashSetNames() {
197  return Collections.unmodifiableList(hashSetNames);
198  }
199 
205  public void addInterestingSetName(String interestingSetName) {
206  if (!interestingSetNames.contains(interestingSetName)) {
207  interestingSetNames.add(interestingSetName);
208  }
209 
210  // Sort the list so the getInterestingSetNames() will be consistent regardless of the order added
211  Collections.sort(interestingSetNames);
212  }
213 
219  public List<String> getInterestingSetNames() {
220  return Collections.unmodifiableList(interestingSetNames);
221  }
222 
228  public void addObjectDetectedName(String objectDetectedName) {
229  if (!objectDetectedNames.contains(objectDetectedName)) {
230  objectDetectedNames.add(objectDetectedName);
231  }
232 
233  // Sort the list so the getObjectDetectedNames() will be consistent regardless of the order added
234  Collections.sort(objectDetectedNames);
235  }
236 
242  public List<String> getObjectDetectedNames() {
243  return Collections.unmodifiableList(objectDetectedNames);
244  }
245 
251  public AbstractFile getFirstInstance() {
252  return instances.get(0);
253  }
254 
255  @Override
256  public String toString() {
257  return getFirstInstance().getName() + "(" + getFirstInstance().getId() + ") - "
258  + getFirstInstance().getSize() + ", " + getFirstInstance().getParentPath() + ", "
259  + getFirstInstance().getDataSourceObjectId() + ", " + getFrequency().toString() + ", "
260  + String.join(",", keywordListNames) + ", " + getFirstInstance().getMIMEType();
261  }
262 
263  @Override
264  public int hashCode() {
265  if (this.getFirstInstance().getMd5Hash() == null
266  || HashUtility.isNoDataMd5(this.getFirstInstance().getMd5Hash())
267  || !HashUtility.isValidMd5Hash(this.getFirstInstance().getMd5Hash())) {
268  return super.hashCode();
269  } else {
270  //if the file has a valid MD5 use the hashcode of the MD5 for deduping files with the same MD5
271  return this.getFirstInstance().getMd5Hash().hashCode();
272  }
273 
274  }
275 
276  @Override
277  public boolean equals(Object obj) {
278  if (!(obj instanceof ResultFile)
279  || this.getFirstInstance().getMd5Hash() == null
280  || HashUtility.isNoDataMd5(this.getFirstInstance().getMd5Hash())
281  || !HashUtility.isValidMd5Hash(this.getFirstInstance().getMd5Hash())) {
282  return super.equals(obj);
283  } else {
284  //if the file has a valid MD5 compare use the MD5 for equality check
285  return this.getFirstInstance().getMd5Hash().equals(((ResultFile) obj).getFirstInstance().getMd5Hash());
286  }
287  }
288 
294  private List<ContentTag> getContentTagsFromDatabase(AbstractFile file) {
295  List<ContentTag> tags = new ArrayList<>();
296  try {
298  } catch (TskCoreException | NoCurrentCaseException ex) {
299  logger.log(Level.SEVERE, "Failed to get tags for file " + file.getName(), ex);
300  }
301  return tags;
302  }
303 
304  @NbBundle.Messages({
305  "ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable.",
306  "ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it.",
307  "ResultFile.score.taggedFile.description=At least one instance of the file has been tagged.",
308  "ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag."})
309  private void updateScoreAndDescription(AbstractFile file) {
311  //already notable can return
312  return;
313  }
314  if (file.getKnown() == TskData.FileKnown.BAD) {
316  scoreDescription = Bundle.ResultFile_score_notableFile_description();
317  return;
318  }
319  try {
320  if (currentScore == DataResultViewerTable.Score.NO_SCORE && !file.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT).isEmpty()) {
322  scoreDescription = Bundle.ResultFile_score_interestingResult_description();
323  }
324  } catch (TskCoreException ex) {
325  logger.log(Level.WARNING, "Error getting artifacts for file: " + file.getName(), ex);
326  }
327  List<ContentTag> tags = getContentTagsFromDatabase(file);
328  if (!tags.isEmpty()) {
330  scoreDescription = Bundle.ResultFile_score_taggedFile_description();
331  for (Tag tag : tags) {
332  if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
334  scoreDescription = Bundle.ResultFile_score_notableTaggedFile_description();
335  return;
336  }
337  }
338  }
339  }
340 
348  public static Type fromMIMEtype(String mimeType) {
349  for (Type type : Type.values()) {
350  if (type.getMediaTypes().contains(mimeType)) {
351  return type;
352  }
353  }
354  return OTHER;
355  }
356 
357  @Override
358  public long getDataSourceObjectId() {
359  return getFirstInstance().getDataSourceObjectId();
360  }
361 
362  @Override
363  public Content getDataSource() throws TskCoreException {
364  return getFirstInstance().getDataSource();
365  }
366 
367  @Override
368  public TskData.FileKnown getKnown() {
369  return getFirstInstance().getKnown();
370  }
371 
372  @Override
373  public Type getType() {
374  return fileType;
375  }
376 }
List< ContentTag > getContentTagsByContent(Content content)
List< ContentTag > getContentTagsFromDatabase(AbstractFile file)
void addKeywordListName(String keywordListName)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void addInterestingSetName(String interestingSetName)
void addObjectDetectedName(String objectDetectedName)

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