mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 11:07:43 +00:00
Merge branch 'develop' of https://github.com/sleuthkit/autopsy into develop
This commit is contained in:
commit
9d97ebdf95
@ -686,6 +686,7 @@ class ReportGenerator {
|
|||||||
NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"),
|
NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"),
|
||||||
NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(),
|
NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(),
|
||||||
MessageNotifyUtil.MessageType.ERROR);
|
MessageNotifyUtil.MessageType.ERROR);
|
||||||
|
logger.log(Level.SEVERE, "failed to generate reports", ex.getCause()); //NON-NLS
|
||||||
logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS
|
logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS
|
||||||
} // catch and ignore if we were cancelled
|
} // catch and ignore if we were cancelled
|
||||||
catch (java.util.concurrent.CancellationException ex) {
|
catch (java.util.concurrent.CancellationException ex) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
CTL_MakeTimeline="Timeline"
|
CTL_MakeTimeline=Timeline
|
||||||
CTL_TimeLineTopComponentAction=TimeLineTopComponent
|
CTL_TimeLineTopComponentAction=TimeLineTopComponent
|
||||||
CTL_TimeLineTopComponent=Timeline Window
|
CTL_TimeLineTopComponent=Timeline Window
|
||||||
HINT_TimeLineTopComponent=This is a Timeline window
|
HINT_TimeLineTopComponent=This is a Timeline window
|
||||||
@ -24,7 +24,5 @@ TimelinePanel.jButton7.text=3d
|
|||||||
TimelinePanel.jButton2.text=1m
|
TimelinePanel.jButton2.text=1m
|
||||||
TimelinePanel.jButton3.text=3m
|
TimelinePanel.jButton3.text=3m
|
||||||
TimelinePanel.jButton4.text=2w
|
TimelinePanel.jButton4.text=2w
|
||||||
OpenTimelineAction.title=Timeline
|
|
||||||
OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources.
|
|
||||||
ProgressWindow.progressHeader.text=\
|
ProgressWindow.progressHeader.text=\
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013 Basis Technology Corp.
|
* Copyright 2013-16 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,8 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.timeline;
|
package org.sleuthkit.autopsy.timeline;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import org.openide.awt.ActionID;
|
import org.openide.awt.ActionID;
|
||||||
import org.openide.awt.ActionReference;
|
import org.openide.awt.ActionReference;
|
||||||
import org.openide.awt.ActionReferences;
|
import org.openide.awt.ActionReferences;
|
||||||
@ -27,10 +27,10 @@ import org.openide.awt.ActionRegistration;
|
|||||||
import org.openide.util.HelpCtx;
|
import org.openide.util.HelpCtx;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.actions.CallableSystemAction;
|
import org.openide.util.actions.CallableSystemAction;
|
||||||
import org.openide.windows.WindowManager;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.core.Installer;
|
import org.sleuthkit.autopsy.core.Installer;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
|
|
||||||
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline")
|
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline")
|
||||||
@ -58,35 +58,39 @@ public class OpenTimelineAction extends CallableSystemAction {
|
|||||||
return Case.isCaseOpen() && fxInited;// && Case.getCurrentCase().hasData();
|
return Case.isCaseOpen() && fxInited;// && Case.getCurrentCase().hasData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"OpenTimelineAction.settingsErrorMessage=Failed to initialize timeline settings.",
|
||||||
|
"OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources."})
|
||||||
@Override
|
@Override
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
public void performAction() {
|
public void performAction() {
|
||||||
//check case
|
try {
|
||||||
if (!Case.isCaseOpen()) {
|
Case currentCase = Case.getCurrentCase();
|
||||||
return;
|
if (currentCase.hasData() == false) {
|
||||||
|
MessageNotifyUtil.Message.info(Bundle.OpenTimeLineAction_msgdlg_text());
|
||||||
|
LOGGER.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (timeLineController == null) {
|
||||||
|
timeLineController = new TimeLineController(currentCase);
|
||||||
|
} else if (timeLineController.getAutopsyCase() != currentCase) {
|
||||||
|
timeLineController.shutDownTimeLine();
|
||||||
|
timeLineController = new TimeLineController(currentCase);
|
||||||
|
}
|
||||||
|
timeLineController.openTimeLine();
|
||||||
|
} catch (IOException iOException) {
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.OpenTimelineAction_settingsErrorMessage());
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to initialize per case timeline settings.", iOException);
|
||||||
|
}
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
//there is no case... Do nothing.
|
||||||
}
|
}
|
||||||
final Case currentCase = Case.getCurrentCase();
|
|
||||||
|
|
||||||
if (currentCase.hasData() == false) {
|
|
||||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
|
||||||
NbBundle.getMessage(this.getClass(), "OpenTimeLineAction.msgdlg.text"));
|
|
||||||
LOGGER.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeLineController == null) {
|
|
||||||
timeLineController = new TimeLineController(currentCase);
|
|
||||||
} else if (timeLineController.getAutopsyCase() != currentCase) {
|
|
||||||
timeLineController.closeTimeLine();
|
|
||||||
timeLineController = new TimeLineController(currentCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeLineController.openTimeLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return NbBundle.getMessage(TimeLineTopComponent.class, "OpenTimelineAction.title");
|
return NbBundle.getMessage(OpenTimelineAction.class, "CTL_MakeTimeline");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2016 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.timeline;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Properties;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides access to per-case timeline properties (key-value store).
|
||||||
|
*/
|
||||||
|
class PerCaseTimelineProperties {
|
||||||
|
|
||||||
|
private static final String STALE_KEY = "stale"; //NON-NLS
|
||||||
|
private static final String WAS_INGEST_RUNNING_KEY = "was_ingest_running"; // NON-NLS
|
||||||
|
|
||||||
|
private final Case autoCase;
|
||||||
|
private final Path propertiesPath;
|
||||||
|
|
||||||
|
PerCaseTimelineProperties(Case c) {
|
||||||
|
Objects.requireNonNull(c, "Case must not be null");
|
||||||
|
this.autoCase = c;
|
||||||
|
propertiesPath = Paths.get(autoCase.getModuleDirectory(), "Timeline", "timeline.properties"); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the DB stale, i.e. does it need to be updated because new datasources
|
||||||
|
* (eg) have been added to the case.
|
||||||
|
*
|
||||||
|
* @return true if the db is stale
|
||||||
|
*
|
||||||
|
* @throws IOException if there is a problem reading the state from disk
|
||||||
|
*/
|
||||||
|
public synchronized boolean isDBStale() throws IOException {
|
||||||
|
|
||||||
|
String stale = getProperty(STALE_KEY);
|
||||||
|
return StringUtils.isBlank(stale) ? true : Boolean.valueOf(stale);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* record the state of the events db as stale(true) or not stale(false).
|
||||||
|
*
|
||||||
|
* @param stale the new state of the event db. true for stale, false for not
|
||||||
|
* stale.
|
||||||
|
*
|
||||||
|
* @throws IOException if there was a problem writing the state to disk.
|
||||||
|
*/
|
||||||
|
public synchronized void setDbStale(Boolean stale) throws IOException {
|
||||||
|
setProperty(STALE_KEY, stale.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was ingest running the last time the database was updated?
|
||||||
|
*
|
||||||
|
* @return true if ingest was running the last time the db was updated
|
||||||
|
*
|
||||||
|
* @throws IOException if there was a problem reading from disk
|
||||||
|
*/
|
||||||
|
public synchronized boolean wasIngestRunning() throws IOException {
|
||||||
|
String stale = getProperty(WAS_INGEST_RUNNING_KEY);
|
||||||
|
return StringUtils.isBlank(stale) ? true : Boolean.valueOf(stale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* record whether ingest was running during the last time the database was
|
||||||
|
* updated
|
||||||
|
*
|
||||||
|
* @param ingestRunning true if ingest was running
|
||||||
|
*
|
||||||
|
* @throws IOException if there was a problem writing to disk
|
||||||
|
*/
|
||||||
|
public synchronized void setIngestRunning(Boolean ingestRunning) throws IOException {
|
||||||
|
setProperty(WAS_INGEST_RUNNING_KEY, ingestRunning.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a {@link Path} to the properties file. If the file does not exist, it
|
||||||
|
* will be created.
|
||||||
|
*
|
||||||
|
* @return the Path to the properties file.
|
||||||
|
*
|
||||||
|
* @throws IOException if there was a problem creating the properties file
|
||||||
|
*/
|
||||||
|
private synchronized Path getPropertiesPath() throws IOException {
|
||||||
|
|
||||||
|
if (!Files.exists(propertiesPath)) {
|
||||||
|
Path parent = propertiesPath.getParent();
|
||||||
|
Files.createDirectories(parent);
|
||||||
|
Files.createFile(propertiesPath);
|
||||||
|
}
|
||||||
|
return propertiesPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the property with the given key.
|
||||||
|
*
|
||||||
|
* @param propertyKey - The property key to get the value for.
|
||||||
|
*
|
||||||
|
* @return - the value associated with the property.
|
||||||
|
*
|
||||||
|
* @throws IOException if there was a problem reading the property from disk
|
||||||
|
*/
|
||||||
|
private synchronized String getProperty(String propertyKey) throws IOException {
|
||||||
|
return getProperties().getProperty(propertyKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the given property to the given value.
|
||||||
|
*
|
||||||
|
* @param propertyKey - The key of the property to be modified.
|
||||||
|
* @param propertyValue - the value to set the property to.
|
||||||
|
*
|
||||||
|
* @throws IOException if there was a problem writing the property to disk
|
||||||
|
*/
|
||||||
|
private synchronized void setProperty(String propertyKey, String propertyValue) throws IOException {
|
||||||
|
Path propertiesFile = getPropertiesPath();
|
||||||
|
Properties props = getProperties(propertiesFile);
|
||||||
|
props.setProperty(propertyKey, propertyValue);
|
||||||
|
|
||||||
|
try (OutputStream fos = Files.newOutputStream(propertiesFile)) {
|
||||||
|
props.store(fos, ""); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a {@link Properties} object used to store the timeline properties.
|
||||||
|
*
|
||||||
|
* @return a properties object
|
||||||
|
*
|
||||||
|
* @throws IOException if there was a problem reading the .properties file
|
||||||
|
*/
|
||||||
|
private synchronized Properties getProperties() throws IOException {
|
||||||
|
return getProperties(getPropertiesPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a {@link Properties} object populated form the given .properties
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* @param propertiesFile a path to the .properties file to load
|
||||||
|
*
|
||||||
|
* @return a properties object
|
||||||
|
*
|
||||||
|
* @throws IOException if there was a problem reading the .properties file
|
||||||
|
*/
|
||||||
|
private synchronized Properties getProperties(final Path propertiesFile) throws IOException {
|
||||||
|
try (InputStream inputStream = Files.newInputStream(propertiesFile)) {
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.load(inputStream);
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2014-2015 Basis Technology Corp.
|
* Copyright 2014-2016 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -21,8 +21,7 @@ package org.sleuthkit.autopsy.timeline;
|
|||||||
import java.awt.HeadlessException;
|
import java.awt.HeadlessException;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.sql.ResultSet;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -33,7 +32,6 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.InvalidationListener;
|
|
||||||
import javafx.beans.Observable;
|
import javafx.beans.Observable;
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
import javafx.beans.property.ReadOnlyBooleanWrapper;
|
import javafx.beans.property.ReadOnlyBooleanWrapper;
|
||||||
@ -49,7 +47,6 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.concurrent.Worker;
|
import javafx.concurrent.Worker;
|
||||||
import javafx.scene.control.Dialog;
|
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
@ -83,9 +80,6 @@ import org.sleuthkit.autopsy.timeline.utils.IntervalUtils;
|
|||||||
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;
|
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;
|
||||||
import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel;
|
import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel;
|
||||||
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
|
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller in the MVC design along with model = {@link FilteredEventsModel}
|
* Controller in the MVC design along with model = {@link FilteredEventsModel}
|
||||||
@ -139,9 +133,6 @@ public class TimeLineController {
|
|||||||
|
|
||||||
private final ReadOnlyStringWrapper status = new ReadOnlyStringWrapper();
|
private final ReadOnlyStringWrapper status = new ReadOnlyStringWrapper();
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
|
||||||
private Dialog<?> currentDialog;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* status is a string that will be displayed in the status bar as a kind of
|
* status is a string that will be displayed in the status bar as a kind of
|
||||||
* user hint/information when it is not empty
|
* user hint/information when it is not empty
|
||||||
@ -156,12 +147,13 @@ public class TimeLineController {
|
|||||||
status.set(string);
|
status.set(string);
|
||||||
}
|
}
|
||||||
private final Case autoCase;
|
private final Case autoCase;
|
||||||
|
private final PerCaseTimelineProperties perCaseTimelineProperties;
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
private final ObservableList<DescriptionFilter> quickHideMaskFilters = FXCollections.observableArrayList();
|
private final ObservableList<DescriptionFilter> quickHideFilters = FXCollections.observableArrayList();
|
||||||
|
|
||||||
public ObservableList<DescriptionFilter> getQuickHideFilters() {
|
public ObservableList<DescriptionFilter> getQuickHideFilters() {
|
||||||
return quickHideMaskFilters;
|
return quickHideFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,13 +211,12 @@ public class TimeLineController {
|
|||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private final ReadOnlyObjectWrapper<ZoomParams> currentParams = new ReadOnlyObjectWrapper<>();
|
private final ReadOnlyObjectWrapper<ZoomParams> currentParams = new ReadOnlyObjectWrapper<>();
|
||||||
|
|
||||||
//all members should be access with the intrinsict lock of this object held
|
|
||||||
//selected events (ie shown in the result viewer)
|
//selected events (ie shown in the result viewer)
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private final ObservableList<Long> selectedEventIDs = FXCollections.<Long>synchronizedObservableList(FXCollections.<Long>observableArrayList());
|
private final ObservableList<Long> selectedEventIDs = FXCollections.<Long>synchronizedObservableList(FXCollections.<Long>observableArrayList());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return an unmodifiable list of the selected event ids
|
* @return a list of the selected event ids
|
||||||
*/
|
*/
|
||||||
synchronized public ObservableList<Long> getSelectedEventIDs() {
|
synchronized public ObservableList<Long> getSelectedEventIDs() {
|
||||||
return selectedEventIDs;
|
return selectedEventIDs;
|
||||||
@ -241,14 +232,8 @@ public class TimeLineController {
|
|||||||
return selectedTimeRange.getReadOnlyProperty();
|
return selectedTimeRange.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyBooleanProperty getNewEventsFlag() {
|
public ReadOnlyBooleanProperty eventsDBStaleProperty() {
|
||||||
return newEventsFlag.getReadOnlyProperty();
|
return eventsDBStale.getReadOnlyProperty();
|
||||||
}
|
|
||||||
|
|
||||||
private final ReadOnlyBooleanWrapper needsHistogramRebuild = new ReadOnlyBooleanWrapper(false);
|
|
||||||
|
|
||||||
public ReadOnlyBooleanProperty getNeedsHistogramRebuild() {
|
|
||||||
return needsHistogramRebuild.getReadOnlyProperty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized public ReadOnlyBooleanProperty getCanAdvance() {
|
synchronized public ReadOnlyBooleanProperty getCanAdvance() {
|
||||||
@ -258,28 +243,26 @@ public class TimeLineController {
|
|||||||
synchronized public ReadOnlyBooleanProperty getCanRetreat() {
|
synchronized public ReadOnlyBooleanProperty getCanRetreat() {
|
||||||
return historyManager.getCanRetreat();
|
return historyManager.getCanRetreat();
|
||||||
}
|
}
|
||||||
private final ReadOnlyBooleanWrapper newEventsFlag = new ReadOnlyBooleanWrapper(false);
|
private final ReadOnlyBooleanWrapper eventsDBStale = new ReadOnlyBooleanWrapper(true);
|
||||||
|
|
||||||
private final PromptDialogManager promptDialogManager = new PromptDialogManager(this);
|
private final PromptDialogManager promptDialogManager = new PromptDialogManager(this);
|
||||||
|
|
||||||
public TimeLineController(Case autoCase) {
|
public TimeLineController(Case autoCase) throws IOException {
|
||||||
this.autoCase = autoCase;
|
this.autoCase = autoCase;
|
||||||
|
this.perCaseTimelineProperties = new PerCaseTimelineProperties(autoCase);
|
||||||
|
eventsDBStale.set(perCaseTimelineProperties.isDBStale());
|
||||||
|
eventsRepository = new EventsRepository(autoCase, currentParams.getReadOnlyProperty());
|
||||||
/*
|
/*
|
||||||
* as the history manager's current state changes, modify the tags
|
* as the history manager's current state changes, modify the tags
|
||||||
* filter to be in sync, and expose that as propery from
|
* filter to be in sync, and expose that as propery from
|
||||||
* TimeLineController. Do we need to do this with datasource or hash hit
|
* TimeLineController. Do we need to do this with datasource or hash hit
|
||||||
* filters?
|
* filters?
|
||||||
*/
|
*/
|
||||||
historyManager.currentState().addListener(new InvalidationListener() {
|
historyManager.currentState().addListener((Observable observable) -> {
|
||||||
public void invalidated(Observable observable) {
|
ZoomParams historyManagerParams = historyManager.getCurrentState();
|
||||||
ZoomParams historyManagerParams = historyManager.getCurrentState();
|
eventsRepository.syncTagsFilter(historyManagerParams.getFilter().getTagsFilter());
|
||||||
eventsRepository.syncTagsFilter(historyManagerParams.getFilter().getTagsFilter());
|
currentParams.set(historyManagerParams);
|
||||||
currentParams.set(historyManagerParams);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
eventsRepository = new EventsRepository(autoCase, currentParams.getReadOnlyProperty());
|
|
||||||
filteredEvents = eventsRepository.getEventsModel();
|
filteredEvents = eventsRepository.getEventsModel();
|
||||||
|
|
||||||
InitialZoomState = new ZoomParams(filteredEvents.getSpanningInterval(),
|
InitialZoomState = new ZoomParams(filteredEvents.getSpanningInterval(),
|
||||||
@ -316,19 +299,22 @@ public class TimeLineController {
|
|||||||
void rebuildRepo() {
|
void rebuildRepo() {
|
||||||
SwingUtilities.invokeLater(this::closeTimelineWindow);
|
SwingUtilities.invokeLater(this::closeTimelineWindow);
|
||||||
final CancellationProgressTask<?> rebuildRepository = eventsRepository.rebuildRepository();
|
final CancellationProgressTask<?> rebuildRepository = eventsRepository.rebuildRepository();
|
||||||
|
boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
|
||||||
rebuildRepository.stateProperty().addListener((stateProperty, oldState, newSate) -> {
|
rebuildRepository.stateProperty().addListener((stateProperty, oldState, newSate) -> {
|
||||||
//this will be on JFX thread
|
//this will be on JFX thread
|
||||||
if (newSate == Worker.State.SUCCEEDED) {
|
setIngestRunning(ingestRunning);
|
||||||
//TODO: this looks hacky. what is going on? should this be an event?
|
switch (newSate) {
|
||||||
needsHistogramRebuild.set(true);
|
case SUCCEEDED:
|
||||||
needsHistogramRebuild.set(false);
|
setEventsDBStale(false);
|
||||||
SwingUtilities.invokeLater(TimeLineController.this::showWindow);
|
SwingUtilities.invokeLater(TimeLineController.this::showWindow);
|
||||||
|
|
||||||
//TODO: should this be an event?
|
|
||||||
newEventsFlag.set(false);
|
|
||||||
historyManager.reset(filteredEvents.zoomParametersProperty().get());
|
|
||||||
TimeLineController.this.showFullRange();
|
|
||||||
|
|
||||||
|
historyManager.reset(filteredEvents.zoomParametersProperty().get());
|
||||||
|
TimeLineController.this.showFullRange();
|
||||||
|
break;
|
||||||
|
case FAILED:
|
||||||
|
case CANCELLED:
|
||||||
|
setEventsDBStale(true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
promptDialogManager.showProgressDialog(rebuildRepository);
|
promptDialogManager.showProgressDialog(rebuildRepository);
|
||||||
@ -370,7 +356,7 @@ public class TimeLineController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
public void closeTimeLine() {
|
public void shutDownTimeLine() {
|
||||||
if (mainFrame != null) {
|
if (mainFrame != null) {
|
||||||
listeningToAutopsy = false;
|
listeningToAutopsy = false;
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(ingestModuleListener);
|
IngestManager.getInstance().removeIngestModuleEventListener(ingestModuleListener);
|
||||||
@ -409,7 +395,7 @@ public class TimeLineController {
|
|||||||
/*
|
/*
|
||||||
* if the repo was not rebuilt at minimum rebuild the tags which
|
* if the repo was not rebuilt at minimum rebuild the tags which
|
||||||
* may have been updated without our knowing it, since we
|
* may have been updated without our knowing it, since we
|
||||||
* can't/aren't checking them. This should at elast be quick.
|
* can't/aren't checking them. This should at least be quick.
|
||||||
* //TODO: can we check the tags to see if we need to do this?
|
* //TODO: can we check the tags to see if we need to do this?
|
||||||
*/
|
*/
|
||||||
if (checkAndPromptForRebuild() == false) {
|
if (checkAndPromptForRebuild() == false) {
|
||||||
@ -425,7 +411,7 @@ public class TimeLineController {
|
|||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
private boolean checkAndPromptForRebuild() {
|
private boolean checkAndPromptForRebuild() {
|
||||||
//if the repo is empty just (r)ebuild it with out asking, they can always cancel part way through;
|
//if the repo is empty just (r)ebuild it with out asking, they can always cancel part way through;
|
||||||
if (eventsRepository.getLastObjID() == -1) {
|
if (eventsRepository.countAllEvents() == 0) {
|
||||||
rebuildRepo();
|
rebuildRepo();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -440,7 +426,6 @@ public class TimeLineController {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // TODO (EUR-733): Do not use SleuthkitCase.getLastObjectId
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.ANY)
|
@ThreadConfined(type = ThreadConfined.ThreadType.ANY)
|
||||||
@NbBundle.Messages({"TimeLineController.errorTitle=Timeline error.",
|
@NbBundle.Messages({"TimeLineController.errorTitle=Timeline error.",
|
||||||
"TimeLineController.outOfDate.errorMessage=Error determing if the timeline is out of date. We will assume it should be updated. See the logs for more details.",
|
"TimeLineController.outOfDate.errorMessage=Error determing if the timeline is out of date. We will assume it should be updated. See the logs for more details.",
|
||||||
@ -450,23 +435,23 @@ public class TimeLineController {
|
|||||||
"TimeLineController.rebuildReasons.incompleteOldSchema=The Timeline events database was previously populated without incomplete information: Some features may be unavailable or non-functional unless you update the events database."})
|
"TimeLineController.rebuildReasons.incompleteOldSchema=The Timeline events database was previously populated without incomplete information: Some features may be unavailable or non-functional unless you update the events database."})
|
||||||
private ArrayList<String> getRebuildReasons() {
|
private ArrayList<String> getRebuildReasons() {
|
||||||
ArrayList<String> rebuildReasons = new ArrayList<>();
|
ArrayList<String> rebuildReasons = new ArrayList<>();
|
||||||
//if ingest was running during last rebuild, prompt to rebuild
|
|
||||||
if (eventsRepository.getWasIngestRunning()) {
|
|
||||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_ingestWasRunning());
|
|
||||||
}
|
|
||||||
final SleuthkitCase sleuthkitCase = autoCase.getSleuthkitCase();
|
|
||||||
try {
|
try {
|
||||||
//if the last artifact and object ids don't match between skc and tldb, prompt to rebuild
|
//if ingest was running during last rebuild, prompt to rebuild
|
||||||
if (sleuthkitCase.getLastObjectId() != eventsRepository.getLastObjID()
|
if (perCaseTimelineProperties.wasIngestRunning()) {
|
||||||
|| getCaseLastArtifactID(sleuthkitCase) != eventsRepository.getLastArtfactID()) {
|
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_ingestWasRunning());
|
||||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDate());
|
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error determing last object id from sleutkit case. We will assume the timeline is out of date.", ex); // NON-NLS
|
} catch (IOException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error determing the state of the timeline db. We will assume the it is out of date.", ex); // NON-NLS
|
||||||
MessageNotifyUtil.Notify.error(Bundle.TimeLineController_errorTitle(),
|
MessageNotifyUtil.Notify.error(Bundle.TimeLineController_errorTitle(),
|
||||||
Bundle.TimeLineController_outOfDate_errorMessage());
|
Bundle.TimeLineController_outOfDate_errorMessage());
|
||||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDateError());
|
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDateError());
|
||||||
}
|
}
|
||||||
|
//if the events db is stale, prompt to rebuild
|
||||||
|
if (isEventsDBStale()) {
|
||||||
|
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDate());
|
||||||
|
}
|
||||||
// if the TLDB schema has been upgraded since last time TL ran, prompt for rebuild
|
// if the TLDB schema has been upgraded since last time TL ran, prompt for rebuild
|
||||||
if (eventsRepository.hasNewColumns() == false) {
|
if (eventsRepository.hasNewColumns() == false) {
|
||||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_incompleteOldSchema());
|
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_incompleteOldSchema());
|
||||||
@ -474,21 +459,6 @@ public class TimeLineController {
|
|||||||
return rebuildReasons;
|
return rebuildReasons;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getCaseLastArtifactID(final SleuthkitCase sleuthkitCase) {
|
|
||||||
//TODO: push this into sleuthkitCase
|
|
||||||
long caseLastArtfId = -1;
|
|
||||||
String query = "select Max(artifact_id) as max_id from blackboard_artifacts"; // NON-NLS //NOI18N
|
|
||||||
try (CaseDbQuery dbQuery = sleuthkitCase.executeQuery(query)) {
|
|
||||||
ResultSet resultSet = dbQuery.getResultSet();
|
|
||||||
while (resultSet.next()) {
|
|
||||||
caseLastArtfId = resultSet.getLong("max_id"); // NON-NLS //NOI18N
|
|
||||||
}
|
|
||||||
} catch (TskCoreException | SQLException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error getting last artifact id: ", ex); // NON-NLS //NOI18N
|
|
||||||
}
|
|
||||||
return caseLastArtfId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* request a time range the same length as the given period and centered
|
* request a time range the same length as the given period and centered
|
||||||
* around the middle of the currently selected range
|
* around the middle of the currently selected range
|
||||||
@ -752,6 +722,38 @@ public class TimeLineController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is the events db out of date
|
||||||
|
*
|
||||||
|
* @return true if the events db is out of date , false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isEventsDBStale() {
|
||||||
|
return eventsDBStale.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param stale the value of stale
|
||||||
|
*/
|
||||||
|
private void setEventsDBStale(final Boolean stale) {
|
||||||
|
eventsDBStale.set(stale);
|
||||||
|
try {
|
||||||
|
perCaseTimelineProperties.setDbStale(stale);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
MessageNotifyUtil.Notify.error("Timeline", "Failed to mark the timeline db as " + (stale ? "" : "not ") + "stale. Some results may be out of date or missing.");
|
||||||
|
LOGGER.log(Level.SEVERE, "Error marking the timeline db as stale.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setIngestRunning(boolean ingestRunning) {
|
||||||
|
try {
|
||||||
|
perCaseTimelineProperties.setIngestRunning(ingestRunning);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
MessageNotifyUtil.Notify.error("Timeline", "Failed to mark the timeline db as populated while ingest was" + (ingestRunning ? "" : "not ") + "running. Some results may be out of date or missing.");
|
||||||
|
LOGGER.log(Level.SEVERE, "Error marking the ingest state while the timeline db was populated.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class AutopsyIngestModuleListener implements PropertyChangeListener {
|
private class AutopsyIngestModuleListener implements PropertyChangeListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -773,12 +775,10 @@ public class TimeLineController {
|
|||||||
|
|
||||||
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
|
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
|
||||||
case CONTENT_CHANGED:
|
case CONTENT_CHANGED:
|
||||||
case DATA_ADDED:
|
|
||||||
break;
|
break;
|
||||||
|
case DATA_ADDED:
|
||||||
case FILE_DONE:
|
case FILE_DONE:
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> setEventsDBStale(true));
|
||||||
newEventsFlag.set(true);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -804,32 +804,26 @@ public class TimeLineController {
|
|||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
switch (Case.Events.valueOf(evt.getPropertyName())) {
|
switch (Case.Events.valueOf(evt.getPropertyName())) {
|
||||||
case BLACKBOARD_ARTIFACT_TAG_ADDED:
|
case BLACKBOARD_ARTIFACT_TAG_ADDED:
|
||||||
executor.submit(() -> {
|
executor.submit(() -> filteredEvents.handleArtifactTagAdded((BlackBoardArtifactTagAddedEvent) evt));
|
||||||
filteredEvents.handleArtifactTagAdded((BlackBoardArtifactTagAddedEvent) evt);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case BLACKBOARD_ARTIFACT_TAG_DELETED:
|
case BLACKBOARD_ARTIFACT_TAG_DELETED:
|
||||||
executor.submit(() -> {
|
executor.submit(() -> filteredEvents.handleArtifactTagDeleted((BlackBoardArtifactTagDeletedEvent) evt));
|
||||||
filteredEvents.handleArtifactTagDeleted((BlackBoardArtifactTagDeletedEvent) evt);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case CONTENT_TAG_ADDED:
|
case CONTENT_TAG_ADDED:
|
||||||
executor.submit(() -> {
|
executor.submit(() -> filteredEvents.handleContentTagAdded((ContentTagAddedEvent) evt));
|
||||||
filteredEvents.handleContentTagAdded((ContentTagAddedEvent) evt);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case CONTENT_TAG_DELETED:
|
case CONTENT_TAG_DELETED:
|
||||||
executor.submit(() -> {
|
executor.submit(() -> filteredEvents.handleContentTagDeleted((ContentTagDeletedEvent) evt));
|
||||||
filteredEvents.handleContentTagDeleted((ContentTagDeletedEvent) evt);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case DATA_SOURCE_ADDED:
|
case DATA_SOURCE_ADDED:
|
||||||
SwingUtilities.invokeLater(TimeLineController.this::confirmOutOfDateRebuildIfWindowOpen);
|
Platform.runLater(() -> {
|
||||||
|
setEventsDBStale(true);
|
||||||
|
SwingUtilities.invokeLater(TimeLineController.this::confirmOutOfDateRebuildIfWindowOpen);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURRENT_CASE:
|
case CURRENT_CASE:
|
||||||
OpenTimelineAction.invalidateController();
|
OpenTimelineAction.invalidateController();
|
||||||
SwingUtilities.invokeLater(TimeLineController.this::closeTimeLine);
|
SwingUtilities.invokeLater(TimeLineController.this::shutDownTimeLine);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,28 +84,6 @@ import org.sqlite.SQLiteJDBCLoader;
|
|||||||
*/
|
*/
|
||||||
public class EventDB {
|
public class EventDB {
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* enum to represent keys stored in db_info table
|
|
||||||
*/
|
|
||||||
private enum DBInfoKey {
|
|
||||||
|
|
||||||
LAST_ARTIFACT_ID("last_artifact_id"), // NON-NLS
|
|
||||||
LAST_OBJECT_ID("last_object_id"), // NON-NLS
|
|
||||||
WAS_INGEST_RUNNING("was_ingest_running"); // NON-NLS
|
|
||||||
|
|
||||||
private final String keyName;
|
|
||||||
|
|
||||||
private DBInfoKey(String keyName) {
|
|
||||||
this.keyName = keyName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return keyName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final org.sleuthkit.autopsy.coreutils.Logger LOGGER = Logger.getLogger(EventDB.class.getName());
|
private static final org.sleuthkit.autopsy.coreutils.Logger LOGGER = Logger.getLogger(EventDB.class.getName());
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -142,14 +120,12 @@ public class EventDB {
|
|||||||
|
|
||||||
private final String dbPath;
|
private final String dbPath;
|
||||||
|
|
||||||
private PreparedStatement getDBInfoStmt;
|
|
||||||
private PreparedStatement getEventByIDStmt;
|
private PreparedStatement getEventByIDStmt;
|
||||||
private PreparedStatement getMaxTimeStmt;
|
private PreparedStatement getMaxTimeStmt;
|
||||||
private PreparedStatement getMinTimeStmt;
|
private PreparedStatement getMinTimeStmt;
|
||||||
private PreparedStatement getDataSourceIDsStmt;
|
private PreparedStatement getDataSourceIDsStmt;
|
||||||
private PreparedStatement getHashSetNamesStmt;
|
private PreparedStatement getHashSetNamesStmt;
|
||||||
private PreparedStatement insertRowStmt;
|
private PreparedStatement insertRowStmt;
|
||||||
private PreparedStatement recordDBInfoStmt;
|
|
||||||
private PreparedStatement insertHashSetStmt;
|
private PreparedStatement insertHashSetStmt;
|
||||||
private PreparedStatement insertHashHitStmt;
|
private PreparedStatement insertHashHitStmt;
|
||||||
private PreparedStatement insertTagStmt;
|
private PreparedStatement insertTagStmt;
|
||||||
@ -394,14 +370,6 @@ public class EventDB {
|
|||||||
return resultIDs;
|
return resultIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getLastArtfactID() {
|
|
||||||
return getDBInfo(DBInfoKey.LAST_ARTIFACT_ID, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
long getLastObjID() {
|
|
||||||
return getDBInfo(DBInfoKey.LAST_OBJECT_ID, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this relies on the fact that no tskObj has ID 0 but 0 is the default
|
* this relies on the fact that no tskObj has ID 0 but 0 is the default
|
||||||
* value for the datasource_id column in the events table.
|
* value for the datasource_id column in the events table.
|
||||||
@ -489,10 +457,6 @@ public class EventDB {
|
|||||||
return -1l;
|
return -1l;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getWasIngestRunning() {
|
|
||||||
return getDBInfo(DBInfoKey.WAS_INGEST_RUNNING, 0) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create the table and indices if they don't already exist
|
* create the table and indices if they don't already exist
|
||||||
*
|
*
|
||||||
@ -614,8 +578,6 @@ public class EventDB {
|
|||||||
getMaxTimeStmt = prepareStatement("SELECT Max(time) AS max FROM events"); // NON-NLS
|
getMaxTimeStmt = prepareStatement("SELECT Max(time) AS max FROM events"); // NON-NLS
|
||||||
getMinTimeStmt = prepareStatement("SELECT Min(time) AS min FROM events"); // NON-NLS
|
getMinTimeStmt = prepareStatement("SELECT Min(time) AS min FROM events"); // NON-NLS
|
||||||
getEventByIDStmt = prepareStatement("SELECT * FROM events WHERE event_id = ?"); // NON-NLS
|
getEventByIDStmt = prepareStatement("SELECT * FROM events WHERE event_id = ?"); // NON-NLS
|
||||||
recordDBInfoStmt = prepareStatement("INSERT OR REPLACE INTO db_info (key, value) values (?, ?)"); // NON-NLS
|
|
||||||
getDBInfoStmt = prepareStatement("SELECT value FROM db_info WHERE key = ?"); // NON-NLS
|
|
||||||
insertHashSetStmt = prepareStatement("INSERT OR IGNORE INTO hash_sets (hash_set_name) values (?)"); //NON-NLS
|
insertHashSetStmt = prepareStatement("INSERT OR IGNORE INTO hash_sets (hash_set_name) values (?)"); //NON-NLS
|
||||||
selectHashSetStmt = prepareStatement("SELECT hash_set_id FROM hash_sets WHERE hash_set_name = ?"); //NON-NLS
|
selectHashSetStmt = prepareStatement("SELECT hash_set_id FROM hash_sets WHERE hash_set_name = ?"); //NON-NLS
|
||||||
insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, event_id) values (?,?)"); //NON-NLS
|
insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, event_id) values (?,?)"); //NON-NLS
|
||||||
@ -938,18 +900,6 @@ public class EventDB {
|
|||||||
return eventIDs;
|
return eventIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void recordLastArtifactID(long lastArtfID) {
|
|
||||||
recordDBInfo(DBInfoKey.LAST_ARTIFACT_ID, lastArtfID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void recordLastObjID(Long lastObjID) {
|
|
||||||
recordDBInfo(DBInfoKey.LAST_OBJECT_ID, lastObjID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void recordWasIngestRunning(boolean wasIngestRunning) {
|
|
||||||
recordDBInfo(DBInfoKey.WAS_INGEST_RUNNING, (wasIngestRunning ? 1 : 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void rollBackTransaction(EventTransaction trans) {
|
void rollBackTransaction(EventTransaction trans) {
|
||||||
trans.rollback();
|
trans.rollback();
|
||||||
}
|
}
|
||||||
@ -983,8 +933,7 @@ public class EventDB {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
LOGGER.log(Level.INFO, String.format("sqlite-jdbc version %s loaded in %s mode", // NON-NLS
|
LOGGER.log(Level.INFO, String.format("sqlite-jdbc version %s loaded in %s mode", // NON-NLS
|
||||||
SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
|
SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode() ? "native" : "pure-java")); // NON-NLS
|
||||||
? "native" : "pure-java")); // NON-NLS
|
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
LOGGER.log(Level.SEVERE, "Failed to determine if sqlite-jdbc is loaded in native or pure-java mode.", exception); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Failed to determine if sqlite-jdbc is loaded in native or pure-java mode.", exception); //NON-NLS
|
||||||
}
|
}
|
||||||
@ -1220,28 +1169,6 @@ public class EventDB {
|
|||||||
return useSubTypes ? "sub_type" : "base_type"; //NON-NLS
|
return useSubTypes ? "sub_type" : "base_type"; //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getDBInfo(DBInfoKey key, long defaultValue) {
|
|
||||||
DBLock.lock();
|
|
||||||
try {
|
|
||||||
getDBInfoStmt.setString(1, key.toString());
|
|
||||||
|
|
||||||
try (ResultSet rs = getDBInfoStmt.executeQuery()) {
|
|
||||||
long result = defaultValue;
|
|
||||||
while (rs.next()) {
|
|
||||||
result = rs.getLong("value"); // NON-NLS
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "failed to read key: " + key + " from db_info", ex); // NON-NLS
|
|
||||||
} finally {
|
|
||||||
DBLock.unlock();
|
|
||||||
}
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "failed to set key: " + key + " on getDBInfoStmt ", ex); // NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PreparedStatement prepareStatement(String queryString) throws SQLException {
|
private PreparedStatement prepareStatement(String queryString) throws SQLException {
|
||||||
PreparedStatement prepareStatement = con.prepareStatement(queryString);
|
PreparedStatement prepareStatement = con.prepareStatement(queryString);
|
||||||
@ -1249,20 +1176,6 @@ public class EventDB {
|
|||||||
return prepareStatement;
|
return prepareStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recordDBInfo(DBInfoKey key, long value) {
|
|
||||||
DBLock.lock();
|
|
||||||
try {
|
|
||||||
recordDBInfoStmt.setString(1, key.toString());
|
|
||||||
recordDBInfoStmt.setLong(2, value);
|
|
||||||
recordDBInfoStmt.executeUpdate();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "failed to set dbinfo key: " + key + " value: " + value, ex); // NON-NLS
|
|
||||||
} finally {
|
|
||||||
DBLock.unlock();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inner class that can reference access database connection
|
* inner class that can reference access database connection
|
||||||
*/
|
*/
|
||||||
|
@ -54,9 +54,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
|||||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
|
||||||
import org.sleuthkit.autopsy.timeline.CancellationProgressTask;
|
import org.sleuthkit.autopsy.timeline.CancellationProgressTask;
|
||||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.EventStripe;
|
import org.sleuthkit.autopsy.timeline.datamodel.EventStripe;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
||||||
@ -168,7 +166,7 @@ public class EventsRepository {
|
|||||||
*/
|
*/
|
||||||
public Long getMaxTime() {
|
public Long getMaxTime() {
|
||||||
return maxCache.getUnchecked("max"); // NON-NLS
|
return maxCache.getUnchecked("max"); // NON-NLS
|
||||||
// return eventDB.getMaxTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,32 +174,9 @@ public class EventsRepository {
|
|||||||
*/
|
*/
|
||||||
public Long getMinTime() {
|
public Long getMinTime() {
|
||||||
return minCache.getUnchecked("min"); // NON-NLS
|
return minCache.getUnchecked("min"); // NON-NLS
|
||||||
// return eventDB.getMinTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recordLastArtifactID(long lastArtfID) {
|
|
||||||
eventDB.recordLastArtifactID(lastArtfID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void recordWasIngestRunning(Boolean wasIngestRunning) {
|
|
||||||
eventDB.recordWasIngestRunning(wasIngestRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void recordLastObjID(Long lastObjID) {
|
|
||||||
eventDB.recordLastObjID(lastObjID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getWasIngestRunning() {
|
|
||||||
return eventDB.getWasIngestRunning();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getLastObjID() {
|
|
||||||
return eventDB.getLastObjID();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLastArtfactID() {
|
|
||||||
return eventDB.getLastArtfactID();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TimeLineEvent getEventById(Long eventID) {
|
public TimeLineEvent getEventById(Long eventID) {
|
||||||
return idToEventCache.getUnchecked(eventID);
|
return idToEventCache.getUnchecked(eventID);
|
||||||
@ -227,6 +202,10 @@ public class EventsRepository {
|
|||||||
return eventCountsCache.getUnchecked(params);
|
return eventCountsCache.getUnchecked(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized public int countAllEvents() {
|
||||||
|
return eventDB.countAllEvents();
|
||||||
|
}
|
||||||
|
|
||||||
private void invalidateCaches() {
|
private void invalidateCaches() {
|
||||||
minCache.invalidateAll();
|
minCache.invalidateAll();
|
||||||
maxCache.invalidateAll();
|
maxCache.invalidateAll();
|
||||||
@ -331,17 +310,7 @@ public class EventsRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param lastObjId the value of lastObjId
|
|
||||||
* @param lastArtfID the value of lastArtfID
|
|
||||||
* @param injestRunning the value of injestRunning
|
|
||||||
*/
|
|
||||||
public void recordDBPopulationState(final long lastObjId, final long lastArtfID, final Boolean injestRunning) {
|
|
||||||
recordLastObjID(lastObjId);
|
|
||||||
recordLastArtifactID(lastArtfID);
|
|
||||||
recordWasIngestRunning(injestRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean areFiltersEquivalent(RootFilter f1, RootFilter f2) {
|
public boolean areFiltersEquivalent(RootFilter f1, RootFilter f2) {
|
||||||
return SQLHelper.getSQLWhere(f1).equals(SQLHelper.getSQLWhere(f2));
|
return SQLHelper.getSQLWhere(f1).equals(SQLHelper.getSQLWhere(f2));
|
||||||
@ -470,11 +439,6 @@ public class EventsRepository {
|
|||||||
protected Void call() throws Exception {
|
protected Void call() throws Exception {
|
||||||
EventDB.EventTransaction trans = null;
|
EventDB.EventTransaction trans = null;
|
||||||
|
|
||||||
//save paramaters for recording later
|
|
||||||
long lastObjId = skCase.getLastObjectId();
|
|
||||||
long lastArtfID = TimeLineController.getCaseLastArtifactID(skCase);
|
|
||||||
boolean injestRunning = IngestManager.getInstance().isIngestRunning();
|
|
||||||
|
|
||||||
if (dbPopulationMode == DBPopulationMode.FULL) {
|
if (dbPopulationMode == DBPopulationMode.FULL) {
|
||||||
//drop old db, and add back MAC and artifact events
|
//drop old db, and add back MAC and artifact events
|
||||||
LOGGER.log(Level.INFO, "Beginning population of timeline db."); // NON-NLS
|
LOGGER.log(Level.INFO, "Beginning population of timeline db."); // NON-NLS
|
||||||
@ -513,9 +477,6 @@ public class EventsRepository {
|
|||||||
Platform.runLater(() -> cancellable.set(false));
|
Platform.runLater(() -> cancellable.set(false));
|
||||||
restartProgressHandle(Bundle.progressWindow_msg_commitingDb(), "", -1D, 1, false);
|
restartProgressHandle(Bundle.progressWindow_msg_commitingDb(), "", -1D, 1, false);
|
||||||
eventDB.commitTransaction(trans);
|
eventDB.commitTransaction(trans);
|
||||||
if (isCancelRequested() == false) {
|
|
||||||
recordDBPopulationState(lastObjId, lastArtfID, injestRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
eventDB.analyze();
|
eventDB.analyze();
|
||||||
populateFilterData(skCase);
|
populateFilterData(skCase);
|
||||||
|
@ -74,8 +74,8 @@ public class StatusBar extends ToolBar {
|
|||||||
taskLabel.setVisible(false);
|
taskLabel.setVisible(false);
|
||||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||||
|
|
||||||
refreshLabel.visibleProperty().bind(this.controller.getNewEventsFlag());
|
refreshLabel.visibleProperty().bind(this.controller.eventsDBStaleProperty());
|
||||||
refreshLabel.managedProperty().bind(this.controller.getNewEventsFlag());
|
refreshLabel.managedProperty().bind(this.controller.eventsDBStaleProperty());
|
||||||
taskLabel.textProperty().bind(this.controller.taskTitleProperty());
|
taskLabel.textProperty().bind(this.controller.taskTitleProperty());
|
||||||
messageLabel.textProperty().bind(this.controller.taskMessageProperty());
|
messageLabel.textProperty().bind(this.controller.taskMessageProperty());
|
||||||
progressBar.progressProperty().bind(this.controller.taskProgressProperty());
|
progressBar.progressProperty().bind(this.controller.taskProgressProperty());
|
||||||
@ -83,6 +83,5 @@ public class StatusBar extends ToolBar {
|
|||||||
|
|
||||||
statusLabel.textProperty().bind(this.controller.getStatusProperty());
|
statusLabel.textProperty().bind(this.controller.getStatusProperty());
|
||||||
statusLabel.visibleProperty().bind(statusLabel.textProperty().isNotEmpty());
|
statusLabel.visibleProperty().bind(statusLabel.textProperty().isNotEmpty());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,9 +347,9 @@ final public class VisualizationPanel extends BorderPane {
|
|||||||
refreshTimeUI(); //populate the viz
|
refreshTimeUI(); //populate the viz
|
||||||
|
|
||||||
//this should use an event(EventBus) , not this weird observable pattern
|
//this should use an event(EventBus) , not this weird observable pattern
|
||||||
controller.getNeedsHistogramRebuild().addListener((observable, oldValue, newValue) -> {
|
controller.eventsDBStaleProperty().addListener(staleProperty -> {
|
||||||
if (newValue) {
|
if (controller.isEventsDBStale()) {
|
||||||
refreshHistorgram();
|
Platform.runLater(VisualizationPanel.this::refreshHistorgram);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
refreshHistorgram();
|
refreshHistorgram();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user