Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
EXIFProcessor.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-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.modules.pictureanalyzer.impls;
20 
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.Set;
35 import java.util.HashSet;
36 import java.util.TimeZone;
37 import java.util.logging.Level;
38 import org.apache.commons.lang3.StringUtils;
39 import org.openide.util.NbBundle;
40 import org.openide.util.lookup.ServiceProvider;
44 import org.sleuthkit.datamodel.AbstractFile;
48 import org.sleuthkit.datamodel.Blackboard;
49 import org.sleuthkit.datamodel.BlackboardArtifact;
50 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF;
51 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED;
52 import org.sleuthkit.datamodel.BlackboardAttribute;
53 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
54 import org.sleuthkit.datamodel.Content;
55 import org.sleuthkit.datamodel.Image;
56 import org.sleuthkit.datamodel.ReadContentInputStream;
57 import org.sleuthkit.datamodel.TskCoreException;
59 
66 @ServiceProvider(service = PictureProcessor.class)
67 public class EXIFProcessor implements PictureProcessor {
68 
69  private static final Logger logger = Logger.getLogger(EXIFProcessor.class.getName());
70 
71  @Override
72  @NbBundle.Messages({
73  "ExifProcessor.indexError.message=Failed to post EXIF Metadata artifact(s).",
74  "ExifProcessor.userContent.description=EXIF metadata data exists for this file."
75  })
76  public void process(IngestJobContext context, AbstractFile file) {
77  final String MODULE_NAME = PictureAnalyzerIngestModuleFactory.getModuleName();
78 
79  try (BufferedInputStream bin = new BufferedInputStream(new ReadContentInputStream(file));) {
80 
81  final Collection<BlackboardAttribute> attributes = new ArrayList<>();
82  final Metadata metadata = ImageMetadataReader.readMetadata(bin);
83 
84  // Date
85  final ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
86  if (exifDir != null) {
87 
88  // set the timeZone for the current datasource.
89  TimeZone timeZone = null;
90  try {
91  Content dataSource = file.getDataSource();
92  if ((dataSource != null) && (dataSource instanceof Image)) {
93  Image image = (Image) dataSource;
94  timeZone = TimeZone.getTimeZone(image.getTimeZone());
95  }
96  } catch (TskCoreException ex) {
97  logger.log(Level.INFO, "Error getting time zones", ex); //NON-NLS
98  }
99 
100  final Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
101  if (date != null) {
102  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, MODULE_NAME, date.getTime() / 1000));
103  }
104  }
105 
106  if (context.fileIngestIsCancelled()) {
107  return;
108  }
109 
110  // GPS Stuff
111  final GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
112  if (gpsDir != null) {
113  final GeoLocation loc = gpsDir.getGeoLocation();
114  if (loc != null) {
115  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, MODULE_NAME, loc.getLatitude()));
116  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, MODULE_NAME, loc.getLongitude()));
117  }
118 
119  final Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
120  if (altitude != null) {
121  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE, MODULE_NAME, altitude.doubleValue()));
122  }
123  }
124 
125  if (context.fileIngestIsCancelled()) {
126  return;
127  }
128 
129  // Device info
130  final ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
131  if (devDir != null) {
132  final String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
133  if (StringUtils.isNotBlank(model)) {
134  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, MODULE_NAME, model));
135  }
136 
137  final String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
138  if (StringUtils.isNotBlank(make)) {
139  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, MODULE_NAME, make));
140  }
141  }
142 
143  if (context.fileIngestIsCancelled()) {
144  return;
145  }
146 
147  final Blackboard blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
148 
149  if (!attributes.isEmpty() && !blackboard.artifactExists(file, TSK_METADATA_EXIF, attributes)) {
150 
151  final BlackboardArtifact exifArtifact = file.newArtifact(TSK_METADATA_EXIF);
152  final BlackboardArtifact userSuspectedArtifact = file.newArtifact(TSK_USER_CONTENT_SUSPECTED);
153  exifArtifact.addAttributes(attributes);
154  userSuspectedArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
155  MODULE_NAME, Bundle.ExifProcessor_userContent_description()));
156  try {
157  // index the artifact for keyword search
158  blackboard.postArtifact(exifArtifact, MODULE_NAME);
159  blackboard.postArtifact(userSuspectedArtifact, MODULE_NAME);
160  } catch (Blackboard.BlackboardException ex) {
161  logger.log(Level.SEVERE, "Unable to index blackboard artifact " + exifArtifact.getArtifactID(), ex); //NON-NLS
163  Bundle.ExifProcessor_indexError_message(), exifArtifact.getDisplayName());
164  }
165  }
166  } catch (TskCoreException ex) {
167  logger.log(Level.WARNING, "Failed to create blackboard artifact for " //NON-NLS
168  + "exif metadata ({0}).", ex.getLocalizedMessage()); //NON-NLS
169  } catch (IOException | ImageProcessingException unused) {
170  // In this case the stack trace is not needed in the log.
171  logger.log(Level.WARNING, String.format("Error parsing " //NON-NLS
172  + "image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId())); //NON-NLS
173  } catch (NoCurrentCaseException ex) {
174  logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS
175  }
176  }
177 
178  @Override
179  public Set<String> mimeTypes() {
180  return new HashSet<String>() {
181  {
182  add("audio/x-wav");
183  add("image/jpeg");
184  add("image/tiff");
185  }
186  };
187  }
188 }
void process(IngestJobContext context, AbstractFile file)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

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