19 package org.sleuthkit.autopsy.modules.exif;
21 import com.drew.imaging.ImageMetadataReader;
22 import com.drew.imaging.ImageProcessingException;
23 import com.drew.lang.GeoLocation;
24 import com.drew.lang.Rational;
25 import com.drew.metadata.Metadata;
26 import com.drew.metadata.exif.ExifIFD0Directory;
27 import com.drew.metadata.exif.ExifSubIFDDirectory;
28 import com.drew.metadata.exif.GpsDirectory;
29 import java.io.BufferedInputStream;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Date;
34 import java.util.HashSet;
35 import java.util.TimeZone;
36 import java.util.logging.Level;
37 import org.apache.commons.lang3.StringUtils;
38 import org.openide.util.NbBundle;
39 import org.openide.util.NbBundle.Messages;
51 import static org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF;
53 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED;
54 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE;
55 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL;
56 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE;
57 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE;
58 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE;
62 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
65 import org.
sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
72 @NbBundle.Messages({
"CannotRunFileTypeDetection=Cannot run file type detection."})
80 private final HashSet<String> supportedMimeTypes =
new HashSet<>();
81 private TimeZone timeZone = null;
85 supportedMimeTypes.add(
"audio/x-wav");
86 supportedMimeTypes.add(
"image/jpeg");
87 supportedMimeTypes.add(
"image/tiff");
92 jobId = context.getJobId();
101 @Messages({
"ExifParserFileIngestModule.indexError.message=Failed to post EXIF Metadata artifact(s)."})
107 logger.log(Level.INFO,
"Exception while getting open case.", ex);
111 if ((content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
112 || (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.SLACK)))) {
116 if (content.isFile() ==
false) {
121 if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
126 if (!parsableFormat(content)) {
130 return processFile(content);
135 try (BufferedInputStream bin =
new BufferedInputStream(
new ReadContentInputStream(file));) {
137 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
138 Metadata metadata = ImageMetadataReader.readMetadata(bin);
141 ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
142 if (exifDir != null) {
145 if (timeZone == null) {
147 Content dataSource = file.getDataSource();
148 if ((dataSource != null) && (dataSource instanceof Image)) {
149 Image image = (Image) dataSource;
150 timeZone = TimeZone.getTimeZone(image.getTimeZone());
152 }
catch (TskCoreException ex) {
153 logger.log(Level.INFO,
"Error getting time zones", ex);
156 Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
158 attributes.add(
new BlackboardAttribute(TSK_DATETIME_CREATED, MODULE_NAME, date.getTime() / 1000));
163 GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
164 if (gpsDir != null) {
165 GeoLocation loc = gpsDir.getGeoLocation();
167 attributes.add(
new BlackboardAttribute(TSK_GEO_LATITUDE, MODULE_NAME, loc.getLatitude()));
168 attributes.add(
new BlackboardAttribute(TSK_GEO_LONGITUDE, MODULE_NAME, loc.getLongitude()));
171 Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
172 if (altitude != null) {
173 attributes.add(
new BlackboardAttribute(TSK_GEO_ALTITUDE, MODULE_NAME, altitude.doubleValue()));
178 ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
179 if (devDir != null) {
180 String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
181 if (StringUtils.isNotBlank(model)) {
182 attributes.add(
new BlackboardAttribute(TSK_DEVICE_MODEL, MODULE_NAME, model));
185 String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
186 if (StringUtils.isNotBlank(make)) {
187 attributes.add(
new BlackboardAttribute(TSK_DEVICE_MAKE, MODULE_NAME, make));
192 if (!attributes.isEmpty()) {
194 if (!blackboard.artifactExists(file, TSK_METADATA_EXIF, attributes)) {
195 BlackboardArtifact bba = file.newArtifact(TSK_METADATA_EXIF);
196 bba.addAttributes(attributes);
200 blackboard.postArtifact(bba, MODULE_NAME);
201 }
catch (Blackboard.BlackboardException ex) {
202 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + bba.getArtifactID(), ex);
204 Bundle.ExifParserFileIngestModule_indexError_message(), bba.getDisplayName());
210 }
catch (TskCoreException ex) {
211 logger.log(Level.WARNING,
"Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage());
213 }
catch (ImageProcessingException ex) {
214 logger.log(Level.WARNING, String.format(
"Failed to process the image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex);
216 }
catch (ReadContentInputStreamException ex) {
217 logger.log(Level.WARNING, String.format(
"Error while trying to read image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex);
219 }
catch (IOException ex) {
220 logger.log(Level.WARNING, String.format(
"IOException when parsing image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex);
235 return supportedMimeTypes.contains(mimeType);
synchronized long decrementAndGet(long jobId)
void startUp(IngestJobContext context)
ProcessResult process(AbstractFile content)
synchronized long incrementAndGet(long jobId)
String getMIMEType(AbstractFile file)
SleuthkitCase getSleuthkitCase()
ProcessResult processFile(AbstractFile file)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
FileTypeDetector fileTypeDetector
boolean parsableFormat(AbstractFile f)