Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DomainSearchThumbnailLoader.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 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 
21 import com.google.common.cache.CacheLoader;
22 import java.awt.Image;
23 import java.util.List;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
28 import org.sleuthkit.datamodel.BlackboardArtifact;
29 import org.sleuthkit.datamodel.AbstractFile;
30 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE;
31 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
32 import org.sleuthkit.datamodel.BlackboardAttribute;
33 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
34 import org.sleuthkit.datamodel.Content;
35 import org.sleuthkit.datamodel.DataSource;
36 import org.sleuthkit.datamodel.SleuthkitCase;
37 import org.sleuthkit.datamodel.TskCoreException;
38 
39 import org.openide.util.ImageUtilities;
40 
49 public class DomainSearchThumbnailLoader extends CacheLoader<DomainSearchThumbnailRequest, Image> {
50 
51  private static final String UNSUPPORTED_IMAGE = "org/sleuthkit/autopsy/images/image-extraction-not-supported.png";
52  private static final List<String> SUPPORTED_EXTENSIONS = Arrays.asList("jpg", "svg", "png", "webp", "ico", "gif");
53  private static final List<String> SUPPORTED_MIMETYPES = Arrays.asList(
54  "image/gif", "image/jpeg", "image/png", "image/webp",
55  "image/svg+xml", "image/vnd.microsoft.icon", "image/x-icon");
56  private static final String ICO_EXTENSION = "ico";
57  private static final List<String> ICO_MIMETYPES = Arrays.asList("image/vnd.microsoft.icon", "image/x-icon");
59 
64  this(new DomainSearchArtifactsCache());
65  }
66 
75  this.artifactsCache = artifactsCache;
76  }
77 
78  @Override
79  public Image load(DomainSearchThumbnailRequest thumbnailRequest) throws TskCoreException, DiscoveryException, InterruptedException {
80  final SleuthkitCase caseDb = thumbnailRequest.getSleuthkitCase();
81  final DomainSearchArtifactsRequest webDownloadsRequest = new DomainSearchArtifactsRequest(
82  caseDb, thumbnailRequest.getDomain(), TSK_WEB_DOWNLOAD);
83  final List<BlackboardArtifact> webDownloads = artifactsCache.get(webDownloadsRequest);
84  final List<AbstractFile> webDownloadPictures = getCandidatesFromWebDownloads(caseDb, webDownloads);
85  Collections.sort(webDownloadPictures, (file1, file2) -> {
86  // Push ICO to the back of the sorted collection, so that ICO
87  // is a last resort matching type.
88  if (isIco(file1) && isIco(file2)) {
89  return Long.compare(file1.getSize(), file2.getSize());
90  } else if (isIco(file1)) {
91  return 1;
92  } else if (isIco(file2)) {
93  return -1;
94  } else {
95  return Long.compare(file1.getCrtime(), file2.getCrtime());
96  }
97  });
98 
99  for (int i = webDownloadPictures.size() - 1; i >= 0; i--) {
100  if(Thread.currentThread().isInterrupted()) {
101  throw new InterruptedException();
102  }
103  // Get the most recent image, according to creation time.
104  final AbstractFile mostRecent = webDownloadPictures.get(i);
105 
106  final Image candidateThumbnail = ImageUtils.getThumbnail(mostRecent, thumbnailRequest.getIconSize());
107  if (candidateThumbnail != ImageUtils.getDefaultThumbnail()) {
108  return candidateThumbnail;
109  }
110  }
112  caseDb, thumbnailRequest.getDomain(), TSK_WEB_CACHE);
113  final List<BlackboardArtifact> webCacheArtifacts = artifactsCache.get(webCacheRequest);
114  final List<AbstractFile> webCachePictures = getCandidatesFromWebCache(caseDb, webCacheArtifacts);
115  Collections.sort(webCachePictures, (file1, file2) -> {
116  // Push ICO to the back of the sorted collection, so that ICO
117  // is a last resort matching type.
118  if (isIco(file1) && isIco(file2)) {
119  return Long.compare(file1.getSize(), file2.getSize());
120  } else if (isIco(file1)) {
121  return 1;
122  } else if (isIco(file2)) {
123  return -1;
124  } else {
125  return Long.compare(file1.getSize(), file2.getSize());
126  }
127  });
128  for (int i = webCachePictures.size() - 1; i >= 0; i--) {
129  if(Thread.currentThread().isInterrupted()) {
130  throw new InterruptedException();
131  }
132  // Get the largest image, according to file size.
133  final AbstractFile largest = webCachePictures.get(i);
134  final Image candidateThumbnail = ImageUtils.getThumbnail(largest, thumbnailRequest.getIconSize());
135  if (candidateThumbnail != ImageUtils.getDefaultThumbnail()) {
136  return candidateThumbnail;
137  }
138  }
139  return ImageUtilities.loadImage(UNSUPPORTED_IMAGE, false);
140  }
141 
153  private List<AbstractFile> getCandidatesFromWebDownloads(SleuthkitCase caseDb, List<BlackboardArtifact> artifacts) throws TskCoreException, InterruptedException {
154  final List<AbstractFile> candidates = new ArrayList<>();
155  for (BlackboardArtifact artifact : artifacts) {
156  if(Thread.currentThread().isInterrupted()) {
157  throw new InterruptedException();
158  }
159  final Content sourceContent = caseDb.getContentById(artifact.getObjectID());
160  addIfSupported(candidates, sourceContent);
161  }
162  return candidates;
163  }
164 
165  private boolean isIco(AbstractFile file) {
166  return ICO_EXTENSION.equals(file.getNameExtension())
167  || ICO_MIMETYPES.contains(file.getMIMEType());
168  }
169 
179  private List<AbstractFile> getCandidatesFromWebCache(SleuthkitCase caseDb, List<BlackboardArtifact> artifacts) throws TskCoreException, InterruptedException {
180  final BlackboardAttribute.Type TSK_PATH_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH_ID);
181  final List<AbstractFile> candidates = new ArrayList<>();
182  for (BlackboardArtifact artifact : artifacts) {
183  if(Thread.currentThread().isInterrupted()) {
184  throw new InterruptedException();
185  }
186  final BlackboardAttribute tskPathId = artifact.getAttribute(TSK_PATH_ID);
187  if (tskPathId != null) {
188  final Content sourceContent = caseDb.getContentById(tskPathId.getValueLong());
189  addIfSupported(candidates, sourceContent);
190  }
191  }
192  return candidates;
193  }
194 
201  private void addIfSupported(List<AbstractFile> files, Content sourceContent) {
202  if ((sourceContent instanceof AbstractFile) && !(sourceContent instanceof DataSource)) {
203  final AbstractFile file = (AbstractFile) sourceContent;
204  if (SUPPORTED_EXTENSIONS.contains(file.getNameExtension())
205  || SUPPORTED_MIMETYPES.contains(file.getMIMEType())) {
206  files.add(file);
207  }
208  }
209  }
210 }
void addIfSupported(List< AbstractFile > files, Content sourceContent)
List< BlackboardArtifact > get(DomainSearchArtifactsRequest request)
List< AbstractFile > getCandidatesFromWebDownloads(SleuthkitCase caseDb, List< BlackboardArtifact > artifacts)
List< AbstractFile > getCandidatesFromWebCache(SleuthkitCase caseDb, List< BlackboardArtifact > artifacts)
static BufferedImage getThumbnail(Content content, int iconSize)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.