Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.discovery.search;
20
21import com.google.common.cache.CacheLoader;
22import java.awt.Image;
23import java.util.List;
24import java.util.ArrayList;
25import java.util.Arrays;
26import java.util.Collections;
27import org.sleuthkit.autopsy.coreutils.ImageUtils;
28import org.sleuthkit.datamodel.BlackboardArtifact;
29import org.sleuthkit.datamodel.AbstractFile;
30import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE;
31import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
32import org.sleuthkit.datamodel.BlackboardAttribute;
33import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
34import org.sleuthkit.datamodel.Content;
35import org.sleuthkit.datamodel.DataSource;
36import org.sleuthkit.datamodel.SleuthkitCase;
37import org.sleuthkit.datamodel.TskCoreException;
38
39import org.openide.util.ImageUtilities;
40
49public 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
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}
static BufferedImage getThumbnail(Content content, int iconSize)
List< AbstractFile > getCandidatesFromWebDownloads(SleuthkitCase caseDb, List< BlackboardArtifact > artifacts)
void addIfSupported(List< AbstractFile > files, Content sourceContent)
List< AbstractFile > getCandidatesFromWebCache(SleuthkitCase caseDb, List< BlackboardArtifact > artifacts)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.