Autopsy  3.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
EventsRepository.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-14 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.timeline.events.db;
20 
21 import com.google.common.cache.CacheBuilder;
22 import com.google.common.cache.CacheLoader;
23 import com.google.common.cache.LoadingCache;
24 import com.google.common.cache.RemovalNotification;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.concurrent.CancellationException;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.TimeUnit;
34 import java.util.logging.Level;
35 import javafx.beans.property.ReadOnlyObjectProperty;
36 import javax.annotation.concurrent.GuardedBy;
37 import javax.swing.JOptionPane;
38 import javax.swing.SwingWorker;
39 import org.apache.commons.lang3.StringUtils;
40 import org.joda.time.Interval;
41 import org.openide.util.NbBundle;
58 
73 public class EventsRepository {
74 
75  private static final String FILES_AND_DIRS_WHERE_CLAUSE = "name != '.' AND name != '..'";
76 
77  private final EventDB eventDB;
78 
79  private final static Logger LOGGER = Logger.getLogger(EventsRepository.class.getName());
80 
81  @GuardedBy("this")
82  private SwingWorker<Void, ProgressWindow.ProgressUpdate> dbPopulationWorker;
83 
84  private final LoadingCache<Object, Long> maxCache;
85 
86  private final LoadingCache<Object, Long> minCache;
87 
89 
90  private final LoadingCache<Long, TimeLineEvent> idToEventCache;
91 
92  private final LoadingCache<ZoomParams, Map<EventType, Long>> eventCountsCache;
93 
94  private final LoadingCache<ZoomParams, List<AggregateEvent>> aggregateEventsCache;
95 
96  public Interval getBoundingEventsInterval(Interval timeRange, Filter filter) {
97  return eventDB.getBoundingEventsInterval(timeRange, filter);
98  }
99 
105  return modelInstance;
106  }
107 
108  public EventsRepository(ReadOnlyObjectProperty<ZoomParams> currentStateProperty) {
109  //TODO: we should check that case is open, or get passed a case object/directory -jm
111 
112  idToEventCache = CacheBuilder.newBuilder().maximumSize(5000L).expireAfterAccess(10, TimeUnit.MINUTES).removalListener((RemovalNotification<Long, TimeLineEvent> rn) -> {
113  //LOGGER.log(Level.INFO, "evicting event: {0}", rn.toString());
114  }).build(CacheLoader.from(eventDB::getEventById));
115  eventCountsCache = CacheBuilder.newBuilder().maximumSize(1000L).expireAfterAccess(10, TimeUnit.MINUTES).removalListener((RemovalNotification<ZoomParams, Map<EventType, Long>> rn) -> {
116  //LOGGER.log(Level.INFO, "evicting counts: {0}", rn.toString());
117  }).build(CacheLoader.from(eventDB::countEvents));
118  aggregateEventsCache = CacheBuilder.newBuilder().maximumSize(1000L).expireAfterAccess(10, TimeUnit.MINUTES).removalListener((RemovalNotification<ZoomParams, List<AggregateEvent>> rn) -> {
119  //LOGGER.log(Level.INFO, "evicting aggregated events: {0}", rn.toString());
120  }).build(CacheLoader.from(eventDB::getAggregatedEvents));
121  maxCache = CacheBuilder.newBuilder().build(CacheLoader.from(eventDB::getMaxTime));
122  minCache = CacheBuilder.newBuilder().build(CacheLoader.from(eventDB::getMinTime));
123  this.modelInstance = new FilteredEventsModel(this, currentStateProperty);
124  }
125 
126 
127 
129  public Long getMaxTime() {
130  return maxCache.getUnchecked("max"); // NON-NLS
131 // return eventDB.getMaxTime();
132  }
133 
135  public Long getMinTime() {
136  return minCache.getUnchecked("min"); // NON-NLS
137 // return eventDB.getMinTime();
138  }
139 
140  public void recordLastArtifactID(long lastArtfID) {
141  eventDB.recordLastArtifactID(lastArtfID);
142  }
143 
144  public void recordWasIngestRunning(Boolean wasIngestRunning) {
145  eventDB.recordWasIngestRunning(wasIngestRunning);
146  }
147 
148  public void recordLastObjID(Long lastObjID) {
149  eventDB.recordLastObjID(lastObjID);
150  }
151 
152  public boolean getWasIngestRunning() {
153  return eventDB.getWasIngestRunning();
154  }
155 
156  public Long getLastObjID() {
157  return eventDB.getLastObjID();
158  }
159  public long getLastArtfactID() {
160  return eventDB.getLastArtfactID();
161  }
162  public TimeLineEvent getEventById(Long eventID) {
163  return idToEventCache.getUnchecked(eventID);
164  }
165 
166  public List<AggregateEvent> getAggregatedEvents(ZoomParams params) {
167 
168  return aggregateEventsCache.getUnchecked(params);
169  }
170 
171  public Map<EventType, Long> countEvents(ZoomParams params) {
172  return eventCountsCache.getUnchecked(params);
173 
174  }
175 
176  private void invalidateCaches() {
177  minCache.invalidateAll();
178  maxCache.invalidateAll();
179  eventCountsCache.invalidateAll();
180  aggregateEventsCache.invalidateAll();
181  }
182 
183  public Set<Long> getEventIDs(Interval timeRange, Filter filter) {
184  return eventDB.getEventIDs(timeRange, filter);
185  }
186 
187  public Interval getSpanningInterval(Collection<Long> eventIDs) {
188  return eventDB.getSpanningInterval(eventIDs);
189  }
190 
191  synchronized public void rebuildRepository(Runnable r) {
192  if (dbPopulationWorker != null) {
193  dbPopulationWorker.cancel(true);
194 
195  }
197  dbPopulationWorker.execute();
198  }
199 
206  private class DBPopulationWorker extends SwingWorker<Void, ProgressWindow.ProgressUpdate> {
207 
209 
210  //TODO: can we avoid this with a state listener? does it amount to the same thing?
211  //post population operation to execute
212  private final Runnable r;
213 
214  public DBPopulationWorker(Runnable r) {
215  progressDialog = new ProgressWindow(null, true, this);
216  progressDialog.setVisible(true);
217  this.r = r;
218  }
219 
220  @Override
221  protected Void doInBackground() throws Exception {
222  process(Arrays.asList(new ProgressWindow.ProgressUpdate(0, -1, NbBundle.getMessage(this.getClass(),
223  "EventsRepository.progressWindow.msg.reinit_db"), "")));
224  //reset database
225  //TODO: can we do more incremental updates? -jm
226  eventDB.dropTable();
227  eventDB.initializeDB();
228 
229  //grab ids of all files
231  List<Long> files = skCase.findAllFileIdsWhere(FILES_AND_DIRS_WHERE_CLAUSE);
232 
233  final int numFiles = files.size();
234  process(Arrays.asList(new ProgressWindow.ProgressUpdate(0, numFiles, NbBundle.getMessage(this.getClass(),
235  "EventsRepository.progressWindow.msg.populateMacEventsFiles"), "")));
236 
237  //insert file events into db
238  int i = 1;
239  EventDB.EventTransaction trans = eventDB.beginTransaction();
240  for (final Long fID : files) {
241  if (isCancelled()) {
242  break;
243  } else {
244  try {
245  AbstractFile f = skCase.getAbstractFileById(fID);
246 
247  if(f != null){
248  //TODO: This is broken for logical files? fix -jm
249  //TODO: logical files don't necessarily have valid timestamps, so ... -jm
250  final String uniquePath = f.getUniquePath();
251  final String parentPath = f.getParentPath();
252  String datasourceName = StringUtils.substringBefore(StringUtils.stripStart(uniquePath, "/"), parentPath);
253  String rootFolder = StringUtils.substringBetween(parentPath, "/", "/");
254  String shortDesc = datasourceName + "/" + StringUtils.defaultIfBlank(rootFolder, "");
255  String medD = datasourceName + parentPath;
256 
257  //insert it into the db if time is > 0 => time is legitimate (drops logical files)
258  if (f.getAtime() > 0) {
259  eventDB.insertEvent(f.getAtime(), FileSystemTypes.FILE_ACCESSED, fID, null, uniquePath, medD, shortDesc, f.getKnown(), trans);
260  }
261  if (f.getMtime() > 0) {
262  eventDB.insertEvent(f.getMtime(), FileSystemTypes.FILE_MODIFIED, fID, null, uniquePath, medD, shortDesc, f.getKnown(), trans);
263  }
264  if (f.getCtime() > 0) {
265  eventDB.insertEvent(f.getCtime(), FileSystemTypes.FILE_CHANGED, fID, null, uniquePath, medD, shortDesc, f.getKnown(), trans);
266  }
267  if (f.getCrtime() > 0) {
268  eventDB.insertEvent(f.getCrtime(), FileSystemTypes.FILE_CREATED, fID, null, uniquePath, medD, shortDesc, f.getKnown(), trans);
269  }
270 
271  process(Arrays.asList(new ProgressWindow.ProgressUpdate(i, numFiles,
272  NbBundle.getMessage(this.getClass(),
273  "EventsRepository.progressWindow.msg.populateMacEventsFiles2"), f.getName())));
274  } else {
275  LOGGER.log(Level.WARNING, "failed to look up data for file : " + fID); // NON-NLS
276  }
277  } catch (TskCoreException tskCoreException) {
278  LOGGER.log(Level.WARNING, "failed to insert mac event for file : " + fID, tskCoreException); // NON-NLS
279  }
280  }
281  i++;
282  }
283 
284  //insert artifact based events
285  //TODO: use (not-yet existing api) to grab all artifacts with timestamps, rather than the hardcoded lists in EventType -jm
286  for (EventType type : RootEventType.allTypes) {
287  if (isCancelled()) {
288  break;
289  }
290  //skip file_system events, they are already handled above.
291  if (type instanceof ArtifactEventType) {
292  populateEventType((ArtifactEventType) type, trans, skCase);
293  }
294  }
295 
296  process(Arrays.asList(new ProgressWindow.ProgressUpdate(0, -1, NbBundle.getMessage(this.getClass(),
297  "EventsRepository.progressWindow.msg.commitingDb"), "")));
298  if (isCancelled()) {
299  eventDB.rollBackTransaction(trans);
300  } else {
301  eventDB.commitTransaction(trans, true);
302  }
303 
305 
306  return null;
307  }
308 
314  @Override
315  protected void process(List<ProgressWindow.ProgressUpdate> chunks) {
316  super.process(chunks);
317  ProgressWindow.ProgressUpdate chunk = chunks.get(chunks.size() - 1);
318  progressDialog.update(chunk);
319  }
320 
321  @Override
322  protected void done() {
323  super.done();
324  try {
325  progressDialog.close();
326  get();
327 
328  } catch (CancellationException ex) {
329  LOGGER.log(Level.INFO, "Database population was cancelled by the user. Not all events may be present or accurate. See the log for details.", ex); // NON-NLS
330  } catch (InterruptedException | ExecutionException ex) {
331  LOGGER.log(Level.WARNING, "Exception while populating database.", ex); // NON-NLS
332  JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(),
333  "EventsRepository.msgdlg.problem.text"));
334  } catch (Exception ex) {
335  LOGGER.log(Level.WARNING, "Unexpected exception while populating database.", ex); // NON-NLS
336  JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(),
337  "EventsRepository.msgdlg.problem.text"));
338  }
339  r.run(); //execute post db population operation
340  }
341 
350  try {
351  //get all the blackboard artifacts corresponding to the given event sub_type
352  final ArrayList<BlackboardArtifact> blackboardArtifacts = skCase.getBlackboardArtifacts(type.getArtifactType());
353  final int numArtifacts = blackboardArtifacts.size();
354 
355  process(Arrays.asList(new ProgressWindow.ProgressUpdate(0, numArtifacts,
356  NbBundle.getMessage(this.getClass(),
357  "EventsRepository.progressWindow.populatingXevents",
358  type.toString()), "")));
359 
360  int i = 0;
361  for (final BlackboardArtifact bbart : blackboardArtifacts) {
362  //for each artifact, extract the relevant information for the descriptions
364 
365  if (eventDescription != null && eventDescription.getTime() > 0L) { //insert it into the db if time is > 0 => time is legitimate
366  eventDB.insertEvent(eventDescription.getTime(), type, bbart.getObjectID(), bbart.getArtifactID(), eventDescription.getFullDescription(), eventDescription.getMedDescription(), eventDescription.getShortDescription(), null, trans);
367  }
368 
369  i++;
370  process(Arrays.asList(new ProgressWindow.ProgressUpdate(i, numArtifacts,
371  NbBundle.getMessage(this.getClass(),
372  "EventsRepository.progressWindow.populatingXevents",
373  type.toString()), "")));
374  }
375  } catch (TskCoreException ex) {
376  LOGGER.log(Level.SEVERE, "There was a problem getting events with sub type = " + type.toString() + ".", ex); // NON-NLS
377  }
378  }
379  }
380 }
static EventDB getEventDB(String dbPath)
Definition: EventDB.java:129
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
Interval getSpanningInterval(Collection< Long > eventIDs)
Definition: EventDB.java:270
Set< Long > getEventIDs(Interval timeRange, Filter filter)
Map< EventType, Long > countEvents(ZoomParams params)
List< Long > findAllFileIdsWhere(String sqlWhereClause)
AbstractFile getAbstractFileById(long id)
SwingWorker< Void, ProgressWindow.ProgressUpdate > dbPopulationWorker
EventsRepository(ReadOnlyObjectProperty< ZoomParams > currentStateProperty)
void populateEventType(final ArtifactEventType type, EventDB.EventTransaction trans, SleuthkitCase skCase)
final LoadingCache< Long, TimeLineEvent > idToEventCache
Interval getSpanningInterval(Collection< Long > eventIDs)
final LoadingCache< ZoomParams, Map< EventType, Long > > eventCountsCache
final LoadingCache< ZoomParams, List< AggregateEvent > > aggregateEventsCache
List< AggregateEvent > getAggregatedEvents(ZoomParams params)
static AttributeEventDescription buildEventDescription(ArtifactEventType type, BlackboardArtifact artf)
static Logger getLogger(String name)
Definition: Logger.java:131
Interval getBoundingEventsInterval(Interval timeRange, Filter filter)
static final List<?extends EventType > allTypes
Definition: EventType.java:35

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