Merge develop into collaborative

This commit is contained in:
Richard Cordovano 2015-09-18 10:26:02 -04:00
commit 33574bbf81
16 changed files with 400 additions and 68 deletions

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -62,7 +62,7 @@ class UpdateRecentCases extends JMenuItem implements DynamicMenuContent {
menuItem.setActionCommand(caseName[i].toUpperCase());
menuItem.addActionListener(new RecentItems(caseName[i], casePath[i]));
comps[i] = menuItem;
hasRecentCase = hasRecentCase || true;
hasRecentCase = true;
}
}

View File

@ -202,6 +202,13 @@
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-filesearch-FileSearchAction.instance"/>
<attr name="position" intvalue="200"/>
</file>
<folder name="RunIngestModules">
<attr name="position" intvalue="201"/>
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.sleuthkit.autopsy.ingest.Bundle"/>
<file name="org-sleuthkit-autopsy-ingest-RunIngestAction.shadow">
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-ingest-RunIngestAction.instance"/>
</file>
</folder>
<file name="org-sleuthkit-autopsy-report-ReportWizardAction.shadow">
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-report-ReportWizardAction.instance"/>
<attr name="position" intvalue="100"/>

View File

@ -1,4 +1,5 @@
OpenIDE-Module-Name=Ingest
Menu/Tools/RunIngestModules=Run Ingest Modules
CTL_IngestMessageTopComponent=Messages
HINT_IngestMessageTopComponent=Messages windows
IngestMessageDetailsPanel.backButton.text=
@ -105,3 +106,4 @@ IngestJobSettingsPanel.processUnallocCheckbox.toolTipText=Processes unallocated
IngestJobSettingsPanel.processUnallocCheckbox.text=Process Unallocated Space
IngestManager.cancellingIngest.msgDlg.text=Cancelling all currently running ingest jobs
IngestManager.serviceIsDown.msgDlg.text={0} is down
RunIngestSubMenu.menuItem.empty=-Empty-

View File

@ -0,0 +1,93 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 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.ingest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JMenuItem;
import org.openide.awt.ActionID;
import org.openide.awt.ActionRegistration;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.Presenter;
@ActionID(
category = "Tools",
id = "org.sleuthkit.autopsy.ingest.RunIngestAction"
)
@ActionRegistration(
displayName = "#CTL_RunIngestAction"
)
@Messages("CTL_RunIngestAction=Run Ingest")
public final class RunIngestAction extends CallableSystemAction implements Presenter.Menu, ActionListener {
static public RunIngestAction getInstance() {
return new RunIngestAction();
}
/**
* Call getMenuPresenters to create images sublist
*/
@Override
public void performAction() {
getMenuPresenter();
}
/**
* Gets the name of this action. This may be presented as an item in a menu.
*
* @return actionName
*/
@Override
public String getName() {
return NbBundle.getMessage(RunIngestAction.class, "RunIngestModulesMenu.getName.text");
}
/**
* Gets the HelpCtx associated with implementing object
*
* @return HelpCtx or HelpCtx.DEFAULT_HELP
*/
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
/**
* Create a sublist of images updated by RunIngestSubMenu
* Each has an action to perform Ingest Modules on it.
*
* @return the images sublist created.
*/
@Override
public JMenuItem getMenuPresenter() {
JMenuItem sublist = new RunIngestSubMenu();
sublist.setVisible(true);
return sublist;
}
/**
* This method does nothing, use performAction instead.
*/
@Override
public void actionPerformed(ActionEvent e) {
}
}

View File

@ -0,0 +1,52 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 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.ingest;
import java.awt.event.ActionEvent;
import java.util.Collections;
import javax.swing.AbstractAction;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
/**
* This class is used to add the action to the run ingest modules menu item.
* When the image is pressed, it should open the wizard for ingest modules.
*/
final class RunIngestModulesAction extends AbstractAction {
Image image;
/**
* the constructor
*/
public RunIngestModulesAction(Image image) {
this.image = image;
}
/**
* Runs the ingest modules wizard on the image.
*
* @param e the action event
*/
@Override
public void actionPerformed(ActionEvent e) {
final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(Collections.<Content>singletonList(image));
ingestDialog.display();
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2014 Basis Technology Corp.
* Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -0,0 +1,99 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 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.ingest;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import org.openide.awt.DynamicMenuContent;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* This class is used to populate the list of open images to run ingest on them
*/
final class RunIngestSubMenu extends JMenuItem implements DynamicMenuContent {
/**
* Creates main menu/popup menu items. It's called each time a popup menu
* is constructed and just once for the main menu.
* Main menu updates happen through the synchMenuPresenters() method.
*
* @return
*/
@Override
public JComponent[] getMenuPresenters() {
List<Image> images = new ArrayList<>();
try {
SleuthkitCase sk = Case.getCurrentCase().getSleuthkitCase();
images = sk.getImages();
} catch (IllegalStateException ex) {
// No open Cases, create a disabled empty menu
return getEmpty();
} catch (TskCoreException e) {
System.out.println("Exception getting images: " + e.getMessage());
}
JComponent[] comps = new JComponent[images.size()];
// Add Images to the component list
for (int i = 0; i < images.size(); i++) {
String action = images.get(i).getName();
JMenuItem menuItem = new JMenuItem(action);
menuItem.setActionCommand(action.toUpperCase());
menuItem.addActionListener(new RunIngestModulesAction(images.get(i)));
comps[i] = menuItem;
}
// If no images are open, create a disabled empty menu
if (images.isEmpty()) {
return getEmpty();
}
return comps;
}
// returns a disabled empty menu
private JComponent[] getEmpty() {
JComponent[] comps = new JComponent[1];
JMenuItem emptyMenu = new JMenuItem(NbBundle.getMessage(RunIngestSubMenu.class, "RunIngestSubMenu.menuItem.empty"));
comps[0] = emptyMenu;
comps[0].setEnabled(false);
return comps;
}
/**
* Updates main menu presenters. This method is called only by the main menu
* processing.
*
* @param jcs the previously used menu items returned by previous call to
* getMenuPresenters() or synchMenuPresenters()
*
* @return menu a new set of items to show in menu. Can be either an updated
* old set of instances or a completely new one.
*/
@Override
public JComponent[] synchMenuPresenters(JComponent[] jcs) {
return getMenuPresenters();
}
}

View File

@ -23,6 +23,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import javax.xml.bind.DatatypeConverter;
import org.openide.util.NbBundle;
import org.python.bouncycastle.util.Arrays;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
@ -48,7 +49,6 @@ public class E01VerifyIngestModule implements DataSourceIngestModule {
private MessageDigest messageDigest;
private boolean verified = false;
private boolean skipped = false;
private String calculatedHash = "";
private String storedHash = "";
private IngestJobContext context;
@ -75,8 +75,10 @@ public class E01VerifyIngestModule implements DataSourceIngestModule {
@Override
public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) {
String imgName = dataSource.getName();
// Skip non-images
if (!(dataSource instanceof Image)) {
logger.log(Level.INFO, "Skipping disk image image {0}", imgName); //NON-NLS
logger.log(Level.INFO, "Skipping non-image {0}", imgName); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.INFO, E01VerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.skipNonEwf",
@ -95,10 +97,8 @@ public class E01VerifyIngestModule implements DataSourceIngestModule {
return ProcessResult.OK;
}
if ((img.getMd5() != null) && !img.getMd5().isEmpty()) {
storedHash = img.getMd5().toLowerCase();
logger.log(Level.INFO, "Hash value stored in {0}: {1}", new Object[]{imgName, storedHash}); //NON-NLS
} else {
// Report an error for null or empty MD5
if ((img.getMd5() == null) || img.getMd5().isEmpty()) {
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, E01VerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.noStoredHash",
@ -106,6 +106,9 @@ public class E01VerifyIngestModule implements DataSourceIngestModule {
return ProcessResult.ERROR;
}
storedHash = img.getMd5().toLowerCase();
logger.log(Level.INFO, "Hash value stored in {0}: {1}", new Object[]{imgName, storedHash}); //NON-NLS
logger.log(Level.INFO, "Starting hash verification of {0}", img.getName()); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.INFO, E01VerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
@ -126,11 +129,12 @@ public class E01VerifyIngestModule implements DataSourceIngestModule {
long chunkSize = 64 * img.getSsize();
chunkSize = (chunkSize == 0) ? DEFAULT_CHUNK_SIZE : chunkSize;
int totalChunks = (int) Math.ceil(size / chunkSize);
// Casting to double to capture decimals
int totalChunks = (int) Math.ceil((double)size / (double)chunkSize);
logger.log(Level.INFO, "Total chunks = {0}", totalChunks); //NON-NLS
int read;
byte[] data;
byte[] data = new byte[(int) chunkSize];
statusHelper.switchToDeterminate(totalChunks);
// Read in byte size chunks and update the hash value with the data.
@ -138,7 +142,6 @@ public class E01VerifyIngestModule implements DataSourceIngestModule {
if (context.dataSourceIngestIsCancelled()) {
return ProcessResult.OK;
}
data = new byte[(int) chunkSize];
try {
read = img.read(data, i * chunkSize, chunkSize);
} catch (TskCoreException ex) {
@ -148,7 +151,14 @@ public class E01VerifyIngestModule implements DataSourceIngestModule {
logger.log(Level.SEVERE, msg, ex);
return ProcessResult.ERROR;
}
// Only update with the read bytes.
if(read == chunkSize) {
messageDigest.update(data);
} else {
byte[] subData = Arrays.copyOfRange(data, 0, read);
messageDigest.update(subData);
}
statusHelper.progress(i);
}

View File

@ -87,6 +87,9 @@ public class HashDbIngestModule implements FileIngestModule {
updateEnabledHashSets(hashDbManager.getKnownFileHashSets(), knownHashSets);
if (refCounter.incrementAndGet(jobId) == 1) {
// initialize job totals
getTotalsForIngestJobs(jobId);
// if first module for this job then post error msgs if needed
if (knownBadHashSets.isEmpty()) {

View File

@ -3,6 +3,7 @@ CTL_ReportWizardAction=Run Report
ArtifactSelectionDialog.titleLabel.text=Select which artifacts you would like to report on:
ArtifactSelectionDialog.okButton.text=OK
ReportVisualPanel1.reportModulesLabel.text=Report Modules:
ReportVisualPanel1.invalidModuleWarning=Encountered an invalid Report Module ({0})
DefaultReportConfigurationPanel.infoLabel.text=This report will be configured on the next screen.
ReportVisualPanel2.dataLabel.text=Select which data to report on:
ReportVisualPanel2.deselectAllButton.text=Deselect All

View File

@ -151,7 +151,7 @@ class ReportGenerator {
if (entry.getValue()) {
TableReportModule module = entry.getKey();
String reportFilePath = module.getRelativeFilePath();
if (reportFilePath != null) {
if (!reportFilePath.isEmpty()) {
tableProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath));
} else {
tableProgress.put(module, panel.addReport(module.getName(), null));
@ -165,7 +165,7 @@ class ReportGenerator {
if (entry.getValue()) {
GeneralReportModule module = entry.getKey();
String reportFilePath = module.getRelativeFilePath();
if (reportFilePath != null) {
if (!reportFilePath.isEmpty()) {
generalProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath));
} else {
generalProgress.put(module, panel.addReport(module.getName(), null));
@ -179,7 +179,7 @@ class ReportGenerator {
if (entry.getValue()) {
FileReportModule module = entry.getKey();
String reportFilePath = module.getRelativeFilePath();
if (reportFilePath != null) {
if (!reportFilePath.isEmpty()) {
fileProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath));
} else {
fileProgress.put(module, panel.addReport(module.getName(), null));

View File

@ -27,6 +27,7 @@ import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
@ -34,11 +35,12 @@ import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.python.JythonModuleLoader;
import org.sleuthkit.autopsy.report.ReportHTML;
final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
@ -64,23 +66,39 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
// Initialize the list of ReportModules
private void initModules() {
for (TableReportModule module : Lookup.getDefault().lookupAll(TableReportModule.class)) {
if (moduleIsValid(module)) {
tableModules.add(module);
modules.add(module);
} else {
popupWarning(module);
}
}
for (GeneralReportModule module : Lookup.getDefault().lookupAll(GeneralReportModule.class)) {
if (moduleIsValid(module)) {
generalModules.add(module);
modules.add(module);
} else {
popupWarning(module);
}
}
for (GeneralReportModule module : JythonModuleLoader.getGeneralReportModules()) {
if (moduleIsValid(module)) {
generalModules.add(module);
modules.add(module);
} else {
popupWarning(module);
}
}
for (FileReportModule module : Lookup.getDefault().lookupAll(FileReportModule.class)) {
if (moduleIsValid(module)) {
fileModules.add(module);
modules.add(module);
} else {
popupWarning(module);
}
}
Collections.sort(modules, new Comparator<ReportModule>() {
@ -117,6 +135,20 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
modulesJList.setSelectedIndex(selectedIndex);
}
// Make sure that the report module has a valid non-null name.
private boolean moduleIsValid(ReportModule module) {
return module.getName() != null && !module.getName().isEmpty()
&& module.getRelativeFilePath() != null;
}
private void popupWarning(ReportModule module) {
String moduleClassName = module.getClass().getSimpleName();
logger.log(Level.WARNING, "Invalid ReportModule: {0}", moduleClassName); // NON_NLS
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
NbBundle.getMessage(ReportVisualPanel1.class, "ReportVisualPanel1.invalidModuleWarning", moduleClassName),
NotifyDescriptor.ERROR_MESSAGE));
}
@Override
public String getName() {
return NbBundle.getMessage(this.getClass(), "ReportVisualPanel1.getName.text");

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-15 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,10 +21,12 @@ package org.sleuthkit.autopsy.timeline;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
/**
* This class supports programmer productivity by abstracting frequently used
@ -34,32 +36,53 @@ import org.openide.util.Exceptions;
* at
* http://stackoverflow.com/questions/11734885/javafx2-very-poor-performance-when-adding-custom-made-fxmlpanels-to-gridpane.
*
* NOTE: As described in the link above above, using FXMLConstructor will be
* inefficient if FXML is used as a template for many similar items. In that use
* case, it is much faster to build the entire hierarchy in Java. This class is
* intended only to remove the boilerplate initialization code when defining a
* relatively static layout
*
* TODO: find a way to move this to CoreUtils and remove duplicate verison in
* image analyzer
*/
public class FXMLConstructor {
static public void construct(Node n, String fxmlFileName) {
final String name = "nbres:/" + StringUtils.replace(n.getClass().getPackage().getName(), ".", "/") + "/" + fxmlFileName; // NON-NLS
System.out.println(name);
private static final Logger LOGGER = Logger.getLogger(FXMLConstructor.class.getName());
/**
* Load an fxml file and initialize a node with it. Since this manipulates
* the node, it must be called on the JFX thread.
*
*
* @param node a node to initialize from a loaded FXML
* @param fxmlFileName the the file name of the FXML to load, relative to
* the package that the class of node is defined in.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
static public void construct(Node node, String fxmlFileName) {
final String name = "nbres:/" + StringUtils.replace(node.getClass().getPackage().getName(), ".", "/") + "/" + fxmlFileName; // NON-NLS
try {
FXMLLoader fxmlLoader = new FXMLLoader(new URL(name));
fxmlLoader.setRoot(n);
fxmlLoader.setController(n);
fxmlLoader.setRoot(node);
fxmlLoader.setController(node);
try {
fxmlLoader.load();
} catch (IOException exception) {
LOGGER.log(Level.SEVERE, "FXMLConstructor was unable to load FXML, falling back on default Class Loader, and trying again.", exception);
try {
fxmlLoader.setClassLoader(FXMLLoader.getDefaultClassLoader());
fxmlLoader.load();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
LOGGER.log(Level.SEVERE, "FXMLConstructor was unable to load FXML, node initialization may not be complete.", ex);
}
}
} catch (MalformedURLException ex) {
Exceptions.printStackTrace(ex);
LOGGER.log(Level.SEVERE, "FXMLConstructor was unable to load FXML, node initialization may not be complete.", ex);
}
}
private FXMLConstructor() {
}
}

View File

@ -23,10 +23,11 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.logging.Level;
import javafx.scene.image.Image;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -57,7 +58,7 @@ public enum MiscTypes implements EventType, ArtifactEventType {
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME,
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME),
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION),
(BlackboardArtifact artf, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attrMap) -> {
(artf, attrMap) -> {
final BlackboardAttribute latStart = attrMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
final BlackboardAttribute longStart = attrMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
final BlackboardAttribute latEnd = attrMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
@ -129,18 +130,16 @@ public enum MiscTypes implements EventType, ArtifactEventType {
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE),
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL),
(BlackboardArtifact t,
Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> u) -> {
(artifact, attributeMap) -> {
try {
AbstractFile f = t.getSleuthkitCase().getAbstractFileById(t.getObjectID());
if (f != null) {
return f.getName();
AbstractFile file = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
if (file != null) {
return file.getName();
}
return " error loading file name"; // NON-NLS
} catch (TskCoreException ex) {
Exceptions.printStackTrace(ex);
return " error loading file name"; // NON-NLS
Logger.getLogger(MiscTypes.class.getName()).log(Level.SEVERE, "Exif event type failed to look up backing file name", ex);
}
return " error loading file name"; // NON-NLS
}),
DEVICES_ATTACHED(NbBundle.getMessage(MiscTypes.class, "MiscTypes.devicesAttached.name"), "usb_devices.png", // NON-NLS
BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED,
@ -185,26 +184,41 @@ public enum MiscTypes implements EventType, ArtifactEventType {
private final BiFunction<BlackboardArtifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute>, String> shortExtractor;
/**
* {@inheritDoc }
*/
@Override
public BiFunction<BlackboardArtifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute>, String> getFullExtractor() {
return longExtractor;
}
/**
* {@inheritDoc }
*/
@Override
public BiFunction<BlackboardArtifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute>, String> getMedExtractor() {
return medExtractor;
}
/**
* {@inheritDoc }
*/
@Override
public BiFunction<BlackboardArtifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute>, String> getShortExtractor() {
return shortExtractor;
}
/**
* {@inheritDoc }
*/
@Override
public BlackboardAttribute.ATTRIBUTE_TYPE getDateTimeAttrubuteType() {
return dateTimeAttributeType;
}
/**
* {@inheritDoc }
*/
@Override
public EventTypeZoomLevel getZoomLevel() {
return EventTypeZoomLevel.SUB_TYPE;

View File

@ -1071,9 +1071,12 @@ public class EventDB {
String timeZone = TimeLineController.getTimeZone().get().equals(TimeZone.getDefault()) ? ", 'localtime'" : ""; // NON-NLS
String typeColumn = typeColumnHelper(useSubTypes);
//compose query string
//compose query string, new-lines only for nicer formatting if printing the entire query
String query = "SELECT strftime('" + strfTimeFormat + "',time , 'unixepoch'" + timeZone + ") AS interval," // NON-NLS
+ " group_concat(events.event_id) as event_ids, min(time), max(time), " + typeColumn + ", " + descriptionColumn // NON-NLS
+ "\n group_concat(events.event_id) as event_ids,"
+ "\n group_concat(CASE WHEN hash_hit = 1 THEN event_id ELSE NULL END) as hash_hits,"
+ "\n group_concat(CASE WHEN tagged = 1 THEN event_id ELSE NULL END) as taggeds,"
+ "\n min(time), max(time), " + typeColumn + ", " + descriptionColumn // NON-NLS
+ "\n FROM events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter) // NON-NLS
+ "\n WHERE time >= " + start + " AND time < " + end + " AND " + SQLHelper.getSQLWhere(filter) // NON-NLS
+ "\n GROUP BY interval, " + typeColumn + " , " + descriptionColumn // NON-NLS
@ -1081,6 +1084,7 @@ public class EventDB {
// perform query and map results to AggregateEvent objects
List<AggregateEvent> events = new ArrayList<>();
DBLock.lock();
try (Statement createStatement = con.createStatement();
@ -1117,23 +1121,8 @@ public class EventDB {
String description = rs.getString(SQLHelper.getDescriptionColumn(descriptionLOD));
EventType type = useSubTypes ? RootEventType.allTypes.get(rs.getInt("sub_type")) : BaseTypes.values()[rs.getInt("base_type")];// NON-NLS
Set<Long> hashHits = new HashSet<>();
String hashHitQuery = "SELECT group_concat(event_id) FROM events WHERE event_id IN (" + eventIDsString + ") AND hash_hit = 1";// NON-NLS
try (Statement stmt = con.createStatement();
ResultSet hashHitsRS = stmt.executeQuery(hashHitQuery)) {
while (hashHitsRS.next()) {
hashHits = SQLHelper.unGroupConcat(hashHitsRS.getString("group_concat(event_id)"), Long::valueOf);// NON-NLS
}
}
Set<Long> tagged = new HashSet<>();
String taggedQuery = "SELECT group_concat(event_id) FROM events WHERE event_id IN (" + eventIDsString + ") AND tagged = 1";// NON-NLS
try (Statement stmt = con.createStatement();
ResultSet taggedRS = stmt.executeQuery(taggedQuery)) {
while (taggedRS.next()) {
tagged = SQLHelper.unGroupConcat(taggedRS.getString("group_concat(event_id)"), Long::valueOf);// NON-NLS
}
}
Set<Long> hashHits = SQLHelper.unGroupConcat(rs.getString("hash_hits"), Long::valueOf);
Set<Long> tagged = SQLHelper.unGroupConcat(rs.getString("taggeds"), Long::valueOf);
return new AggregateEvent(interval, type, eventIDs, hashHits, tagged,
description, descriptionLOD);

View File

@ -22,6 +22,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import javafx.beans.Observable;
import javax.swing.Action;
import org.joda.time.DateTime;
@ -29,8 +30,8 @@ import org.joda.time.DateTimeZone;
import org.openide.nodes.Children;
import org.openide.nodes.PropertySupport;
import org.openide.nodes.Sheet;
import org.openide.util.Exceptions;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
@ -46,6 +47,8 @@ import org.sleuthkit.datamodel.Content;
*/
class EventNode extends DisplayableItemNode {
private static final Logger LOGGER = Logger.getLogger(EventNode.class.getName());
private final TimeLineEvent e;
EventNode(TimeLineEvent eventById, AbstractFile file, BlackboardArtifact artifact) {
@ -75,7 +78,7 @@ class EventNode extends DisplayableItemNode {
try {
timePropery.setValue(getDateTimeString());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
LOGGER.log(Level.SEVERE, "unexpected error setting date/time property on EventNode explorer node", ex);
}
});
@ -105,7 +108,7 @@ class EventNode extends DisplayableItemNode {
final List<Action> factoryActions = DataModelActionsFactory.getActions(content, artifact != null);
actionsList.addAll(factoryActions);
return actionsList.toArray(new Action[0]);
return actionsList.toArray(new Action[actionsList.size()]);
}
@Override
@ -118,7 +121,11 @@ class EventNode extends DisplayableItemNode {
throw new UnsupportedOperationException("Not supported yet."); // NON-NLS //To change body of generated methods, choose Tools | Templates.
}
class TimeProperty extends PropertySupport.ReadWrite<String> {
/**
* We use TimeProperty instead of a normal NodeProperty to correctly display
* the date/time when the user changes the timezone setting.
*/
private class TimeProperty extends PropertySupport.ReadWrite<String> {
private String value;
@ -127,7 +134,7 @@ class EventNode extends DisplayableItemNode {
return false;
}
public TimeProperty(String name, String displayName, String shortDescription, String value) {
TimeProperty(String name, String displayName, String shortDescription, String value) {
super(name, String.class, displayName, shortDescription);
setValue("suppressCustomEditor", Boolean.TRUE); // remove the "..." (editing) button NON-NLS
this.value = value;