Autopsy  4.8.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExifParserFileIngestModule.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2018 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.exif;
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.io.InputStream;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.Date;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.TimeZone;
38 import java.util.concurrent.atomic.AtomicInteger;
39 import java.util.logging.Level;
40 import org.openide.util.NbBundle;
41 import org.openide.util.NbBundle.Messages;
53 import org.sleuthkit.datamodel.AbstractFile;
54 import org.sleuthkit.datamodel.BlackboardArtifact;
55 import org.sleuthkit.datamodel.BlackboardAttribute;
56 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
57 import org.sleuthkit.datamodel.Content;
58 import org.sleuthkit.datamodel.Image;
59 import org.sleuthkit.datamodel.ReadContentInputStream;
60 import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
61 import org.sleuthkit.datamodel.TskCoreException;
62 import org.sleuthkit.datamodel.TskData;
63 import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
64 
70 @NbBundle.Messages({
71  "CannotRunFileTypeDetection=Cannot run file type detection."
72 })
73 public final class ExifParserFileIngestModule implements FileIngestModule {
74 
75  private static final Logger logger = Logger.getLogger(ExifParserFileIngestModule.class.getName());
76  private final IngestServices services = IngestServices.getInstance();
77  private final AtomicInteger filesProcessed = new AtomicInteger(0);
78  private volatile boolean filesToFire = false;
79  private final List<BlackboardArtifact> listOfFacesDetectedArtifacts = new ArrayList<>();
80  private long jobId;
81  private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
83  private final HashSet<String> supportedMimeTypes = new HashSet<>();
84  private TimeZone timeZone = null;
86 
88  supportedMimeTypes.add("audio/x-wav"); //NON-NLS
89  supportedMimeTypes.add("image/jpeg"); //NON-NLS
90  supportedMimeTypes.add("image/tiff"); //NON-NLS
91  }
92 
93  @Override
94  public void startUp(IngestJobContext context) throws IngestModuleException {
95  jobId = context.getJobId();
96  refCounter.incrementAndGet(jobId);
97  try {
98  fileTypeDetector = new FileTypeDetector();
100  throw new IngestModuleException(Bundle.CannotRunFileTypeDetection(), ex);
101  }
102  }
103 
104  @Override
105  public ProcessResult process(AbstractFile content) {
106  try {
108  } catch (NoCurrentCaseException ex) {
109  logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS
110  return ProcessResult.ERROR;
111  }
112  //skip unalloc
113  if ((content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
114  || (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.SLACK)))) {
115  return ProcessResult.OK;
116  }
117 
118  if (content.isFile() == false) {
119  return ProcessResult.OK;
120  }
121 
122  // skip known
123  if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
124  return ProcessResult.OK;
125  }
126 
127  // update the tree every 1000 files if we have EXIF data that is not being being displayed
128  final int filesProcessedValue = filesProcessed.incrementAndGet();
129  if ((filesProcessedValue % 1000 == 0)) {
130  if (filesToFire) {
131  services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
132  filesToFire = false;
133  }
134  }
135 
136  //skip unsupported
137  if (!parsableFormat(content)) {
138  return ProcessResult.OK;
139  }
140 
141  return processFile(content);
142  }
143 
144  @Messages({"ExifParserFileIngestModule.indexError.message=Failed to index EXIF Metadata artifact for keyword search."})
145  ProcessResult processFile(AbstractFile f) {
146  InputStream in = null;
147  BufferedInputStream bin = null;
148 
149  try {
150  in = new ReadContentInputStream(f);
151  bin = new BufferedInputStream(in);
152 
153  Collection<BlackboardAttribute> attributes = new ArrayList<>();
154  Metadata metadata = ImageMetadataReader.readMetadata(bin);
155 
156  // Date
157  ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
158  if (exifDir != null) {
159 
160  // set the timeZone for the current datasource.
161  if (timeZone == null) {
162  try {
163  Content dataSource = f.getDataSource();
164  if ((dataSource != null) && (dataSource instanceof Image)) {
165  Image image = (Image) dataSource;
166  timeZone = TimeZone.getTimeZone(image.getTimeZone());
167  }
168  } catch (TskCoreException ex) {
169  logger.log(Level.INFO, "Error getting time zones", ex); //NON-NLS
170  }
171  }
172  Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
173  if (date != null) {
174  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, ExifParserModuleFactory.getModuleName(), date.getTime() / 1000));
175  }
176  }
177 
178  // GPS Stuff
179  GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
180  if (gpsDir != null) {
181  GeoLocation loc = gpsDir.getGeoLocation();
182  if (loc != null) {
183  double latitude = loc.getLatitude();
184  double longitude = loc.getLongitude();
185  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, ExifParserModuleFactory.getModuleName(), latitude));
186  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, ExifParserModuleFactory.getModuleName(), longitude));
187  }
188 
189  Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
190  if (altitude != null) {
191  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE, ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
192  }
193  }
194 
195  // Device info
196  ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
197  if (devDir != null) {
198  String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
199  if (model != null && !model.isEmpty()) {
200  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, ExifParserModuleFactory.getModuleName(), model));
201  }
202 
203  String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
204  if (make != null && !make.isEmpty()) {
205  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, ExifParserModuleFactory.getModuleName(), make));
206  }
207  }
208 
209  // Add the attributes, if there are any, to a new artifact
210  if (!attributes.isEmpty()) {
211  BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF);
212  bba.addAttributes(attributes);
213 
214  try {
215  // index the artifact for keyword search
216  blackboard.indexArtifact(bba);
217  } catch (Blackboard.BlackboardException ex) {
218  logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
219  MessageNotifyUtil.Notify.error(
220  Bundle.ExifParserFileIngestModule_indexError_message(), bba.getDisplayName());
221  }
222  filesToFire = true;
223  }
224 
225  return ProcessResult.OK;
226  } catch (TskCoreException ex) {
227  logger.log(Level.WARNING, "Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage()); //NON-NLS
228  return ProcessResult.ERROR;
229  } catch (ImageProcessingException ex) {
230  logger.log(Level.WARNING, String.format("Failed to process the image file '%s/%s' (id=%d).", f.getParentPath(), f.getName(), f.getId()), ex);
231  return ProcessResult.ERROR;
232  } catch (ReadContentInputStreamException ex) {
233  logger.log(Level.WARNING, String.format("Error while trying to read image file '%s/%s' (id=%d).", f.getParentPath(), f.getName(), f.getId()), ex); //NON-NLS
234  return ProcessResult.ERROR;
235  } catch (IOException ex) {
236  logger.log(Level.WARNING, String.format("IOException when parsing image file '%s/%s' (id=%d).", f.getParentPath(), f.getName(), f.getId()), ex); //NON-NLS
237  return ProcessResult.ERROR;
238  } finally {
239  try {
240  if (in != null) {
241  in.close();
242  }
243  if (bin != null) {
244  bin.close();
245  }
246  } catch (IOException ex) {
247  logger.log(Level.WARNING, "Failed to close InputStream.", ex); //NON-NLS
248  return ProcessResult.ERROR;
249  }
250  }
251  }
252 
261  private boolean parsableFormat(AbstractFile f) {
262  String mimeType = fileTypeDetector.getMIMEType(f);
263  return supportedMimeTypes.contains(mimeType);
264  }
265 
266  @Override
267  public void shutDown() {
268  // We only need to check for this final event on the last module per job
269  if (refCounter.decrementAndGet(jobId) == 0) {
270  timeZone = null;
271  if (filesToFire) {
272  //send the final new data event
273  services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
274  }
275  }
276  }
277 }
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
synchronized void indexArtifact(BlackboardArtifact artifact)
Definition: Blackboard.java:58
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static synchronized IngestServices getInstance()

Copyright © 2012-2018 Basis Technology. Generated on: Thu Oct 4 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.