Merge branch 'file-search' of https://github.com/sleuthkit/autopsy into 5368-GroupByPathModifications

This commit is contained in:
William Schaefer 2019-09-17 14:04:12 -04:00
commit aa01285223
104 changed files with 4483 additions and 1417 deletions

3
.gitignore vendored
View File

@ -82,7 +82,8 @@ hs_err_pid*.log
/RecentActivity/release/
/CentralRepository/release/
/.idea/
.idea/
*.iml
*.img
*.vhd

View File

@ -1,24 +1,65 @@
language: java
sudo: required
dist: trusty
dist: bionic
os:
- linux
env:
global:
- TSK_HOME=$TRAVIS_BUILD_DIR/sleuthkit/sleuthkit
addons:
apt:
update: true
packages:
- libafflib-dev
- libewf-dev
- libpq-dev
- autopoint
- libsqlite3-dev
- ant
- ant-optional
- libcppunit-dev
- wget
- openjdk-8-jdk
- openjfx=8u161-b12-1ubuntu2
- libopenjfx-java=8u161-b12-1ubuntu2
- libopenjfx-jni=8u161-b12-1ubuntu2
homebrew:
update: true
packages:
- ant
- ant-optional
- libewf
- gettext
- cppunit
- afflib
python:
- "2.7"
jdk:
- oraclejdk8
before_install:
- git clone https://github.com/sleuthkit/sleuthkit.git sleuthkit/sleuthkit
- python setupSleuthkitBranch.py
install:
- sudo apt-get install testdisk
- cd sleuthkit/sleuthkit
- sh travis_build.sh
- ./travis_install_libs.sh
before_script:
- if [ $TRAVIS_OS_NAME = linux ]; then
sudo update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java;
sudo update-alternatives --set javac /usr/lib/jvm/java-8-openjdk-amd64/bin/javac;
export PATH=/usr/bin:$PATH;
unset JAVA_HOME;
fi
script:
- set -e
- echo "Building TSK..."
- ./bootstrap && ./configure --prefix=/usr && make
- pushd bindings/java/ && ant -q dist-PostgreSQL && popd
- echo "Building Autopsy..." && echo -en 'travis_fold:start:script.build\\r'
- cd $TRAVIS_BUILD_DIR/
- ant build

View File

@ -22,12 +22,12 @@ import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,6 +24,7 @@ import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
@ -59,6 +60,7 @@ final class CollaborationMonitor {
private static final String COLLABORATION_MONITOR_EVENT = "COLLABORATION_MONITOR_EVENT"; //NON-NLS
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.ADDING_DATA_SOURCE,
Case.Events.DATA_SOURCE_ADDED, Case.Events.ADDING_DATA_SOURCE_FAILED);
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED, IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 2;
private static final String PERIODIC_TASK_THREAD_NAME = "collab-monitor-periodic-tasks-%d"; //NON-NLS
private static final long HEARTBEAT_INTERVAL_MINUTES = 1;
@ -113,7 +115,7 @@ final class CollaborationMonitor {
* Create a local tasks manager to track and broadcast local tasks.
*/
localTasksManager = new LocalTasksManager();
IngestManager.getInstance().addIngestJobEventListener(localTasksManager);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, localTasksManager);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
/**
@ -538,7 +540,7 @@ final class CollaborationMonitor {
* @return A mapping of task IDs to current tasks
*/
Map<Long, Task> getCurrentTasks() {
return currentTasks;
return Collections.unmodifiableMap(currentTasks);
}
}

View File

@ -23,7 +23,9 @@ import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
@ -44,6 +46,7 @@ import org.sleuthkit.datamodel.DataSource;
public final class IngestJobInfoPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(IngestJobInfoPanel.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED);
private List<IngestJobInfo> ingestJobs;
private final List<IngestJobInfo> ingestJobsForSelectedDataSource = new ArrayList<>();
private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel();
@ -69,7 +72,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
this.ingestModuleTable.setModel(this.ingestModuleTableModel);
});
IngestManager.getInstance().addIngestJobEventListener((PropertyChangeEvent evt) -> {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST , (PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.STARTED.toString())
|| evt.getPropertyName().equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|| evt.getPropertyName().equals(IngestManager.IngestJobEvent.COMPLETED.toString())) {

View File

@ -30,7 +30,7 @@ import java.util.List;
import java.util.Map;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.event.ListSelectionListener;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case;

View File

@ -22,7 +22,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.Collections;

View File

@ -24,7 +24,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.CaseDbAccessManager;
/**

View File

@ -24,7 +24,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.CaseDbAccessManager;
/**

View File

@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.CaseDbAccessManager;

View File

@ -81,7 +81,7 @@
<Component class="javax.swing.JLabel" name="byMimeTypeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryCountsPanel.byMimeTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryCountsPanel.byMimeTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -104,14 +104,14 @@
<Component class="javax.swing.JLabel" name="byCategoryLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryCountsPanel.byCategoryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryCountsPanel.byCategoryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryCountsPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryCountsPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>

View File

@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JLabel;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

View File

@ -52,7 +52,7 @@
<Component class="javax.swing.JLabel" name="displayNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.displayNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.displayNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -64,7 +64,7 @@
<Component class="javax.swing.JLabel" name="originalNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.originalNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.originalNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -76,7 +76,7 @@
<Component class="javax.swing.JLabel" name="sha1HashValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha1HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha1HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -88,10 +88,10 @@
<Component class="javax.swing.JLabel" name="operatingSystemValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.operatingSystemValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.operatingSystemValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.operatingSystemValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.operatingSystemValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -103,7 +103,7 @@
<Component class="javax.swing.JLabel" name="displayNameValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.displayNameValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.displayNameValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -115,7 +115,7 @@
<Component class="javax.swing.JLabel" name="sha256HashValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha256HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha256HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -127,7 +127,7 @@
<Component class="javax.swing.JLabel" name="originalNameValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.originalNameValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.originalNameValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -139,10 +139,10 @@
<Component class="javax.swing.JLabel" name="deviceIdValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -179,7 +179,7 @@
<TableColumnModel selectionModel="0">
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.filePathsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.filePathsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Title>
<Editor/>
<Renderer/>
@ -196,7 +196,7 @@
<Component class="javax.swing.JLabel" name="dataSourceUsageValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.dataSourceUsageValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.dataSourceUsageValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -208,7 +208,7 @@
<Component class="javax.swing.JLabel" name="timeZoneValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.timeZoneValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.timeZoneValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -220,10 +220,10 @@
<Component class="javax.swing.JLabel" name="imageTypeValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -235,10 +235,10 @@
<Component class="javax.swing.JLabel" name="md5HashValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -250,7 +250,7 @@
<Component class="javax.swing.JLabel" name="sectorSizeValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sectorSizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sectorSizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -262,7 +262,7 @@
<Component class="javax.swing.JLabel" name="sizeValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -274,7 +274,7 @@
<Component class="javax.swing.JLabel" name="filePathsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.filePathsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.filePathsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -286,7 +286,7 @@
<Component class="javax.swing.JLabel" name="sha256HashLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha256HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha256HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -298,7 +298,7 @@
<Component class="javax.swing.JLabel" name="sha1HashLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha1HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha1HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -310,7 +310,7 @@
<Component class="javax.swing.JLabel" name="md5HashLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -322,7 +322,7 @@
<Component class="javax.swing.JLabel" name="sectorSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sectorSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sectorSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -334,7 +334,7 @@
<Component class="javax.swing.JLabel" name="sizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -346,7 +346,7 @@
<Component class="javax.swing.JLabel" name="imageTypeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -358,7 +358,7 @@
<Component class="javax.swing.JLabel" name="acquisitionDetailsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.acquisitionDetailsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.acquisitionDetailsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -370,7 +370,7 @@
<Component class="javax.swing.JLabel" name="timeZoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -382,7 +382,7 @@
<Component class="javax.swing.JLabel" name="dataSourceUsageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.dataSourceUsageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.dataSourceUsageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -394,7 +394,7 @@
<Component class="javax.swing.JLabel" name="deviceIdLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -427,7 +427,7 @@
</Property>
<Property name="rows" type="int" value="4"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.acquisitionDetailsTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.acquisitionDetailsTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
@ -469,7 +469,7 @@
<Component class="javax.swing.JLabel" name="unallocatedSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.unallocatedSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.unallocatedSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -481,7 +481,7 @@
<Component class="javax.swing.JLabel" name="unallocatedSizeValue">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourcesummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.unallocatedSizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.unallocatedSizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>

View File

@ -22,7 +22,7 @@ import java.text.DecimalFormat;
import java.util.Map;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.table.DefaultTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.DataSource;

View File

@ -20,9 +20,11 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary;
import java.awt.Frame;
import java.beans.PropertyChangeEvent;
import java.util.EnumSet;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import javax.swing.event.ListSelectionEvent;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel;
@ -38,6 +40,7 @@ import org.sleuthkit.datamodel.IngestJobInfo;
final class DataSourceSummaryDialog extends javax.swing.JDialog implements Observer {
private static final long serialVersionUID = 1L;
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
private final DataSourceSummaryCountsPanel countsPanel;
private final DataSourceSummaryDetailsPanel detailsPanel;
private final DataSourceBrowser dataSourcesPanel;
@ -77,7 +80,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser
}
});
//add listener to refresh jobs with Started status when they complete
IngestManager.getInstance().addIngestJobEventListener((PropertyChangeEvent evt) -> {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, (PropertyChangeEvent evt) -> {
if (evt instanceof DataSourceAnalysisCompletedEvent) {
DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt;
if (dsEvent.getResult() == Reason.ANALYSIS_COMPLETED) {

View File

@ -25,8 +25,10 @@ import static java.lang.Boolean.FALSE;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
@ -38,10 +40,8 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadUtils;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
@ -51,10 +51,13 @@ import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.coreutils.ThreadUtils;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent;
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisEvent;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -68,17 +71,18 @@ import org.sleuthkit.datamodel.TskCoreException;
public class IngestEventsListener {
private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED);
private static final String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name();
final Collection<String> recentlyAddedCeArtifacts = new LinkedHashSet<>();
private static int correlationModuleInstanceCount;
private static boolean flagNotableItems;
private static boolean flagSeenDevices;
private static boolean createCrProperties;
private final ExecutorService jobProcessingExecutor;
private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d";
private final ExecutorService jobProcessingExecutor;
private final PropertyChangeListener pcl1 = new IngestModuleEventListener();
private final PropertyChangeListener pcl2 = new IngestJobEventListener();
final Collection<String> recentlyAddedCeArtifacts = new LinkedHashSet<>();
IngestEventsListener() {
jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(INGEST_EVENT_THREAD_NAME).build());
@ -92,8 +96,8 @@ public class IngestEventsListener {
* Add all of our Ingest Event Listeners to the IngestManager Instance.
*/
public void installListeners() {
IngestManager.getInstance().addIngestModuleEventListener(pcl1);
IngestManager.getInstance().addIngestJobEventListener(pcl2);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl1);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl2);
}
/*
@ -348,8 +352,7 @@ public class IngestEventsListener {
String dataSourceName = "";
long dataSourceObjectId = -1;
try {
dataSource = ((DataSourceAnalysisCompletedEvent) event).getDataSource();
dataSource = ((DataSourceAnalysisEvent) event).getDataSource();
/*
* We only care about Images for the purpose of
* updating hash values.

View File

@ -1,7 +1,7 @@
/*
* Central Repository
*
* Copyright 2015-2018 Basis Technology Corp.
* Copyright 2015-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,6 +24,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumSet;
import java.util.Set;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.netbeans.spi.options.OptionsPanelController;
@ -49,7 +50,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(GlobalSettingsPanel.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED);
private final IngestJobEventPropertyChangeListener ingestJobEventListener;
/**
@ -72,7 +73,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
}
private void addIngestJobEventsListener() {
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
ingestStateUpdated(Case.isCaseOpen());
}

View File

@ -27,7 +27,9 @@ import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import org.netbeans.spi.sendopts.OptionProcessor;
import org.openide.LifecycleManager;
@ -65,6 +67,7 @@ import org.sleuthkit.datamodel.Content;
public class CommandLineIngestManager {
private static final Logger LOGGER = Logger.getLogger(CommandLineIngestManager.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED);
private Path rootOutputDirectory;
public CommandLineIngestManager() {
@ -100,6 +103,7 @@ public class CommandLineIngestManager {
}
}
@Override
public void run() {
LOGGER.log(Level.INFO, "Job processing task started");
@ -198,10 +202,11 @@ public class CommandLineIngestManager {
System.out.println("Unable to ingest data source " + dataSourcePath + ". Exiting...");
} catch (Throwable ex) {
/*
* Unexpected runtime exceptions firewall. This task is designed to
* be able to be run in an executor service thread pool without
* calling get() on the task's Future<Void>, so this ensures that
* such errors get logged.
* Unexpected runtime exceptions firewall. This task is
* designed to be able to be run in an executor service
* thread pool without calling get() on the task's
* Future<Void>, so this ensures that such errors get
* logged.
*/
LOGGER.log(Level.SEVERE, "Unexpected error while ingesting data source " + dataSourcePath, ex);
System.out.println("Unexpected error while ingesting data source " + dataSourcePath + ". Exiting...");
@ -229,6 +234,7 @@ public class CommandLineIngestManager {
* object.
*
* @param dataSource DataSource object
*
* @return object ID
*/
private Long getDataSourceId(AutoIngestDataSource dataSource) {
@ -268,12 +274,11 @@ public class CommandLineIngestManager {
* @param dataSource The data source.
*
* @throws
* AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
* if there was a DSP processing error
* AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException if
* there was a DSP processing error
*
* @throws InterruptedException if the thread running the job processing
* task is interrupted while blocked, i.e., if auto ingest is shutting
* down.
* @throws InterruptedException if the thread running the job processing
* task is interrupted while blocked, i.e., if auto ingest is shutting down.
*/
private void runDataSourceProcessor(Case caseForJob, AutoIngestDataSource dataSource) throws InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException {
@ -384,7 +389,7 @@ public class CommandLineIngestManager {
LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", dataSource.getPath());
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
try {
synchronized (ingestLock) {
IngestJobSettings ingestJobSettings = new IngestJobSettings(UserPreferences.getCommandLineModeIngestModuleContextString());
@ -447,7 +452,7 @@ public class CommandLineIngestManager {
* the path.
*
* @param caseFoldersPath The root case folders path.
* @param caseName The name of the case.
* @param caseName The name of the case.
*
* @return A case folder path with a time stamp suffix.
*/
@ -461,8 +466,8 @@ public class CommandLineIngestManager {
* for a case.
*
* @param folderToSearch The folder to be searched.
* @param caseName The name of the case for which a case folder is to be
* found.
* @param caseName The name of the case for which a case folder is
* to be found.
*
* @return The path of the case folder, or null if it is not found.
*/

View File

@ -23,7 +23,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.netbeans.api.sendopts.CommandException;
import org.netbeans.spi.sendopts.Env;
import org.netbeans.spi.sendopts.Option;

View File

@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.commonpropertiessearch;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;

View File

@ -24,7 +24,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import org.openide.util.NbBundle;

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-2018 Basis Technology Corp.
* Copyright 2017-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -34,6 +34,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.stream.Collectors;
@ -81,7 +82,8 @@ final public class FiltersPanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(FiltersPanel.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED);
/**
* Map from Account.Type to the checkbox for that account type's filter.
*/
@ -151,8 +153,8 @@ final public class FiltersPanel extends JPanel {
updateFilters(true);
UserPreferences.addChangeListener(preferenceChangeEvent -> {
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME) ||
preferenceChangeEvent.getKey().equals(UserPreferences.TIME_ZONE_FOR_DISPLAYS)) {
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)
|| preferenceChangeEvent.getKey().equals(UserPreferences.TIME_ZONE_FOR_DISPLAYS)) {
updateTimeZone();
}
});
@ -166,22 +168,21 @@ final public class FiltersPanel extends JPanel {
&& (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()))
{
updateFilters(true);
needsRefresh = true;
validateFilters();
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())) {
updateFilters(true);
needsRefresh = true;
validateFilters();
}
}
};
this.ingestJobListener = pce -> {
String eventType = pce.getPropertyName();
if (eventType.equals(COMPLETED.toString()) &&
updateFilters(true)) {
if (eventType.equals(COMPLETED.toString())
&& updateFilters(true)) {
needsRefresh = true;
validateFilters();
needsRefresh = true;
validateFilters();
}
};
@ -210,14 +211,14 @@ final public class FiltersPanel extends JPanel {
}
private boolean validateLimitValue() {
String selectedValue = (String)limitComboBox.getSelectedItem();
if(selectedValue.trim().equalsIgnoreCase("all")) {
String selectedValue = (String) limitComboBox.getSelectedItem();
if (selectedValue.trim().equalsIgnoreCase("all")) {
return true;
} else {
try{
try {
int value = Integer.parseInt(selectedValue);
return value > 0;
} catch( NumberFormatException ex) {
} catch (NumberFormatException ex) {
return false;
}
}
@ -250,8 +251,8 @@ final public class FiltersPanel extends JPanel {
@Override
public void addNotify() {
super.addNotify();
IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
IngestManager.getInstance().addIngestJobEventListener(ingestJobListener);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, ingestListener);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobListener);
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
//clear the device filter widget when the case changes.
devicesMap.clear();
@ -310,7 +311,7 @@ final public class FiltersPanel extends JPanel {
* Helper function to create a new instance of the CheckBoxIconPanel base on
* the Account.Type and initalState (check box state).
*
* @param type Account.Type to display on the panel
* @param type Account.Type to display on the panel
* @param initalState initial check box state
*
* @return instance of the CheckBoxIconPanel
@ -339,7 +340,7 @@ final public class FiltersPanel extends JPanel {
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
if(devicesMap.containsKey(dataSource.getDeviceId())) {
if (devicesMap.containsKey(dataSource.getDeviceId())) {
continue;
}
@ -357,7 +358,7 @@ final public class FiltersPanel extends JPanel {
logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException);
}
if(newOneFound) {
if (newOneFound) {
devicesListPane.revalidate();
}
@ -373,12 +374,12 @@ final public class FiltersPanel extends JPanel {
public void setFilters(CommunicationsFilter commFilter) {
List<CommunicationsFilter.SubFilter> subFilters = commFilter.getAndFilters();
subFilters.forEach(subFilter -> {
if( subFilter instanceof DeviceFilter ) {
setDeviceFilter((DeviceFilter)subFilter);
} else if( subFilter instanceof AccountTypeFilter) {
if (subFilter instanceof DeviceFilter) {
setDeviceFilter((DeviceFilter) subFilter);
} else if (subFilter instanceof AccountTypeFilter) {
setAccountTypeFilter((AccountTypeFilter) subFilter);
} else if (subFilter instanceof MostRecentFilter ) {
setMostRecentFilter((MostRecentFilter)subFilter);
} else if (subFilter instanceof MostRecentFilter) {
setMostRecentFilter((MostRecentFilter) subFilter);
}
});
}
@ -395,12 +396,13 @@ final public class FiltersPanel extends JPanel {
});
}
/**
* Set the state of the account type checkboxes to match the passed in filter
/**
* Set the state of the account type checkboxes to match the passed in
* filter
*
* @param typeFilter Account Types to be selected
*/
private void setAccountTypeFilter(AccountTypeFilter typeFilter){
private void setAccountTypeFilter(AccountTypeFilter typeFilter) {
accountTypeMap.forEach((type, cb) -> {
cb.setSelected(typeFilter.getAccountTypes().contains(type));
@ -439,7 +441,7 @@ final public class FiltersPanel extends JPanel {
*/
private void setMostRecentFilter(MostRecentFilter filter) {
int limit = filter.getLimit();
if(limit > 0) {
if (limit > 0) {
limitComboBox.setSelectedItem(filter.getLimit());
} else {
limitComboBox.setSelectedItem("All");
@ -448,7 +450,7 @@ final public class FiltersPanel extends JPanel {
@Subscribe
void filtersBack(CVTEvents.StateChangeEvent event) {
if(event.getCommunicationsState().getCommunicationsFilter() != null){
if (event.getCommunicationsState().getCommunicationsFilter() != null) {
setFilters(event.getCommunicationsState().getCommunicationsFilter());
setStartDateControlState(event.getCommunicationsState().getStartControlState());
setEndDateControlState(event.getCommunicationsState().getEndControlState());
@ -831,7 +833,7 @@ final public class FiltersPanel extends JPanel {
*
* @return an instance of CommunicationsFilter
*/
protected CommunicationsFilter getFilter() {
private CommunicationsFilter getFilter() {
CommunicationsFilter commsFilter = new CommunicationsFilter();
commsFilter.addAndFilter(getDeviceFilter());
commsFilter.addAndFilter(getAccountTypeFilter());
@ -878,35 +880,36 @@ final public class FiltersPanel extends JPanel {
private DateRangeFilter getDateRangeFilter() {
ZoneId zone = Utils.getUserPreferredZoneId();
return new DateRangeFilter( startCheckBox.isSelected() ? startDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0,
endCheckBox.isSelected() ? endDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0);
return new DateRangeFilter(startCheckBox.isSelected() ? startDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0,
endCheckBox.isSelected() ? endDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0);
}
/**
* Get a MostRecentFilter that based on the current state of the ui controls.
* Get a MostRecentFilter that based on the current state of the ui
* controls.
*
* @return A new instance of MostRecentFilter
*/
private MostRecentFilter getMostRecentFilter() {
String value = (String)limitComboBox.getSelectedItem();
if(value.trim().equalsIgnoreCase("all")){
String value = (String) limitComboBox.getSelectedItem();
if (value.trim().equalsIgnoreCase("all")) {
return new MostRecentFilter(-1);
} else{
} else {
try {
int count = Integer.parseInt(value);
return new MostRecentFilter(count);
} catch(NumberFormatException ex) {
} catch (NumberFormatException ex) {
return null;
}
}
}
private DateControlState getStartControlState() {
return new DateControlState (startDatePicker.getDate(), startCheckBox.isSelected());
return new DateControlState(startDatePicker.getDate(), startCheckBox.isSelected());
}
private DateControlState getEndControlState() {
return new DateControlState (endDatePicker.getDate(), endCheckBox.isSelected());
return new DateControlState(endDatePicker.getDate(), endCheckBox.isSelected());
}
/**
@ -947,19 +950,19 @@ final public class FiltersPanel extends JPanel {
*/
private void initalizeDateTimeFilters() {
Case currentCase = null;
try{
try {
currentCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
logger.log(Level.INFO, "Tried to intialize communication filters date range filters without an open case, using default values");
logger.log(Level.INFO, "Tried to intialize communication filters date range filters without an open case, using default values");
}
if(currentCase == null) {
if (currentCase == null) {
setDateTimeFiltersToDefault();
openCase = null;
return;
}
if(!currentCase.equals(openCase)) {
if (!currentCase.equals(openCase)) {
setDateTimeFiltersToDefault();
openCase = currentCase;
(new DatePickerWorker()).execute();
@ -1002,11 +1005,12 @@ final public class FiltersPanel extends JPanel {
}//GEN-LAST:event_limitComboBoxActionPerformed
/**
* A class to wrap the state of the date controls that consist of a date picker
* and a checkbox.
* A class to wrap the state of the date controls that consist of a date
* picker and a checkbox.
*
*/
final class DateControlState {
private final LocalDate date;
private final boolean enabled;
@ -1014,7 +1018,7 @@ final public class FiltersPanel extends JPanel {
* Wraps the state of the date controls that consist of a date picker
* and checkbox
*
* @param date LocalDate value of the datepicker
* @param date LocalDate value of the datepicker
* @param enabled State of the checkbox
*/
protected DateControlState(LocalDate date, boolean enabled) {
@ -1027,7 +1031,7 @@ final public class FiltersPanel extends JPanel {
*
* @return Current state LocalDate
*/
public LocalDate getDate(){
public LocalDate getDate() {
return date;
}
@ -1078,13 +1082,15 @@ final public class FiltersPanel extends JPanel {
private final javax.swing.JButton unCheckAllDevicesButton = new javax.swing.JButton();
// End of variables declaration//GEN-END:variables
/**
* This class is a small panel that appears to just be a checkbox but
* adds the functionality of being able to show an icon between the checkbox
* and label.
* This class is a small panel that appears to just be a checkbox but adds
* the functionality of being able to show an icon between the checkbox and
* label.
*/
final class CheckBoxIconPanel extends JPanel{
final class CheckBoxIconPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final JCheckBox checkbox;
private final JLabel label;
@ -1092,7 +1098,7 @@ final public class FiltersPanel extends JPanel {
* Creates a JPanel instance with the specified label and image.
*
* @param labelText The text to be displayed by the checkbox label.
* @param image The image to be dispayed by the label.
* @param image The image to be dispayed by the label.
*/
private CheckBoxIconPanel(String labelText, Icon image) {
checkbox = new JCheckBox();
@ -1139,8 +1145,8 @@ final public class FiltersPanel extends JPanel {
}
/**
* A simple class that implements CaseDbAccessQueryCallback. Can be used
* as an anonymous innerclass with the CaseDbAccessManager select function.
* A simple class that implements CaseDbAccessQueryCallback. Can be used as
* an anonymous innerclass with the CaseDbAccessManager select function.
*/
class FilterPanelQueryCallback implements CaseDbAccessQueryCallback {

View File

@ -1,12 +1,10 @@
ContactDetailsPane.nameLabel.text=Placeholder
SummaryViewer.countsPanel.border.title=Counts
SummaryViewer.contactsLabel.text=Contacts:
SummaryViewer.attachmentsLabel.text=Media Attachments:
OutlineViewPanel.messageLabel.text=<Control Disabled>
SummaryViewer.messagesDataLabel.text=messages
SummaryViewer.callLogsDataLabel.text=callLogs
SummaryViewer.contactsDataLabel.text=contacts
SummaryViewer.attachmentsDataLabel.text=attachments
SummaryViewer.messagesLabel.text=Messages:
SummaryViewer.callLogsLabel.text=Call Logs:
ThreadRootMessagePanel.showAllCheckBox.text=Show All Messages
@ -19,3 +17,7 @@ MessageViewer.showingMessagesLabel.text=Showing Messages for Thread:
MessageViewer.backButton.AccessibleContext.accessibleDescription=
MessageViewer.backButton.text=Threads
MessageViewer.showAllButton.text=All Messages
SummaryViewer.thumbnailCntLabel.text=Media Attachments:
SummaryViewer.attachmentsLable.text=Total Attachments:
SummaryViewer.thumbnailsDataLabel.text=attachments
SummaryViewer.attachmentDataLabel.text=count

View File

@ -37,12 +37,10 @@ MessageViewer_viewMessage_selected=Selected
MessageViewer_viewMessage_unthreaded=Unthreaded
SummaryViewer.countsPanel.border.title=Counts
SummaryViewer.contactsLabel.text=Contacts:
SummaryViewer.attachmentsLabel.text=Media Attachments:
OutlineViewPanel.messageLabel.text=<Control Disabled>
SummaryViewer.messagesDataLabel.text=messages
SummaryViewer.callLogsDataLabel.text=callLogs
SummaryViewer.contactsDataLabel.text=contacts
SummaryViewer.attachmentsDataLabel.text=attachments
SummaryViewer.messagesLabel.text=Messages:
SummaryViewer.callLogsLabel.text=Call Logs:
SummaryViewer_CaseRefNameColumn_Title=Case Name
@ -61,3 +59,7 @@ MessageViewer.showingMessagesLabel.text=Showing Messages for Thread:
MessageViewer.backButton.AccessibleContext.accessibleDescription=
MessageViewer.backButton.text=Threads
MessageViewer.showAllButton.text=All Messages
SummaryViewer.thumbnailCntLabel.text=Media Attachments:
SummaryViewer.attachmentsLable.text=Total Attachments:
SummaryViewer.thumbnailsDataLabel.text=attachments
SummaryViewer.attachmentDataLabel.text=count

View File

@ -21,9 +21,10 @@ package org.sleuthkit.autopsy.communications.relationships;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -51,9 +52,9 @@ public final class SelectionInfo {
/**
* Wraps the details of the currently selected accounts.
*
* @param selectedNodes Selected AccountDeviceInstances
* @param selectedEdges Selected pairs of AccountDeviceInstances
* @param communicationFilter Currently selected communications filters
* @param selectedNodes Selected AccountDeviceInstances
* @param selectedEdges Selected pairs of AccountDeviceInstances
* @param communicationFilter Currently selected communications filters
*/
public SelectionInfo(Set<AccountDeviceInstance> selectedNodes, Set<GraphEdge> selectedEdges,
CommunicationsFilter communicationFilter) {
@ -102,6 +103,7 @@ public final class SelectionInfo {
* Get the set of relationship sources from the case database
*
* @return the relationship sources (may be empty)
*
* @throws TskCoreException
*/
Set<Content> getRelationshipSources() throws TskCoreException {
@ -131,7 +133,7 @@ public final class SelectionInfo {
}
public Set<BlackboardArtifact> getArtifacts() {
if(accountArtifacts == null) {
if (accountArtifacts == null) {
accountArtifacts = new HashSet<>();
try {
@ -149,45 +151,54 @@ public final class SelectionInfo {
}
public SelectionSummary getSummary() {
if(summary == null) {
if (summary == null) {
summary = new SelectionSummary();
}
return summary;
}
final class SelectionSummary{
final class SelectionSummary {
int attachmentCnt;
int messagesCnt;
int emailCnt;
int callLogCnt;
int contactsCnt;
int mediaCnt;
SelectionSummary() {
getCounts();
}
private void getCounts(){
for(BlackboardArtifact artifact: getArtifacts()) {
private void getCounts() {
for (BlackboardArtifact artifact : getArtifacts()) {
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if(null != fromID) switch (fromID) {
case TSK_EMAIL_MSG:
emailCnt++;
break;
case TSK_CALLLOG:
callLogCnt++;
break;
case TSK_MESSAGE:
messagesCnt++;
break;
case TSK_CONTACT:
contactsCnt++;
break;
default:
break;
if (null != fromID) {
switch (fromID) {
case TSK_EMAIL_MSG:
emailCnt++;
break;
case TSK_CALLLOG:
callLogCnt++;
break;
case TSK_MESSAGE:
messagesCnt++;
break;
case TSK_CONTACT:
contactsCnt++;
break;
default:
break;
}
}
try{
attachmentCnt+= artifact.getChildrenCount();
try {
attachmentCnt += artifact.getChildrenCount();
for (Content childContent : artifact.getChildren()) {
if (ImageUtils.thumbnailSupported(childContent)) {
mediaCnt++;
}
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Exception thrown "
+ "from getChildrenCount artifactID: %d",
@ -215,12 +226,17 @@ public final class SelectionInfo {
public int getContactsCnt() {
return contactsCnt;
}
public int getThumbnailCnt() {
return mediaCnt;
}
}
/**
* Utility class to represent an edge from the graph visualization.
*/
public static class GraphEdge {
AccountDeviceInstance startNode;
AccountDeviceInstance endNode;

View File

@ -41,16 +41,18 @@
<Component id="messagesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="callLogsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="contactsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="thumbnailCntLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsLable" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="attachmentsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="attachmentDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="thumbnailsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="contactsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="callLogsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="messagesDataLabel" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="959" max="32767" attributes="0"/>
<EmptySpace pref="845" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -74,10 +76,14 @@
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="attachmentsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="thumbnailCntLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="thumbnailsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="attachmentsLable" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="attachmentDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
@ -104,17 +110,17 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="attachmentsLabel">
<Component class="javax.swing.JLabel" name="thumbnailCntLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.attachmentsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.thumbnailCntLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="attachmentsDataLabel">
<Component class="javax.swing.JLabel" name="thumbnailsDataLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.attachmentsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.thumbnailsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -139,6 +145,20 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="attachmentsLable">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.attachmentsLable.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="attachmentDataLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.attachmentDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="fileReferencesPanel">

View File

@ -104,10 +104,11 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
} else {
SelectionSummary summaryDetails = info.getSummary();
attachmentsDataLabel.setText(Integer.toString(summaryDetails.getAttachmentCnt()));
thumbnailsDataLabel.setText(Integer.toString(summaryDetails.getThumbnailCnt()));
callLogsDataLabel.setText(Integer.toString(summaryDetails.getCallLogCnt()));
contactsDataLabel.setText(Integer.toString(summaryDetails.getContactsCnt()));
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt() + summaryDetails.getEmailCnt()));
attachmentDataLabel.setText(Integer.toString(summaryDetails.getAttachmentCnt()));
fileReferencesPanel.showOutlineView();
@ -131,7 +132,7 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
attachmentsLabel.setEnabled(enabled);
thumbnailCntLabel.setEnabled(enabled);
callLogsLabel.setEnabled(enabled);
contactsLabel.setEnabled(enabled);
messagesLabel.setEnabled(enabled);
@ -144,10 +145,11 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
* Clears the text fields and OutlookViews.
*/
private void clearControls() {
attachmentsDataLabel.setText("");
thumbnailsDataLabel.setText("");
callLogsDataLabel.setText("");
contactsDataLabel.setText("");
messagesDataLabel.setText("");
attachmentDataLabel.setText("");
fileReferencesPanel.setNode(new AbstractNode(Children.LEAF));
caseReferencesPanel.setNode(new AbstractNode(Children.LEAF));
@ -187,11 +189,13 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
contactsLabel = new javax.swing.JLabel();
messagesLabel = new javax.swing.JLabel();
callLogsLabel = new javax.swing.JLabel();
attachmentsLabel = new javax.swing.JLabel();
attachmentsDataLabel = new javax.swing.JLabel();
thumbnailCntLabel = new javax.swing.JLabel();
thumbnailsDataLabel = new javax.swing.JLabel();
messagesDataLabel = new javax.swing.JLabel();
callLogsDataLabel = new javax.swing.JLabel();
contactsDataLabel = new javax.swing.JLabel();
attachmentsLable = new javax.swing.JLabel();
attachmentDataLabel = new javax.swing.JLabel();
fileReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
caseReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
@ -205,9 +209,9 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
org.openide.awt.Mnemonics.setLocalizedText(callLogsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.callLogsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(attachmentsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.attachmentsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(thumbnailCntLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.thumbnailCntLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(attachmentsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.attachmentsDataLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(thumbnailsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.thumbnailsDataLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(messagesDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.messagesDataLabel.text")); // NOI18N
@ -215,6 +219,10 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
org.openide.awt.Mnemonics.setLocalizedText(contactsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsDataLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(attachmentsLable, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.attachmentsLable.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(attachmentDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.attachmentDataLabel.text")); // NOI18N
javax.swing.GroupLayout countsPanelLayout = new javax.swing.GroupLayout(countsPanel);
countsPanel.setLayout(countsPanelLayout);
countsPanelLayout.setHorizontalGroup(
@ -225,14 +233,16 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
.addComponent(messagesLabel)
.addComponent(callLogsLabel)
.addComponent(contactsLabel)
.addComponent(attachmentsLabel))
.addComponent(thumbnailCntLabel)
.addComponent(attachmentsLable))
.addGap(18, 18, 18)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(attachmentsDataLabel)
.addComponent(attachmentDataLabel)
.addComponent(thumbnailsDataLabel)
.addComponent(contactsDataLabel)
.addComponent(callLogsDataLabel)
.addComponent(messagesDataLabel))
.addContainerGap(959, Short.MAX_VALUE))
.addContainerGap(845, Short.MAX_VALUE))
);
countsPanelLayout.setVerticalGroup(
countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -251,9 +261,12 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
.addComponent(contactsDataLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(attachmentsLabel)
.addComponent(attachmentsDataLabel))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(thumbnailCntLabel)
.addComponent(thumbnailsDataLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(attachmentsLable)
.addComponent(attachmentDataLabel)))
);
gridBagConstraints = new java.awt.GridBagConstraints();
@ -287,8 +300,8 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel attachmentsDataLabel;
private javax.swing.JLabel attachmentsLabel;
private javax.swing.JLabel attachmentDataLabel;
private javax.swing.JLabel attachmentsLable;
private javax.swing.JLabel callLogsDataLabel;
private javax.swing.JLabel callLogsLabel;
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel caseReferencesPanel;
@ -298,6 +311,8 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel fileReferencesPanel;
private javax.swing.JLabel messagesDataLabel;
private javax.swing.JLabel messagesLabel;
private javax.swing.JLabel thumbnailCntLabel;
private javax.swing.JLabel thumbnailsDataLabel;
// End of variables declaration//GEN-END:variables
}

View File

@ -22,7 +22,7 @@ import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;

View File

@ -22,7 +22,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.netbeans.api.sendopts.CommandException;
import org.netbeans.spi.sendopts.Env;
import org.netbeans.spi.sendopts.Option;

View File

@ -436,7 +436,7 @@
<folder name="Windows2">
<folder name="Components">
<file name="DirectoryTreeTopComponent.settings" url="DirectoryTreeTopComponentSettings.xml"/>
<!-- <file name="DataContentTopComponent.settings" url="DataContentTopComponentSettings.xml" /> -->
<file name="DataContentTopComponent.settings" url="DataContentTopComponentSettings.xml" />
<file name="IngestMessageTopComponent.settings" url="IngestMessageTopComponentSettings.xml"/>
</folder>
<folder name="Modes">

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -40,9 +40,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* startup).
*/
// Registered as a service provider in layer.xml
//@TopComponent.Description(preferredID = "DataContentTopComponent")
//@TopComponent.Registration(mode = "output", openAtStartup = true)
//@TopComponent.OpenActionRegistration(displayName = "#CTL_DataContentAction", preferredID = "DataContentTopComponent")
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class DataContentTopComponent extends TopComponent implements DataContent, ExplorerManager.Provider {
@ -125,15 +122,18 @@ public final class DataContentTopComponent extends TopComponent implements DataC
public static synchronized DataContentTopComponent findInstance() {
TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
if (win == null) {
logger.warning("Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); //NON-NLS
logger.log(Level.INFO, "Cannot find " + PREFERRED_ID + " component. It will "
+ "not be located properly in the window system."); //NON-NLS
return getDefault();
}
if (win instanceof DataContentTopComponent) {
return (DataContentTopComponent) win;
}
logger.warning(
"There seem to be multiple components with the '" + PREFERRED_ID //NON-NLS
logger.log(Level.INFO, "There seem to be multiple components with the '" + PREFERRED_ID //NON-NLS
+ "' ID. That is a potential source of errors and unexpected behavior."); //NON-NLS
return getDefault();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,326 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 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.coreutils;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.casemodule.services.Services;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* An abstraction around an SQLite app DB found in a data source.
* This class makes a copy of it, along with any meta files (WAL, SHM),
* opens a SQLite connection to it, and runs queries on it.
*/
public final class AppSQLiteDB implements Closeable {
private final Logger logger = Logger.getLogger(AppSQLiteDB.class.getName());
private final AbstractFile dbAbstractFile; // AbstractFile for the DB file
private final Connection connection;
private final Statement statement;
/**
* Class to abstract the abstract file for a DB file and its on disk copy
*
*/
private static final class AppSQLiteDBFileBundle {
private final AbstractFile dbAbstractFile;
private final File dbFileCopy;
AppSQLiteDBFileBundle(AbstractFile dbAbstractFile, File dbFileCopy) {
this.dbAbstractFile = dbAbstractFile;
this.dbFileCopy = dbFileCopy;
}
AbstractFile getAbstractFile() {
return dbAbstractFile;
}
File getFileCopy() {
return dbFileCopy;
}
}
private AppSQLiteDB(AppSQLiteDBFileBundle appSQLiteDBFileBundle) throws ClassNotFoundException, SQLException {
this.dbAbstractFile = appSQLiteDBFileBundle.getAbstractFile();
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver
connection = DriverManager.getConnection("jdbc:sqlite:" + appSQLiteDBFileBundle.getFileCopy().getPath()); //NON-NLS
statement = connection.createStatement();
}
/**
* Looks for the given SQLIte database filename, with matching path substring.
* It looks for exact name or a pattern match based on a input parameter.
* It makes a copy of each matching file, and creates an instance of
* AppSQLiteDB to help query the DB.
*
* A list of AppSQLiteDB instances is returned, one for each
* match found.,
* .
* @param dataSource data source to search in
* @param dbName db file name to search
* @param matchExactName whether to look for exact file name or a pattern match
* @param parentPathSubstr path substring to match
*
* @return A list of abstract files matching the specified name and path.
* Returns an empty list if no matching database is found.
*/
public static Collection<AppSQLiteDB> findAppDatabases(DataSource dataSource,
String dbName, boolean matchExactName, String parentPathSubstr) {
List<AppSQLiteDB> appDbs = new ArrayList<> ();
try {
Collection<AppSQLiteDBFileBundle> dbFileBundles = findAndCopySQLiteDB( dataSource, dbName, matchExactName, parentPathSubstr, false);
dbFileBundles.forEach((dbFileBundle) -> {
try {
AppSQLiteDB appSQLiteDB = new AppSQLiteDB(dbFileBundle);
appDbs.add(appSQLiteDB);
} catch (ClassNotFoundException | SQLException ex) {
Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Failed to open a DB connection for file = '%s' and path = '%s'.", dbFileBundle.dbAbstractFile.getName(), dbFileBundle.getFileCopy().getPath()), ex); //NON-NLS
}
});
} catch (TskCoreException ex) {
Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error finding App database files with name = '%s' and path = '%s'.", dbName, parentPathSubstr), ex); //NON-NLS
}
return appDbs;
}
public AbstractFile getDBFile() {
return this.dbAbstractFile;
}
/**
* Attaches a database to the current connection.
*
* Finds the specified database file in the specified folder.
* If found, makes copy of the database in the case folder and
* run ATTACH DATABASE sql.
*
* @param dataSource data source in which to look file the db file
* @param dbName name of db file to look for
* @param dbPath path in which to look for the db file
* @param dbAlias alias name to attach the database as
*
* @return abstract file for the matching db file.
* null if no match is found.
*
* @throws SQLException in case of an SQL error
*/
public AbstractFile attachDatabase(DataSource dataSource, String dbName,
String dbPath, String dbAlias) throws SQLException {
try {
// find and copy DB files with exact name and path.
Collection<AppSQLiteDBFileBundle> dbFileBundles = findAndCopySQLiteDB(dataSource, dbName, true, dbPath, true);
if (!dbFileBundles.isEmpty()) {
AppSQLiteDBFileBundle dbFileBundle = dbFileBundles.iterator().next();
String attachDbSql = String.format("ATTACH DATABASE '%s' AS '%s'", dbFileBundle.getFileCopy().getPath(), dbAlias); //NON-NLS
statement.executeUpdate(attachDbSql);
return dbFileBundle.getAbstractFile();
}
} catch (TskCoreException ex) {
Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error attaching to App database files with name = '%s' and path = '%s'.", dbName, dbPath), ex); //NON-NLS
}
return null;
}
/**
* Finds database file with the specified name, makes a copy of the file in the case directory,
* and returns the AbstractFile as well as the file copy.
*
* @param dataSource data source to search in
* @param dbName db file name to search
* @param matchExactName whether to look for exact file name or a pattern match
* @param dbPath path to match
* @param matchExactName whether to look for exact path name or a substring match
*
* @return a collection of AppSQLiteDBFileBundle
*
* @throws TskCoreException
*/
private static Collection<AppSQLiteDBFileBundle> findAndCopySQLiteDB(DataSource dataSource, String dbName,
boolean matchExactName, String dbPath, boolean matchExactPath) throws TskCoreException {
Case openCase;
try {
openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
throw new TskCoreException("Failed to get current case.", ex);
}
List<AppSQLiteDBFileBundle> dbFileBundles = new ArrayList<> ();
long fileId = 0;
String localDiskPath = "";
SleuthkitCase skCase = openCase.getSleuthkitCase();
String parentPath = dbPath.replace("\\", "/");
parentPath = SleuthkitCase.escapeSingleQuotes(parentPath);
String whereClause;
if (matchExactName) {
whereClause = String.format("LOWER(name) = LOWER('%s')", dbName);
} else {
whereClause = String.format("LOWER(name) LIKE LOWER('%%%s%%') AND LOWER(name) NOT LIKE LOWER('%%journal%%')", dbName );
}
if (matchExactPath) {
whereClause += String.format(" AND LOWER(parent_path) = LOWER('%s')", parentPath );
} else {
whereClause += String.format(" AND LOWER(parent_path) LIKE LOWER('%%%s%%')", parentPath );
}
whereClause += String.format(" AND data_source_obj_id = %s", dataSource.getId());
List<AbstractFile> absFiles = skCase.findAllFilesWhere(whereClause);
for (AbstractFile absFile : absFiles) {
try {
localDiskPath = openCase.getTempDirectory()
+ File.separator + absFile.getId() + absFile.getName();
File jFile = new java.io.File(localDiskPath);
fileId = absFile.getId();
ContentUtils.writeToFile(absFile, jFile);
//Find and copy both WAL and SHM meta files
findAndCopySQLiteMetaFile(absFile, absFile.getName() + "-wal");
findAndCopySQLiteMetaFile(absFile, absFile.getName() + "-shm");
AppSQLiteDBFileBundle dbFileBundle = new AppSQLiteDBFileBundle(absFile, jFile);
dbFileBundles.add(dbFileBundle);
} catch (ReadContentInputStream.ReadContentInputStreamException ex) {
Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", absFile.getName(), fileId), ex); //NON-NLS
} catch (IOException | NoCurrentCaseException | TskCoreException ex) {
Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error creating AppSQLiteDB for file '%s' (id=%d) to copied to '%s'.", absFile.getName(), fileId, localDiskPath), ex); //NON-NLS
}
}
return dbFileBundles;
}
/**
* Detaches the specified database from the connection
*
* @param dbAlias alias for database to detach
*
* @throws SQLException
*/
public void detachDatabase(String dbAlias) throws SQLException {
String detachDbSql = String.format("DETACH DATABASE '%s'", dbAlias);
statement.executeUpdate(detachDbSql); //NON-NLS
}
/**
* Runs the given query on the database and returns result set.
* @param queryStr SQL string for the query to run
*
* @return ResultSet from running the query.
*
* @throws SQLException in case of an error.
*
*/
public ResultSet runQuery(String queryStr) throws SQLException {
ResultSet resultSet = null;
if (null != queryStr) {
resultSet = statement.executeQuery(queryStr); //NON-NLS
}
return resultSet;
}
/**
* Closes the DB connection
*
* @throws IOException
*/
@Override
public void close() throws IOException {
// Close the DB connection
try {
statement.close();
connection.close();
} catch (SQLException e) {
logger.log(Level.SEVERE, "Error closing the database", e); //NON-NLS
}
}
/**
* Searches for a meta file associated with the give SQLite database. If
* found, it copies this file into the temp directory of the current case.
*
* @param sqliteFile file being processed
* @param metaFileName name of meta file to look for
*
* @throws NoCurrentCaseException Case has been closed.
* @throws TskCoreException fileManager cannot find AbstractFile
* files.
* @throws IOException Issue during writing to file.
*/
private static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile,
String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException {
Case openCase = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase();
Services services = new Services(sleuthkitCase);
FileManager fileManager = services.getFileManager();
List<AbstractFile> metaFiles = fileManager.findFiles(
sqliteFile.getDataSource(), metaFileName,
sqliteFile.getParent().getName());
if (metaFiles != null) {
for (AbstractFile metaFile : metaFiles) {
String localDiskPath = openCase.getTempDirectory()
+ File.separator + sqliteFile.getId() + metaFile.getName();
File localMetaFile = new File(localDiskPath);
if (!localMetaFile.exists()) {
ContentUtils.writeToFile(metaFile, localMetaFile);
}
}
}
}
}

View File

@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.coreutils;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import org.openide.filesystems.FileObject;
import java.nio.file.Files;
@ -172,6 +174,18 @@ public class FileUtil {
return fileName.replaceAll("[\\p{Cntrl}/:\"*?<>|]+", "_");
}
/**
* UTF-8 sanitize and escape special characters in a file name or a file name component
*
* @param fileName to escape
*
* @return Sanitized string
*/
public static String utf8SanitizeFileName(String fileName) {
Charset charset = StandardCharsets.UTF_8;
return charset.decode(charset.encode(escapeFileName(fileName))).toString();
}
/**
* Test if the current user has read and write access to the dirPath.
*

View File

@ -54,6 +54,7 @@ import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractF
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.RefreshKeysEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.CONTENT_CHANGED;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
@ -77,6 +78,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, Case.Events.CR_COMMENT_CHANGED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(CONTENT_CHANGED);
/**
* @param abstractFile file to wrap
@ -89,7 +91,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
// If this is an archive file we will listen for ingest events
// that will notify us when new content has been identified.
if (FileTypeExtensions.getArchiveExtensions().contains(ext)) {
IngestManager.getInstance().addIngestModuleEventListener(weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
}
}
@ -330,13 +332,11 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
if (EamDb.isEnabled()) {
properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), VALUE_LOADING, ""));
}
// Get the SCO columns data in a background task
backgroundTasksPool.submit(new GetSCOTask(
new WeakReference<>(this), weakPcl));
}
// Get the SCO columns data in a background task
backgroundTasksPool.submit(new GetSCOTask(
new WeakReference<>(this), weakPcl));
properties.add(new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), NO_DESCR, getContentPath(content)));
properties.add(new NodeProperty<>(MOD_TIME.toString(), MOD_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getMtime(), content)));
properties.add(new NodeProperty<>(CHANGED_TIME.toString(), CHANGED_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getCtime(), content)));
properties.add(new NodeProperty<>(ACCESS_TIME.toString(), ACCESS_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getAtime(), content)));
@ -345,6 +345,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
properties.add(new NodeProperty<>(FLAGS_DIR.toString(), FLAGS_DIR.toString(), NO_DESCR, content.getDirFlagAsString()));
properties.add(new NodeProperty<>(FLAGS_META.toString(), FLAGS_META.toString(), NO_DESCR, content.getMetaFlagsAsString()));
properties.add(new NodeProperty<>(KNOWN.toString(), KNOWN.toString(), NO_DESCR, content.getKnown().getName()));
properties.add(new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), NO_DESCR, getContentPath(content)));
properties.add(new NodeProperty<>(MD5HASH.toString(), MD5HASH.toString(), NO_DESCR, StringUtils.defaultString(content.getMd5Hash())));
properties.add(new NodeProperty<>(MIMETYPE.toString(), MIMETYPE.toString(), NO_DESCR, StringUtils.defaultString(content.getMIMEType())));
properties.add(new NodeProperty<>(EXTENSION.toString(), EXTENSION.toString(), NO_DESCR, content.getNameExtension()));

View File

@ -28,7 +28,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import java.util.prefs.PreferenceChangeEvent;
import java.util.stream.Collectors;
import org.openide.nodes.ChildFactory;

View File

@ -369,12 +369,11 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
if (EamDb.isEnabled()) {
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, ""));
}
// Get the SCO columns data in a background task
backgroundTasksPool.submit(new GetSCOTask(
new WeakReference<>(this), weakPcl));
}
// Get the SCO columns data in a background task
backgroundTasksPool.submit(new GetSCOTask(
new WeakReference<>(this), weakPcl));
if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
try {
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));

View File

@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.CONTENT_CHANGED;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
@ -190,10 +191,12 @@ public class DeletedContent implements AutopsyVisitableItem {
Case.Events.DATA_SOURCE_ADDED,
Case.Events.CURRENT_CASE
);
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(CONTENT_CHANGED);
DeletedContentsChildrenObservable() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
}

View File

@ -63,6 +63,9 @@ public class EmailExtracted implements AutopsyVisitableItem {
private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text");
private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text");
private static final String MAIL_PATH_SEPARATOR = "/";
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
/**
* Parse the path of the email msg to get the account name and folder in
* which the email is contained.
@ -88,8 +91,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
private final EmailResults emailResults;
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
/**
* Constructor
*
@ -102,7 +103,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
/**
* Constructor
*
* @param skCase Case DB
* @param skCase Case DB
* @param objId Object id of the data source
*
*/
@ -112,11 +113,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
emailResults = new EmailResults();
}
@Override
public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this);
}
private final class EmailResults extends Observable {
// NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
@ -161,7 +162,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (filteringDSObjId > 0) {
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
}
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
@ -307,8 +308,8 @@ public class EmailExtracted implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
emailResults.update();
emailResults.addObserver(this);

View File

@ -26,6 +26,7 @@ import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
@ -51,7 +52,6 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWO
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
/**
* Parent of the "extracted content" artifacts to be displayed in the tree.
@ -59,10 +59,12 @@ import org.sleuthkit.datamodel.TskException;
*/
public class ExtractedContent implements AutopsyVisitableItem {
private SleuthkitCase skCase; // set to null after case has been closed
private Blackboard blackboard;
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
private SleuthkitCase skCase; // set to null after case has been closed
private Blackboard blackboard;
/**
* Constructs extracted content object
@ -77,7 +79,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
* Constructs extracted content object
*
* @param skCase Case DB
* @param objId Object id of the parent datasource
* @param objId Object id of the parent datasource
*/
public ExtractedContent(SleuthkitCase skCase, long objId) {
this.skCase = skCase;
@ -144,8 +146,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
return filePath + "gps-search.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID()) {
return filePath + "installed.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() ||
typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID()) {
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()
|| typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID()) {
return filePath + "encrypted-file.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
return filePath + "mismatch-16.png"; //NON-NLS
@ -223,7 +225,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
// maps the artifact type to its child node
private final HashMap<BlackboardArtifact.Type, TypeNode> typeNodeList = new HashMap<>();
public TypeFactory() {
TypeFactory() {
super();
// these are shown in other parts of the UI tree
@ -235,7 +237,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT));
doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT));
doNotShow.add(new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE));
doNotShow.add(new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE) );
doNotShow.add(new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE));
}
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
@ -288,8 +290,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
}
@ -305,9 +307,9 @@ public class ExtractedContent implements AutopsyVisitableItem {
protected boolean createKeys(List<BlackboardArtifact.Type> list) {
if (skCase != null) {
try {
List<BlackboardArtifact.Type> types = (filteringDSObjId > 0) ?
blackboard.getArtifactTypesInUse(filteringDSObjId) :
skCase.getArtifactTypesInUse() ;
List<BlackboardArtifact.Type> types = (filteringDSObjId > 0)
? blackboard.getArtifactTypesInUse(filteringDSObjId)
: skCase.getArtifactTypesInUse();
types.removeAll(doNotShow);
Collections.sort(types,
@ -370,10 +372,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
// a performance increase might be had by adding a
// "getBlackboardArtifactCount()" method to skCase
try {
this.childCount = (filteringDSObjId > 0) ?
blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId) :
skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
} catch (TskException ex) {
this.childCount = (filteringDSObjId > 0)
? blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId)
: skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
} catch (TskCoreException ex) {
Logger.getLogger(TypeNode.class.getName())
.log(Level.WARNING, "Error getting child count", ex); //NON-NLS
}
@ -425,7 +427,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
private BlackboardArtifact.Type type;
public ArtifactFactory(BlackboardArtifact.Type type) {
ArtifactFactory(BlackboardArtifact.Type type) {
super(type.getTypeName());
this.type = type;
}
@ -480,8 +482,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
@Override
protected void onAdd() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
}
@Override
@ -502,7 +504,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
return (filteringDSObjId > 0)
? blackboard.getArtifacts(type.getTypeID(), filteringDSObjId)
: skCase.getBlackboardArtifacts(type.getTypeID());
} catch (TskException ex) {
} catch (TskCoreException ex) {
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
}
}

View File

@ -128,7 +128,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
private void setIcon(AbstractFile file) {
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png"); //NON-NLS
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-x-icon-16.png"); //NON-NLS
} else {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
}

View File

@ -117,6 +117,7 @@ public class FileSize implements AutopsyVisitableItem {
long filteringDataSourceObjId() {
return this.filteringDSObjId;
}
/*
* Root node. Children are nodes for specific sizes.
*/
@ -169,7 +170,7 @@ public class FileSize implements AutopsyVisitableItem {
public static class FileSizeRootChildren extends ChildFactory<org.sleuthkit.autopsy.datamodel.FileSize.FileSizeFilter> {
private SleuthkitCase skCase;
private final long datasourceObjId;
private final long datasourceObjId;
private Observable notifier;
public FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId) {
@ -185,10 +186,12 @@ public class FileSize implements AutopsyVisitableItem {
private static final class FileSizeRootChildrenObservable extends Observable {
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.CURRENT_CASE);
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.CONTENT_CHANGED);
FileSizeRootChildrenObservable() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
}
@ -266,7 +269,7 @@ public class FileSize implements AutopsyVisitableItem {
*/
public class FileSizeNode extends DisplayableItemNode {
private FileSizeFilter filter;
private final FileSizeFilter filter;
private final long datasourceObjId;
// use version with observer instead so that it updates
@ -282,9 +285,10 @@ public class FileSize implements AutopsyVisitableItem {
*
* @param skCase
* @param filter
* @param o Observable that provides updates when events are
* fired
* @param datasourceObjId filter by data source, if configured in user preferences
* @param o Observable that provides updates when
* events are fired
* @param datasourceObjId filter by data source, if configured in
* user preferences
*/
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o, long datasourceObjId) {
super(Children.create(new FileSizeChildren(filter, skCase, o, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
@ -360,11 +364,11 @@ public class FileSize implements AutopsyVisitableItem {
*/
static class FileSizeChildren extends BaseChildFactory<AbstractFile> {
private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
private final SleuthkitCase skCase;
private final FileSizeFilter filter;
private final Observable notifier;
private final long datasourceObjId;
private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
/**
*
@ -435,7 +439,7 @@ public class FileSize implements AutopsyVisitableItem {
// filter by datasource if indicated in case preferences
if (filteringDSObjId > 0) {
query += " AND data_source_obj_id = " + filteringDSObjId;
query += " AND data_source_obj_id = " + filteringDSObjId;
}
return query;

View File

@ -53,6 +53,8 @@ import org.sleuthkit.datamodel.TskData;
public final class FileTypesByExtension implements AutopsyVisitableItem {
private final static Logger logger = Logger.getLogger(FileTypesByExtension.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.CONTENT_CHANGED);
private final SleuthkitCase skCase;
private final FileTypes typesRoot;
@ -115,8 +117,8 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
}
};
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
}
@ -279,7 +281,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
* Node for a specific file type / extension. Children of it will be the
* files of that type.
*/
class FileExtensionNode extends FileTypes.BGCountUpdatingNode {
final class FileExtensionNode extends FileTypes.BGCountUpdatingNode {
private final FileTypesByExtension.SearchFilterInterface filter;
@ -365,11 +367,11 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
: " ")
+ (filteringDataSourceObjId() > 0
? " AND data_source_obj_id = " + filteringDataSourceObjId()
: " ")
? " AND data_source_obj_id = " + filteringDataSourceObjId()
: " ")
+ " AND (extension IN (" + filter.getFilter().stream()
.map(String::toLowerCase)
.map(s -> "'"+StringUtils.substringAfter(s, ".")+"'")
.map(s -> "'" + StringUtils.substringAfter(s, ".") + "'")
.collect(Collectors.joining(", ")) + "))";
}
@ -384,10 +386,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
/**
*
* @param filter Extensions to display
* @param filter Extensions to display
* @param skCase
* @param o Observable that will notify when there could be new
* data to display
* @param o Observable that will notify when there could be new
* data to display
* @param nodeName
*/
private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o, String nodeName) {
@ -493,7 +495,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
@Override
public List<String> getFilter() {
return this.filter;
return Collections.unmodifiableList(this.filter);
}
}
@ -550,7 +552,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
@Override
public List<String> getFilter() {
return this.filter;
return Collections.unmodifiableList(this.filter);
}
}
@ -597,7 +599,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
@Override
public List<String> getFilter() {
return this.filter;
return Collections.unmodifiableList(this.filter);
}
}

View File

@ -61,7 +61,7 @@ import org.sleuthkit.datamodel.TskData;
public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private final SleuthkitCase skCase;
/**
* The nodes of this tree will be determined dynamically by the mimetypes
@ -101,7 +101,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
+ "))"
+ ( (filteringDataSourceObjId() > 0) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
+ ((filteringDataSourceObjId() > 0) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
+ (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
}
@ -180,7 +180,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
}
}
};
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
populateHashMap();
}
@ -370,7 +370,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
* Node which represents the media sub type in the By MIME type tree, the
* media subtype is the portion of the MIME type following the /.
*/
class MediaSubTypeNode extends FileTypes.BGCountUpdatingNode {
final class MediaSubTypeNode extends FileTypes.BGCountUpdatingNode {
@NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype",
"FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype",

View File

@ -51,7 +51,6 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
/**
* Hash set hits node support. Inner classes have all of the nodes in the tree.
@ -61,15 +60,16 @@ public class HashsetHits implements AutopsyVisitableItem {
private static final String HASHSET_HITS = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getLabel();
private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName();
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
private SleuthkitCase skCase;
private final HashsetResults hashsetResults;
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
/**
* Constructor
*
* @param skCase Case DB
* @param skCase Case DB
*
*/
public HashsetHits(SleuthkitCase skCase) {
@ -79,7 +79,7 @@ public class HashsetHits implements AutopsyVisitableItem {
/**
* Constructor
*
* @param skCase Case DB
* @param skCase Case DB
* @param objId Object id of the data source
*
*/
@ -141,7 +141,7 @@ public class HashsetHits implements AutopsyVisitableItem {
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (filteringDSObjId > 0) {
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
}
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
@ -151,7 +151,7 @@ public class HashsetHits implements AutopsyVisitableItem {
String setName = resultSet.getString("value_text"); //NON-NLS
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
if (!hashSetHitsMap.containsKey(setName)) {
hashSetHitsMap.put(setName, new HashSet<Long>());
hashSetHitsMap.put(setName, new HashSet<>());
}
hashSetHitsMap.get(setName).add(artifactId);
}
@ -275,8 +275,8 @@ public class HashsetHits implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
hashsetResults.update();
hashsetResults.addObserver(this);
@ -377,8 +377,8 @@ public class HashsetHits implements AutopsyVisitableItem {
*/
private class HitFactory extends BaseChildFactory<BlackboardArtifact> implements Observer {
private String hashsetName;
private Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
private final String hashsetName;
private final Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
private HitFactory(String hashsetName) {
super(hashsetName);
@ -415,7 +415,7 @@ public class HashsetHits implements AutopsyVisitableItem {
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
artifactHits.put(id, art);
}
} catch (TskException ex) {
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
}
});

View File

@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.Action;
import org.apache.commons.lang3.tuple.Pair;
@ -59,6 +60,7 @@ import org.sleuthkit.datamodel.Tag;
public class ImageNode extends AbstractContentNode<Image> {
private static final Logger logger = Logger.getLogger(ImageNode.class.getName());
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.CONTENT_CHANGED);
/**
* Helper so that the display name and the name used in building the path
@ -84,7 +86,7 @@ public class ImageNode extends AbstractContentNode<Image> {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg"); //NON-NLS
// Listen for ingest events so that we can detect new added files (e.g. carved)
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
// Listen for case events so that we can detect when case is closed
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
}
@ -117,7 +119,7 @@ public class ImageNode extends AbstractContentNode<Image> {
actionsList.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
actionsList.add(new NewWindowViewAction(
NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this));
return actionsList.toArray(new Action[0]);
return actionsList.toArray(new Action[actionsList.size()]);
}
@Override

View File

@ -57,6 +57,8 @@ public class InterestingHits implements AutopsyVisitableItem {
.getMessage(InterestingHits.class, "InterestingHits.interestingItems.text");
private static final String DISPLAY_NAME = NbBundle.getMessage(InterestingHits.class, "InterestingHits.displayName.text");
private static final Logger logger = Logger.getLogger(InterestingHits.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
private SleuthkitCase skCase;
private final InterestingResults interestingResults = new InterestingResults();
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
@ -64,7 +66,7 @@ public class InterestingHits implements AutopsyVisitableItem {
/**
* Constructor
*
* @param skCase Case DB
* @param skCase Case DB
*
*/
public InterestingHits(SleuthkitCase skCase) {
@ -74,7 +76,7 @@ public class InterestingHits implements AutopsyVisitableItem {
/**
* Constructor
*
* @param skCase Case DB
* @param skCase Case DB
* @param objId Object id of the data source
*
*/
@ -132,7 +134,7 @@ public class InterestingHits implements AutopsyVisitableItem {
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (filteringDSObjId > 0) {
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
}
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
@ -217,17 +219,17 @@ public class InterestingHits implements AutopsyVisitableItem {
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
* different way of handling the closing of cases is worked out.
* Currently, remote events may be received for a case that is
* already closed.
*/
try {
Case.getCurrentCaseThrows();
/**
* Even with the check above, it is still possible that
* the case will be closed in a different thread before
* this code executes. If that happens, it is possible
* for the event to have a null oldValue.
* Even with the check above, it is still possible that the
* case will be closed in a different thread before this
* code executes. If that happens, it is possible for the
* event to have a null oldValue.
*/
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()
@ -243,9 +245,9 @@ public class InterestingHits implements AutopsyVisitableItem {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
* different way of handling the closing of cases is worked out.
* Currently, remote events may be received for a case that is
* already closed.
*/
try {
Case.getCurrentCaseThrows();
@ -266,8 +268,8 @@ public class InterestingHits implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
interestingResults.update();
interestingResults.addObserver(this);

View File

@ -62,7 +62,8 @@ import org.sleuthkit.datamodel.TskCoreException;
public class KeywordHits implements AutopsyVisitableItem {
private static final Logger logger = Logger.getLogger(KeywordHits.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
@NbBundle.Messages("KeywordHits.kwHits.text=Keyword Hits")
private static final String KEYWORD_HITS = KeywordHits_kwHits_text();
@NbBundle.Messages("KeywordHits.simpleLiteralSearch.text=Single Literal Keyword Search")
@ -160,14 +161,11 @@ public class KeywordHits implements AutopsyVisitableItem {
// doesn't know about Keyword Search NBM
if (o1.startsWith("Single Literal Keyword Search")) {
return -1;
}
else if (o2.startsWith("Single Literal Keyword Search")) {
} else if (o2.startsWith("Single Literal Keyword Search")) {
return 1;
}
else if (o1.startsWith("Single Regular Expression Search")) {
} else if (o1.startsWith("Single Regular Expression Search")) {
return -1;
}
else if (o2.startsWith("Single Regular Expression Search")) {
} else if (o2.startsWith("Single Regular Expression Search")) {
return 1;
}
return o1.compareTo(o2);
@ -501,8 +499,8 @@ public class KeywordHits implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
keywordResults.update();
super.addNotify();
@ -529,6 +527,7 @@ public class KeywordHits implements AutopsyVisitableItem {
}
private abstract class KWHitsNodeBase extends DisplayableItemNode implements Observer {
private String displayName;
private KWHitsNodeBase(Children children, Lookup lookup, String displayName) {

View File

@ -73,7 +73,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
this.setDisplayName(nameForLayoutFile(lf));
if (lf.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png"); //NON-NLS
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-x-icon-16.png"); //NON-NLS
} else if (lf.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE)) {
if (lf.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS

View File

@ -63,7 +63,7 @@ public class SlackFileNode extends AbstractFsContentNode<AbstractFile> {
// set name, display name, and icon
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png"); //NON-NLS
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-x-icon-16.png"); //NON-NLS
} else {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -54,9 +54,10 @@ public class Tags implements AutopsyVisitableItem {
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
// override of Children.Keys<T>.createNodes().
private final TagResults tagResults = new TagResults();
private final static String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text");
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS
private final TagResults tagResults = new TagResults();
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
@ -223,8 +224,7 @@ public class Tags implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
tagResults.update();
tagResults.addObserver(this);
@ -233,7 +233,6 @@ public class Tags implements AutopsyVisitableItem {
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
tagResults.deleteObserver(this);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -20,8 +20,6 @@ package org.sleuthkit.autopsy.datamodel;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
@ -119,7 +117,19 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode {
}
//Otherwise default to the AAFN createSheet method.
return super.createSheet();
Sheet defaultSheet = super.createSheet();
Sheet.Set defaultSheetSet = defaultSheet.get(Sheet.PROPERTIES);
//Pick out the location column
//This path should not show because VDs are not part of the data source
String locationCol = NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.locationColLbl");
for (Property<?> p : defaultSheetSet.getProperties()) {
if(locationCol.equals(p.getName())) {
defaultSheetSet.remove(p.getName());
}
}
return defaultSheet;
}
@Override

View File

@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.Action;
import org.apache.commons.lang3.tuple.Pair;
@ -52,6 +53,7 @@ import org.sleuthkit.datamodel.Tag;
public class VolumeNode extends AbstractContentNode<Volume> {
private static final Logger logger = Logger.getLogger(VolumeNode.class.getName());
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.CONTENT_CHANGED);
/**
* Helper so that the display name and the name used in building the path
@ -81,7 +83,7 @@ public class VolumeNode extends AbstractContentNode<Volume> {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/vol-icon.png"); //NON-NLS
// Listen for ingest events so that we can detect new added files (e.g. carved)
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
// Listen for case events so that we can detect when case is closed
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
}
@ -159,7 +161,7 @@ public class VolumeNode extends AbstractContentNode<Volume> {
NbBundle.getMessage(this.getClass(), "VolumeNode.getActions.viewInNewWin.text"), this));
actionsList.addAll(ExplorerNodeActionVisitor.getActions(content));
return actionsList.toArray(new Action[0]);
return actionsList.toArray(new Action[actionsList.size()]);
}
@Override

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -89,6 +89,8 @@ final public class Accounts implements AutopsyVisitableItem {
private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName());
private static final String ICON_BASE_PATH = "/org/sleuthkit/autopsy/images/"; //NON-NLS
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
@NbBundle.Messages("AccountsRootNode.name=Accounts")
final public static String NAME = Bundle.AccountsRootNode_name();
@ -98,7 +100,9 @@ final public class Accounts implements AutopsyVisitableItem {
private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus");
/* Should rejected accounts be shown in the accounts section of the tree. */
/*
* Should rejected accounts be shown in the accounts section of the tree.
*/
private boolean showRejected = false; //NOPMD redundant initializer
private final RejectAccounts rejectActionInstance;
@ -127,7 +131,6 @@ final public class Accounts implements AutopsyVisitableItem {
this.approveActionInstance = new ApproveAccounts();
}
@Override
public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this);
@ -190,6 +193,7 @@ final public class Accounts implements AutopsyVisitableItem {
* Create of keys used by this Children object to represent the child
* nodes.
*/
@Override
abstract protected boolean createKeys(List<X> list);
/**
@ -320,14 +324,14 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected boolean createKeys(List<String> list) {
String accountTypesInUseQuery =
"SELECT DISTINCT blackboard_attributes.value_text as account_type "
String accountTypesInUseQuery
= "SELECT DISTINCT blackboard_attributes.value_text as account_type "
+ " FROM blackboard_artifacts " //NON-NLS
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
+ getFilterByDataSourceClause();
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery );
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery);
ResultSet resultSet = executeQuery.getResultSet()) {
while (resultSet.next()) {
String accountType = resultSet.getString("account_type");
@ -368,8 +372,8 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.addNotify();
refresh(true);
@ -439,8 +443,8 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.addNotify();
}
@ -455,8 +459,8 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected boolean createKeys(List<Long> list) {
String query =
"SELECT blackboard_artifacts.artifact_id " //NON-NLS
String query
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
+ " FROM blackboard_artifacts " //NON-NLS
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
@ -603,8 +607,8 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.addNotify();
}
@ -727,8 +731,8 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.addNotify();
}
@ -755,8 +759,8 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected boolean createKeys(List<FileWithCCN> list) {
String query =
"SELECT blackboard_artifacts.obj_id," //NON-NLS
String query
= "SELECT blackboard_artifacts.obj_id," //NON-NLS
+ " solr_attribute.value_text AS solr_document_id, "; //NON-NLS
if (skCase.getDatabaseType().equals(DbType.POSTGRESQL)) {
query += " string_agg(blackboard_artifacts.artifact_id::character varying, ',') AS artifact_IDs, " //NON-NLS
@ -833,8 +837,8 @@ final public class Accounts implements AutopsyVisitableItem {
"# {0} - number of children",
"Accounts.ByFileNode.displayName=By File ({0})"})
private void updateDisplayName() {
String query =
"SELECT count(*) FROM ( SELECT count(*) AS documents "
String query
= "SELECT count(*) FROM ( SELECT count(*) AS documents "
+ " FROM blackboard_artifacts " //NON-NLS
+ " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS
+ " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS
@ -941,8 +945,8 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.addNotify();
}
@ -972,8 +976,8 @@ final public class Accounts implements AutopsyVisitableItem {
RangeMap<Integer, BinResult> binRanges = TreeRangeMap.create();
String query =
"SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS
String query
= "SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS
+ " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS
+ " FROM blackboard_artifacts " //NON-NLS
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
@ -1040,8 +1044,8 @@ final public class Accounts implements AutopsyVisitableItem {
"# {0} - number of children",
"Accounts.ByBINNode.displayName=By BIN ({0})"})
private void updateDisplayName() {
String query =
"SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS
String query
= "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS
+ " FROM blackboard_artifacts " //NON-NLS
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
@ -1171,7 +1175,7 @@ final public class Accounts implements AutopsyVisitableItem {
* @return the artifact ids of the account artifacts from this file.
*/
public List<Long> getArtifactIDs() {
return artifactIDs;
return Collections.unmodifiableList(artifactIDs);
}
/**
@ -1189,7 +1193,7 @@ final public class Accounts implements AutopsyVisitableItem {
* @return the status(s) of the account artifacts from this file.
*/
public Set<BlackboardArtifact.ReviewStatus> getStatuses() {
return statuses;
return Collections.unmodifiableSet(statuses);
}
}
@ -1335,8 +1339,8 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected boolean createKeys(List<Long> list) {
String query =
"SELECT blackboard_artifacts.artifact_id " //NON-NLS
String query
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
+ " FROM blackboard_artifacts " //NON-NLS
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
@ -1383,7 +1387,9 @@ final public class Accounts implements AutopsyVisitableItem {
final public class BINNode extends DisplayableItemNode {
/** Creates the nodes for the credit card numbers */
/**
* Creates the nodes for the credit card numbers
*/
private final BinResult bin;
private BINNode(BinResult bin) {
@ -1407,8 +1413,8 @@ final public class Accounts implements AutopsyVisitableItem {
}
private void updateDisplayName() {
String query =
"SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS
String query
= "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS
+ " FROM blackboard_artifacts " //NON-NLS
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
@ -1549,7 +1555,9 @@ final public class Accounts implements AutopsyVisitableItem {
return true;
}
/** The number of accounts with this BIN */
/**
* The number of accounts with this BIN
*/
private final long count;
private final BINRange binRange;
@ -1726,8 +1734,10 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
public void actionPerformed(ActionEvent e) {
/* get paths for selected nodes to reselect after applying review
* status change */
/*
* get paths for selected nodes to reselect after applying review
* status change
*/
List<String[]> selectedPaths = Utilities.actionsGlobalContext().lookupAll(Node.class).stream()
.map(node -> {
String[] createPath;
@ -1746,9 +1756,11 @@ final public class Accounts implements AutopsyVisitableItem {
: siblings.get(Integer.max(indexOf + 1, siblings.size() - 1));
createPath = NodeOp.createPath(sibling, null);
} else {
/* if there are no other siblings to select,
/*
* if there are no other siblings to select,
* just return null, but note we need to filter
* this out of stream below */
* this out of stream below
*/
return null;
}
} else {

View File

@ -0,0 +1,209 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2019 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.datamodel.utils;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SpecialDirectory;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Utility class for adding local files with specified paths in the data source.
* It is currently assumed that the data source is empty to start or that at
* least the paths to the files being added do not exist; no checks will be done
* to see if folders exist prior to creating them through addLocalFile().
*/
public class LocalFileImporter {
private static final Logger logger = Logger.getLogger(LocalFileImporter.class.getName());
SleuthkitCase.CaseDbTransaction globalTrans = null;
boolean useSingleTransaction = true;
SleuthkitCase sleuthkitCase;
private final Map<String, SpecialDirectory> localFileDirMap = new HashMap<>();
/**
* Create a LocalFileImporter.
*
* @param sleuthkitCase The current SleuthkitCase
*/
public LocalFileImporter(SleuthkitCase sleuthkitCase) {
this.sleuthkitCase = sleuthkitCase;
this.useSingleTransaction = false;
}
/**
* Create a LocalFileImporter. The caller is responsible for committing
* or rolling back the transaction.
*
* @param sleuthkitCase The current SleuthkitCase
* @param trans The open CaseDbTransaction
*/
public LocalFileImporter(SleuthkitCase sleuthkitCase, SleuthkitCase.CaseDbTransaction trans) {
this.sleuthkitCase = sleuthkitCase;
this.globalTrans = trans;
this.useSingleTransaction = true;
}
/**
* Add a local file to the database with the specified parameters. Will create
* any necessary parent folders.
*
* Will not fail if the fileOnDisk does not exist.
*
* @param fileOnDisk The local file on disk
* @param name The name to use in the data source
* @param parentPath The path to use in the data source
* @param ctime Change time
* @param crtime Created time
* @param atime Access time
* @param mtime Modified time
* @param dataSource The data source to add the file to
*
* @return The AbstractFile that was just created
*
* @throws TskCoreException
*/
public AbstractFile addLocalFile(File fileOnDisk, String name, String parentPath,
Long ctime, Long crtime, Long atime, Long mtime,
DataSource dataSource) throws TskCoreException {
// Get the parent folder, creating it and any of its parent folders if necessary
SpecialDirectory parentDir = getOrMakeDirInDataSource(new File(parentPath), dataSource);
SleuthkitCase.CaseDbTransaction trans = null;
try {
if (useSingleTransaction) {
trans = globalTrans;
} else {
trans = sleuthkitCase.beginTransaction();
}
// Try to get the file size
long size = 0;
if (fileOnDisk.exists()) {
size = fileOnDisk.length();
}
// Create the new file
AbstractFile file = sleuthkitCase.addLocalFile(name, fileOnDisk.getAbsolutePath(), size,
ctime, crtime, atime, mtime,
true, TskData.EncodingType.NONE, parentDir, trans);
if (! useSingleTransaction) {
trans.commit();
}
return file;
} catch (TskCoreException ex) {
if ((!useSingleTransaction) && (null != trans)) {
try {
trans.rollback();
} catch (TskCoreException ex2) {
logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
}
}
throw ex;
}
}
/**
* Returns the SpecialDirectory object corresponding to the given directory, creating
* it and its parents as needed.
*
* @param directory The file to get the SpecialDirectory for
* @param dataSource The data source
*
* @return The SpecialDirectory object corresponding to the given file
*
* @throws TskCoreException
*/
private SpecialDirectory getOrMakeDirInDataSource(File directory, Content dataSource) throws TskCoreException {
if ((directory == null) || directory.getPath().isEmpty()) {
throw new TskCoreException("Can not create directory from null path");
}
// Check if we've already created it
if (localFileDirMap.containsKey(directory.toString())) {
return localFileDirMap.get(directory.toString());
}
File parent = directory.getParentFile();
if (parent == null) {
// This is the root of the path and it isn't in the map, so create it
SpecialDirectory dir = createLocalFilesDir(dataSource.getId(), directory.getName());
localFileDirMap.put(directory.getName(), dir);
return dir;
} else {
// Create everything above this in the tree, and then add the parent folder
SpecialDirectory parentDir = getOrMakeDirInDataSource(parent, dataSource);
SpecialDirectory dir = createLocalFilesDir(parentDir.getId(), directory.getName());
localFileDirMap.put(directory.getPath(), dir);
return dir;
}
}
/**
* Create a new LocalDirectory
*
* @param parentId The object ID for parent
* @param name The name of the new local directory
*
* @return The new LocalDirectory
*
* @throws TskCoreException
*/
private SpecialDirectory createLocalFilesDir(long parentId, String name) throws TskCoreException {
SleuthkitCase.CaseDbTransaction trans = null;
try {
if (useSingleTransaction) {
trans = globalTrans;
} else {
trans = sleuthkitCase.beginTransaction();
}
SpecialDirectory dir;
dir = sleuthkitCase.addLocalDirectory(parentId, name, trans);
if (! useSingleTransaction) {
trans.commit();
}
return dir;
} catch (TskCoreException ex) {
if (( !useSingleTransaction) && (null != trans)) {
try {
trans.rollback();
} catch (TskCoreException ex2) {
logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
}
}
throw ex;
}
}
}

View File

@ -179,9 +179,7 @@ public class DataResultFilterNode extends FilterNode {
newPs.setShortDescription(ps.getShortDescription());
newPs.put(ps.getProperties());
if (newPs.remove(AbstractFsContentNode.HIDE_PARENT) != null) {
newPs.remove(AbstractFilePropertyType.LOCATION.toString());
}
newPs.remove(AbstractFsContentNode.HIDE_PARENT);
propertySets[i] = newPs;
}
}

View File

@ -85,7 +85,6 @@ import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
import org.sleuthkit.autopsy.datamodel.accounts.BINRange;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -128,7 +127,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
getTree().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
//Hook into the JTree and pre-expand the Views Node and Results node when a user
//expands an item in the tree that makes these nodes visible.
((ExpansionBeanTreeView )getTree()).addTreeExpansionListener(new TreeExpansionListener() {
((ExpansionBeanTreeView) getTree()).addTreeExpansionListener(new TreeExpansionListener() {
@Override
public void treeExpanded(TreeExpansionEvent event) {
//Bail immediately if we are not in the Group By view.
@ -238,8 +237,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE, Case.Events.DATA_SOURCE_ADDED), this);
this.em.addPropertyChangeListener(this);
IngestManager.getInstance().addIngestJobEventListener(this);
IngestManager.getInstance().addIngestModuleEventListener(this);
}
public void setDirectoryListingActive() {
@ -799,9 +796,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
} // change in node selection
else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
respondSelection((Node[]) event.getOldValue(), (Node[]) event.getNewValue());
} else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
// nothing to do here.
// all nodes should be listening for these events and update accordingly.
}
}
}

View File

@ -296,6 +296,7 @@
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="instancesListModel" type="code"/>
</Property>
<Property name="selectionMode" type="int" value="0"/>
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new InstancesCellRenderer()" type="code"/>
</Property>

View File

@ -427,6 +427,7 @@ public class ResultsPanel extends javax.swing.JPanel {
instancesList.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ResultsPanel.class, "ResultsPanel.instancesList.border.title"))); // NOI18N
instancesList.setModel(instancesListModel);
instancesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
instancesList.setCellRenderer(new InstancesCellRenderer());
instancesScrollPane.setViewportView(instancesList);

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.imagewriter;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@ -44,15 +46,16 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* The ImageWriter class is used to complete VHD copies created from local disks
* after the ingest process completes. The AddImageTask for this data source must have included
* a non-empty imageWriterPath parameter to enable Image Writer.
* after the ingest process completes. The AddImageTask for this data source
* must have included a non-empty imageWriterPath parameter to enable Image
* Writer.
*
* Most of the cancellation/cleanup is handled through ImageWriterService
*/
class ImageWriter implements PropertyChangeListener{
private final Logger logger = Logger.getLogger(ImageWriter.class.getName());
class ImageWriter implements PropertyChangeListener {
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
private static final Logger logger = Logger.getLogger(ImageWriter.class.getName());
private final Long dataSourceId;
private final ImageWriterSettings settings;
@ -63,18 +66,19 @@ class ImageWriter implements PropertyChangeListener{
private boolean isCancelled = false;
private boolean isStarted = false;
private final Object currentTasksLock = new Object(); // Get this lock before accessing imageHandle, finishTask, progressHandle, progressUpdateTask,
// isCancelled, isStarted, or isFinished
// isCancelled, isStarted, or isFinished
private ScheduledThreadPoolExecutor periodicTasksExecutor = null;
private final boolean doUI;
private SleuthkitCase caseDb = null;
/**
* Create the Image Writer object.
* After creation, startListeners() should be called.
* Create the Image Writer object. After creation, startListeners() should
* be called.
*
* @param dataSourceId
*/
ImageWriter(Long dataSourceId, ImageWriterSettings settings){
ImageWriter(Long dataSourceId, ImageWriterSettings settings) {
this.dataSourceId = dataSourceId;
this.settings = settings;
doUI = RuntimeProperties.runningWithGUI();
@ -82,9 +86,9 @@ class ImageWriter implements PropertyChangeListener{
// We save the reference to the sleuthkit case here in case getOpenCase() is set to
// null before Image Writer finishes. The user can still elect to wait for image writer
// (in ImageWriterService.closeCaseResources) even though the case is closing.
try{
try {
caseDb = Case.getCurrentCaseThrows().getSleuthkitCase();
} catch (NoCurrentCaseException ex){
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Unable to load case. Image writer will be cancelled.");
this.isCancelled = true;
}
@ -93,33 +97,34 @@ class ImageWriter implements PropertyChangeListener{
/**
* Add this ImageWriter object as a listener to the necessary events
*/
void subscribeToEvents(){
IngestManager.getInstance().addIngestJobEventListener(this);
void subscribeToEvents() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, this);
}
/**
* Deregister this object from the events. This is ok to call multiple times.
* Deregister this object from the events. This is ok to call multiple
* times.
*/
void unsubscribeFromEvents(){
void unsubscribeFromEvents() {
IngestManager.getInstance().removeIngestJobEventListener(this);
}
/**
* Handle the events:
* DATA_SOURCE_ANALYSIS_COMPLETED - start the finish image process and clean up after it is complete
* Handle the events: DATA_SOURCE_ANALYSIS_COMPLETED - start the finish
* image process and clean up after it is complete
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
if(evt instanceof DataSourceAnalysisCompletedEvent){
if (evt instanceof DataSourceAnalysisCompletedEvent) {
DataSourceAnalysisCompletedEvent event = (DataSourceAnalysisCompletedEvent)evt;
DataSourceAnalysisCompletedEvent event = (DataSourceAnalysisCompletedEvent) evt;
if(event.getDataSource() != null){
if (event.getDataSource() != null) {
long imageId = event.getDataSource().getId();
String name = event.getDataSource().getName();
// Check that the event corresponds to this datasource
if(imageId != dataSourceId){
if (imageId != dataSourceId) {
return;
}
new Thread(() -> {
@ -136,25 +141,25 @@ class ImageWriter implements PropertyChangeListener{
"# {0} - data source name",
"ImageWriter.progressBar.message=Finishing acquisition of {0} (unplug device to cancel)"
})
private void startFinishImage(String dataSourceName){
private void startFinishImage(String dataSourceName) {
synchronized(currentTasksLock){
if(isCancelled){
synchronized (currentTasksLock) {
if (isCancelled) {
return;
}
// If we've already started the finish process for this datasource, return.
// Multiple DataSourceAnalysisCompletedEvent events can come from
// the same image if more ingest modules are run later
if(isStarted){
if (isStarted) {
return;
}
Image image;
try{
try {
image = Case.getCurrentCaseThrows().getSleuthkitCase().getImageById(dataSourceId);
imageHandle = image.getImageHandle();
} catch (NoCurrentCaseException ex){
} catch (NoCurrentCaseException ex) {
// This exception means that getOpenCase() failed because no case was open.
// This can happen when the user closes the case while ingest is ongoing - canceling
// ingest fires off the DataSourceAnalysisCompletedEvent while the case is in the
@ -162,7 +167,7 @@ class ImageWriter implements PropertyChangeListener{
logger.log(Level.WARNING, String.format("Case closed before ImageWriter could start the finishing process for %s",
dataSourceName));
return;
} catch (TskCoreException ex){
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading image", ex);
return;
}
@ -170,7 +175,7 @@ class ImageWriter implements PropertyChangeListener{
logger.log(Level.INFO, String.format("Finishing VHD image for %s",
dataSourceName)); //NON-NLS
if(doUI){
if (doUI) {
periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("image-writer-progress-update-%d").build()); //NON-NLS
progressHandle = ProgressHandle.createHandle(Bundle.ImageWriter_progressBar_message(dataSourceName));
progressHandle.start(100);
@ -181,20 +186,20 @@ class ImageWriter implements PropertyChangeListener{
// The added complexity here with the Future is because we absolutely need to make sure
// the call to finishImageWriter returns before allowing the TSK data structures to be freed
// during case close.
finishTask = Executors.newSingleThreadExecutor().submit(new Callable<Integer>(){
finishTask = Executors.newSingleThreadExecutor().submit(new Callable<Integer>() {
@Override
public Integer call() throws TskCoreException{
try{
public Integer call() throws TskCoreException {
try {
int result = SleuthkitJNI.finishImageWriter(imageHandle);
// We've decided to always update the path to the VHD, even if it wasn't finished.
// This supports the case where an analyst has partially ingested a device
// but has to stop before completion. They will at least have part of the image.
if(settings.getUpdateDatabasePath()){
if (settings.getUpdateDatabasePath()) {
caseDb.updateImagePath(settings.getPath(), dataSourceId);
}
return result;
} catch (TskCoreException ex){
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
return -1;
}
@ -207,15 +212,15 @@ class ImageWriter implements PropertyChangeListener{
// Wait for finishImageWriter to complete
int result = 0;
try{
try {
// The call to get() can happen multiple times if the user closes the case, which is ok
result = finishTask.get();
} catch (InterruptedException | ExecutionException ex){
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
}
synchronized(currentTasksLock){
if(doUI){
synchronized (currentTasksLock) {
if (doUI) {
// Some of these may be called twice if the user closes the case
progressUpdateTask.cancel(true);
progressHandle.finish();
@ -223,7 +228,7 @@ class ImageWriter implements PropertyChangeListener{
}
}
if(result == 0){
if (result == 0) {
logger.log(Level.INFO, String.format("Successfully finished writing VHD image for %s", dataSourceName)); //NON-NLS
} else {
logger.log(Level.INFO, String.format("Finished VHD image for %s with errors", dataSourceName)); //NON-NLS
@ -231,14 +236,13 @@ class ImageWriter implements PropertyChangeListener{
}
/**
* If a task hasn't been started yet, set the cancel flag so it can no longer
* start.
* This is intended to be used in case close so a job doesn't suddenly start
* up during cleanup.
* If a task hasn't been started yet, set the cancel flag so it can no
* longer start. This is intended to be used in case close so a job doesn't
* suddenly start up during cleanup.
*/
void cancelIfNotStarted(){
synchronized(currentTasksLock){
if(! isStarted){
void cancelIfNotStarted() {
synchronized (currentTasksLock) {
if (!isStarted) {
isCancelled = true;
}
}
@ -246,25 +250,26 @@ class ImageWriter implements PropertyChangeListener{
/**
* Check if the finishTask process is running.
* @return true if the finish task is still going on, false if it is finished or
* never started
*
* @return true if the finish task is still going on, false if it is
* finished or never started
*/
boolean jobIsInProgress(){
synchronized(currentTasksLock){
return((isStarted) && (! finishTask.isDone()));
boolean jobIsInProgress() {
synchronized (currentTasksLock) {
return ((isStarted) && (!finishTask.isDone()));
}
}
/**
* Cancels a single job.
* Does not wait for the job to complete. Safe to call with Image Writer in any state.
* Cancels a single job. Does not wait for the job to complete. Safe to call
* with Image Writer in any state.
*/
void cancelJob(){
synchronized(currentTasksLock){
void cancelJob() {
synchronized (currentTasksLock) {
// All of the following is redundant but safe to call on a complete job
isCancelled = true;
if(isStarted){
if (isStarted) {
SleuthkitJNI.cancelFinishImage(imageHandle);
// Stop the progress bar update task.
@ -273,7 +278,7 @@ class ImageWriter implements PropertyChangeListener{
// when that happens.
// Since we've stopped the update task, we'll stop the associated progress
// bar now, too.
if(doUI){
if (doUI) {
progressUpdateTask.cancel(true);
progressHandle.finish();
}
@ -282,19 +287,19 @@ class ImageWriter implements PropertyChangeListener{
}
/**
* Blocks while all finishImage tasks complete.
* Also makes sure the progressUpdateTask is canceled.
* Blocks while all finishImage tasks complete. Also makes sure the
* progressUpdateTask is canceled.
*/
void waitForJobToFinish(){
synchronized(currentTasksLock){
void waitForJobToFinish() {
synchronized (currentTasksLock) {
// Wait for the finish task to end
if(isStarted){
try{
if (isStarted) {
try {
finishTask.get();
} catch (InterruptedException | ExecutionException ex){
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(ImageWriter.class.getName()).log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
}
if(doUI){
if (doUI) {
progressUpdateTask.cancel(true);
}
}
@ -305,10 +310,11 @@ class ImageWriter implements PropertyChangeListener{
* Task to query the Sleuthkit processing to get the percentage done.
*/
private final class ProgressUpdateTask implements Runnable {
final long imageHandle;
final ProgressHandle progressHandle;
ProgressUpdateTask(ProgressHandle progressHandle, long imageHandle){
ProgressUpdateTask(ProgressHandle progressHandle, long imageHandle) {
this.imageHandle = imageHandle;
this.progressHandle = progressHandle;
}

View File

@ -105,7 +105,7 @@ EditNonFullPathsRulePanel.minSizeCheckbox.text=Minimum size:
NewRulePanel.chooseLabel.text=Choose the type of rule
ConfigVisualPanel1.configureDriveRadioButton.text_1=Configure selected external drive:
ConfigVisualPanel1.configureFolderRadioButton.text_1=Configure in a folder:
ConfigVisualPanel1.descriptionTextArea.text=Select a location for the Logical Imager. This location will contain the imaging program and a configuration file. If that location already contains a configuration file, it will be loaded to edit. Imaging results will be saved to this location, so ensure it has enough free space.
ConfigVisualPanel1.descriptionTextArea.text=Select a location for the Logical Imager. This location will contain the imaging program and a configuration file. If that location already contains a configuration file, it will be loaded to edit. Imaging results will be saved to this location, so ensure it has enough free space. Drives with FAT format are not supported.
ConfigVisualPanel1.refreshButton.text=Refresh
ConfigVisualPanel3.saveButton.text=Save
ConfigVisualPanel3.configLabel.text=Logical Imager config file save status:
@ -122,3 +122,4 @@ EditNonFullPathsRulePanel.fileNamesInfoLabel.text=File names are case insensitiv
EditNonFullPathsRulePanel.extensionsInfoLabel.text=Extensions are case insensitive.
ConfigVisualPanel2.promptBeforeExit.text=Prompt before exiting imager
ConfigVisualPanel2.promptBeforeExit.actionCommand=
ConfigVisualPanel2.createVHDCheckBox.text=Create VHD

View File

@ -26,10 +26,16 @@ ConfigVisualPanel1.chooseFileTitle=Select a Logical Imager configuration
# {0} - filename
ConfigVisualPanel1.configFileIsEmpty=Configuration file {0} is empty
ConfigVisualPanel1.configurationError=Configuration error
# {0} - root
# {1} - description
# {2} - size with unit
# {3} - file system
ConfigVisualPanel1.driveListItem={0} ({1}) ({2}) - File system: {3}
ConfigVisualPanel1.fileNameExtensionFilter=Configuration JSON File
ConfigVisualPanel1.invalidConfigJson=Invalid config JSON:
ConfigVisualPanel1.messageLabel.noExternalDriveFound=No drive found
ConfigVisualPanel1.selectConfigurationFile=Select location
ConfigVisualPanel1.unknown=Unknown
ConfigVisualPanel2.cancel=Cancel
ConfigVisualPanel2.deleteRuleSet=Delete rule
ConfigVisualPanel2.deleteRuleSetConfirmation=Delete rule confirmation
@ -174,7 +180,7 @@ LogicalImagerConfigDeserializer.unsupportedKeyException=Unsupported key: {0}
NewRulePanel.chooseLabel.text=Choose the type of rule
ConfigVisualPanel1.configureDriveRadioButton.text_1=Configure selected external drive:
ConfigVisualPanel1.configureFolderRadioButton.text_1=Configure in a folder:
ConfigVisualPanel1.descriptionTextArea.text=Select a location for the Logical Imager. This location will contain the imaging program and a configuration file. If that location already contains a configuration file, it will be loaded to edit. Imaging results will be saved to this location, so ensure it has enough free space.
ConfigVisualPanel1.descriptionTextArea.text=Select a location for the Logical Imager. This location will contain the imaging program and a configuration file. If that location already contains a configuration file, it will be loaded to edit. Imaging results will be saved to this location, so ensure it has enough free space. Drives with FAT format are not supported.
ConfigVisualPanel1.refreshButton.text=Refresh
ConfigVisualPanel3.saveButton.text=Save
ConfigVisualPanel3.configLabel.text=Logical Imager config file save status:
@ -191,6 +197,7 @@ EditNonFullPathsRulePanel.fileNamesInfoLabel.text=File names are case insensitiv
EditNonFullPathsRulePanel.extensionsInfoLabel.text=Extensions are case insensitive.
ConfigVisualPanel2.promptBeforeExit.text=Prompt before exiting imager
ConfigVisualPanel2.promptBeforeExit.actionCommand=
ConfigVisualPanel2.createVHDCheckBox.text=Create VHD
NewRuleSetPanel.attributeRule.description=Search for files based on one or more attributes or metadata fields.
NewRuleSetPanel.attributeRule.name=Attribute
NewRuleSetPanel.fullPathRule.description=Search for files based on full exact match path.

View File

@ -29,7 +29,11 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
@ -241,10 +245,31 @@ final class ConfigVisualPanel1 extends JPanel {
firePropertyChange(UPDATE_UI_EVENT_NAME, false, true); // NON-NLS
}//GEN-LAST:event_driveListMouseReleasedSelection
/*
* Return the Windows file system name of the drive
* @param drive File system drive, should be of the form "C:\"
*
*/
@Messages({"ConfigVisualPanel1.unknown=Unknown"})
private String getFileSystemName(String drive) {
FileSystem fileSystem = FileSystems.getDefault();
FileSystemProvider provider = fileSystem.provider();
try {
FileStore fileStore = provider.getFileStore(Paths.get(drive));
return fileStore.type();
} catch (IOException ex) {
return Bundle.ConfigVisualPanel1_unknown();
}
}
/**
* Refresh the list of local drives on the current machine
*/
@Messages({"ConfigVisualPanel1.messageLabel.noExternalDriveFound=No drive found"})
@NbBundle.Messages({
"ConfigVisualPanel1.messageLabel.noExternalDriveFound=No drive found",
"# {0} - root", "# {1} - description", "# {2} - size with unit", "# {3} - file system",
"ConfigVisualPanel1.driveListItem={0} ({1}) ({2}) - File system: {3}"
})
private void refreshDriveList() {
List<String> listData = new ArrayList<>();
File[] roots = File.listRoots();
@ -257,7 +282,8 @@ final class ConfigVisualPanel1 extends JPanel {
String description = FileSystemView.getFileSystemView().getSystemTypeDescription(root);
long spaceInBytes = root.getTotalSpace();
String sizeWithUnit = DriveListUtils.humanReadableByteCount(spaceInBytes, false);
listData.add(root + " (" + description + ") (" + sizeWithUnit + ")");
String fileSystem = getFileSystemName(root.toString());
listData.add(Bundle.ConfigVisualPanel1_driveListItem(root, description, sizeWithUnit, fileSystem));
if (firstRemovableDrive == -1) {
try {
FileStore fileStore = Files.getFileStore(root.toPath());
@ -266,7 +292,7 @@ final class ConfigVisualPanel1 extends JPanel {
}
} catch (IOException ignored) {
//unable to get this removable drive for default selection will try and select next removable drive by default
logger.log(Level.INFO, "Unable to select first removable drive found", ignored);
logger.log(Level.INFO, String.format("Unable to select first removable drive found %s", root.toString())); // NON-NLS
}
}
i++;
@ -431,8 +457,7 @@ final class ConfigVisualPanel1 extends JPanel {
return UPDATE_UI_EVENT_NAME;
}
void setConfigFilename(String filename
) {
void setConfigFilename(String filename) {
configFileTextField.setText(filename);
}
@ -442,9 +467,11 @@ final class ConfigVisualPanel1 extends JPanel {
* @return true if panel has valid settings selected, false otherwise
*/
boolean isPanelValid() {
return !StringUtils.isBlank(getConfigPath()) && ((configureDriveRadioButton.isSelected() && !StringUtils.isBlank(driveList.getSelectedValue()))
|| (configureFolderRadioButton.isSelected() && (!configFileTextField.getText().isEmpty())));
return !StringUtils.isBlank(getConfigPath())
&& !(getFileSystemName(getConfigPath().substring(0, 3)).equals("FAT") // NON-NLS
|| getFileSystemName(getConfigPath().substring(0, 3)).equals("FAT32")) // NON-NLS
&& ((configureDriveRadioButton.isSelected() && !StringUtils.isBlank(driveList.getSelectedValue()))
|| (configureFolderRadioButton.isSelected() && (!configFileTextField.getText().isEmpty())));
}
/**

View File

@ -103,6 +103,7 @@
<Component id="flagEncryptionProgramsCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="finalizeImageWriter" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="promptBeforeExit" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="createVHDCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
@ -193,7 +194,8 @@
<Component id="finalizeImageWriter" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="promptBeforeExit" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="createVHDCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
@ -582,5 +584,15 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="promptBeforeExitActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="createVHDCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/logicalimager/configuration/Bundle.properties" key="ConfigVisualPanel2.createVHDCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="createVHDCheckBoxActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -111,6 +111,7 @@ final class ConfigVisualPanel2 extends JPanel {
maxSizeLabel = new javax.swing.JLabel();
maxSizeTextField = new javax.swing.JFormattedTextField();
promptBeforeExit = new javax.swing.JCheckBox();
createVHDCheckBox = new javax.swing.JCheckBox();
org.openide.awt.Mnemonics.setLocalizedText(modifiedDateLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.modifiedDateLabel.text")); // NOI18N
@ -264,6 +265,13 @@ final class ConfigVisualPanel2 extends JPanel {
}
});
org.openide.awt.Mnemonics.setLocalizedText(createVHDCheckBox, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.createVHDCheckBox.text")); // NOI18N
createVHDCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
createVHDCheckBoxActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -338,7 +346,8 @@ final class ConfigVisualPanel2 extends JPanel {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(flagEncryptionProgramsCheckBox)
.addComponent(finalizeImageWriter)
.addComponent(promptBeforeExit))
.addComponent(promptBeforeExit)
.addComponent(createVHDCheckBox))
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(jSeparator1)))))
);
@ -412,7 +421,8 @@ final class ConfigVisualPanel2 extends JPanel {
.addComponent(finalizeImageWriter)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(promptBeforeExit)
.addGap(21, 21, 21))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(createVHDCheckBox))))
);
}// </editor-fold>//GEN-END:initComponents
@ -546,6 +556,10 @@ final class ConfigVisualPanel2 extends JPanel {
config.setPromptBeforeExit(promptBeforeExit.isSelected());
}//GEN-LAST:event_promptBeforeExitActionPerformed
private void createVHDCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createVHDCheckBoxActionPerformed
config.setCreateVHD(createVHDCheckBox.isSelected());
}//GEN-LAST:event_createVHDCheckBoxActionPerformed
/**
* Set the whether the a rule for detecting encryption programs will be
* added to the rules in this config
@ -588,6 +602,7 @@ final class ConfigVisualPanel2 extends JPanel {
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextField configFileTextField;
private javax.swing.JCheckBox createVHDCheckBox;
private javax.swing.JLabel daysIncludedLabel;
private javax.swing.JButton deleteRuleButton;
private javax.swing.JTextField descriptionEditTextField;
@ -638,13 +653,14 @@ final class ConfigVisualPanel2 extends JPanel {
* Update the panel to reflect the rules in the current config
*
* @param configFilePath path of the config file being modified
* @param config contents of the config file being modifed
* @param config contents of the config file being modified
* @param rowSelectionkey the name of the rule to select by default
*/
private void updatePanel(String configFilePath, LogicalImagerConfig config, String rowSelectionkey) {
configFileTextField.setText(configFilePath);
finalizeImageWriter.setSelected(config.isFinalizeImageWriter());
promptBeforeExit.setSelected(config.isPromptBeforeExit());
createVHDCheckBox.setSelected(config.isCreateVHD());
LogicalImagerRuleSet ruleSet = getRuleSetFromCurrentConfig();
flagEncryptionProgramsCheckBox.setSelected(ruleSet.find(EncryptionProgramsRule.getName()) != null);
RulesTableModel rulesTableModel = new RulesTableModel();

View File

@ -42,6 +42,10 @@ class LogicalImagerConfig {
@Expose(serialize = true)
private boolean promptBeforeExit;
@SerializedName("create-VHD")
@Expose(serialize = true)
private boolean createVHD;
@SerializedName("rule-sets")
@Expose(serialize = true)
private List<LogicalImagerRuleSet> ruleSets;
@ -50,6 +54,7 @@ class LogicalImagerConfig {
this.version = CURRENT_VERSION;
this.finalizeImageWriter = false;
this.promptBeforeExit = true;
this.createVHD = false;
this.ruleSets = new ArrayList<>();
}
@ -60,6 +65,7 @@ class LogicalImagerConfig {
this.version = CURRENT_VERSION;
this.finalizeImageWriter = finalizeImageWriter;
this.promptBeforeExit = true;
this.createVHD = false;
this.ruleSets = ruleSets;
}
@ -71,6 +77,7 @@ class LogicalImagerConfig {
this.version = version;
this.finalizeImageWriter = finalizeImageWriter;
this.promptBeforeExit = true;
this.createVHD = false;
this.ruleSets = ruleSets;
}
@ -78,11 +85,13 @@ class LogicalImagerConfig {
String version,
boolean finalizeImageWriter,
boolean promptBeforeExit,
boolean createVHD,
List<LogicalImagerRuleSet> ruleSets
) {
this.version = version;
this.finalizeImageWriter = finalizeImageWriter;
this.promptBeforeExit = promptBeforeExit;
this.createVHD = createVHD;
this.ruleSets = ruleSets;
}
@ -114,6 +123,14 @@ class LogicalImagerConfig {
this.promptBeforeExit = promptBeforeExit;
}
boolean isCreateVHD() {
return createVHD;
}
void setCreateVHD(boolean createVHD) {
this.createVHD = createVHD;
}
List<LogicalImagerRuleSet> getRuleSets() {
return ruleSets;
}

View File

@ -46,6 +46,7 @@ class LogicalImagerConfigDeserializer implements JsonDeserializer<LogicalImagerC
String version = LogicalImagerConfig.getCurrentVersion();
boolean finalizeImageWriter = false;
boolean promptBeforeExit = true;
boolean createVHD = false;
final JsonObject jsonObject = je.getAsJsonObject();
final JsonElement jsonVersion = jsonObject.get("version"); // NON-NLS
@ -63,6 +64,11 @@ class LogicalImagerConfigDeserializer implements JsonDeserializer<LogicalImagerC
promptBeforeExit = jsonPromptBeforeExit.getAsBoolean();
}
final JsonElement jsonCreateVHD = jsonObject.get("create-VHD"); // NON-NLS
if (jsonCreateVHD != null) {
createVHD = jsonCreateVHD.getAsBoolean();
}
JsonArray asJsonArray = jsonObject.get("rule-sets").getAsJsonArray(); // NON-NLS
if (asJsonArray == null) {
throw new JsonParseException(Bundle.LogicalImagerConfigDeserializer_missingRuleSetException());
@ -80,7 +86,7 @@ class LogicalImagerConfigDeserializer implements JsonDeserializer<LogicalImagerC
LogicalImagerRuleSet ruleSet = new LogicalImagerRuleSet(setName, rules);
ruleSets.add(ruleSet);
}
return new LogicalImagerConfig(version, finalizeImageWriter, promptBeforeExit, ruleSets);
return new LogicalImagerConfig(version, finalizeImageWriter, promptBeforeExit, createVHD, ruleSets);
}
private List<LogicalImagerRule> parseRules(JsonArray asJsonArray) {

View File

@ -23,6 +23,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@ -31,19 +32,22 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.annotation.concurrent.GuardedBy;
import org.apache.commons.io.FileUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.datamodel.utils.LocalFileImporter;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
@ -51,12 +55,16 @@ import org.sleuthkit.datamodel.TskCoreException;
* SearchResults.txt and users.txt files to report - add an image data source to the
* case database.
*/
final class AddLogicalImageTask extends AddMultipleImageTask {
final class AddLogicalImageTask implements Runnable {
private final static Logger LOGGER = Logger.getLogger(AddLogicalImageTask.class.getName());
private final static String SEARCH_RESULTS_TXT = "SearchResults.txt"; //NON-NLS
private final static String USERS_TXT = "users.txt"; //NON-NLS
private final static String MODULE_NAME = "Logical Imager"; //NON-NLS
private final static String ROOT_STR = "root"; // NON-NLS
private final static String VHD_EXTENSION = ".vhd"; // NON-NLS
private final String deviceId;
private final String timeZone;
private final File src;
private final File dest;
private final DataSourceProcessorCallback callback;
@ -64,20 +72,30 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
private final Blackboard blackboard;
private final Case currentCase;
private volatile boolean cancelled;
private volatile boolean createVHD;
private long totalFiles;
private Map<String, Long> imagePathToObjIdMap;
private final Object addMultipleImagesLock;
@GuardedBy("addMultipleImagesLock")
private AddMultipleImagesTask addMultipleImagesTask = null;
AddLogicalImageTask(String deviceId,
List<String> imagePaths,
String timeZone,
File src, File dest,
DataSourceProcessorProgressMonitor progressMonitor,
DataSourceProcessorCallback callback
) throws NoCurrentCaseException {
super(deviceId, imagePaths, timeZone, progressMonitor, callback);
this.deviceId = deviceId;
this.timeZone = timeZone;
this.src = src;
this.dest = dest;
this.progressMonitor = progressMonitor;
this.callback = callback;
this.currentCase = Case.getCurrentCase();
this.blackboard = this.currentCase.getServices().getBlackboard();
this.blackboard = this.currentCase.getServices().getArtifactsBlackboard();
this.addMultipleImagesLock = new Object();
}
/**
@ -90,16 +108,43 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
"# {0} - src", "# {1} - dest", "AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}",
"# {0} - file", "AddLogicalImageTask.addingToReport=Adding {0} to report",
"# {0} - file", "AddLogicalImageTask.doneAddingToReport=Done adding {0} to report",
"AddLogicalImageTask.ingestionCancelled=Ingestion cancelled",
"# {0} - file", "AddLogicalImageTask.failToGetCanonicalPath=Fail to get canonical path for {0}",
"# {0} - sparseImageDirectory", "AddLogicalImageTask.directoryDoesNotContainSparseImage=Directory {0} does not contain any images",
"AddLogicalImageTask.noCurrentCase=No current case",
"AddLogicalImageTask.addingInterestingFiles=Adding search results as interesting files",
"AddLogicalImageTask.doneAddingInterestingFiles=Done adding search results as interesting files",
"# {0} - SearchResults.txt", "# {1} - directory", "AddLogicalImageTask.cannotFindFiles=Cannot find {0} in {1}",
"# {0} - reason", "AddLogicalImageTask.failedToAddInterestingFiles=Failed to add interesting files: {0}"
"# {0} - reason", "AddLogicalImageTask.failedToAddInterestingFiles=Failed to add interesting files: {0}",
"AddLogicalImageTask.addingExtractedFiles=Adding extracted files",
"AddLogicalImageTask.doneAddingExtractedFiles=Done adding extracted files",
"# {0} - reason", "AddLogicalImageTask.failedToGetTotalFilesCount=Failed to get total files count: {0}",
"AddLogicalImageTask.addImageCancelled=Add image cancelled"
})
@Override
public void run() {
List<String> errorList = new ArrayList<>();
List<Content> emptyDataSources = new ArrayList<>();
try {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_copyingImageFromTo(src.toString(), dest.toString()));
FileUtils.copyDirectory(src, dest);
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneCopying());
} catch (IOException ex) {
// Copy directory failed
String msg = Bundle.AddLogicalImageTask_failedToCopyDirectory(src.toString(), dest.toString());
errorList.add(msg);
}
if (cancelled) {
// Don't delete destination directory once we started adding interesting files.
// At this point the database and destination directory are complete.
deleteDestinationDirectory();
errorList.add(Bundle.AddLogicalImageTask_addImageCancelled());
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
// Add the SearchResults.txt and users.txt to the case report
String resultsFilename;
if (Paths.get(dest.toString(), SEARCH_RESULTS_TXT).toFile().exists()) {
@ -109,6 +154,7 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingToReport(resultsFilename));
String status = addReport(Paths.get(dest.toString(), resultsFilename), resultsFilename + " " + src.getName());
if (status != null) {
@ -127,17 +173,101 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
}
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(USERS_TXT));
super.run();
if (super.getResult() == DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS) {
callback.done(super.getResult(), super.getErrorMessages(), super.getNewDataSources());
// Get all VHD files in the dest directory
List<String> imagePaths = new ArrayList<>();
for (File f : dest.listFiles()) {
if (f.getName().endsWith(VHD_EXTENSION)) {
try {
imagePaths.add(f.getCanonicalPath());
} catch (IOException ioe) {
String msg = Bundle.AddLogicalImageTask_failToGetCanonicalPath(f.getName());
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
}
}
Path resultsPath = Paths.get(dest.toString(), resultsFilename);
try {
totalFiles = Files.lines(resultsPath).count() - 1; // skip the header line
} catch (IOException ex) {
errorList.add(Bundle.AddLogicalImageTask_failedToGetTotalFilesCount(ex.getMessage()));
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
List<Content> newDataSources = new ArrayList<>();
if (imagePaths.isEmpty()) {
createVHD = false;
// No VHD in src directory, try ingest the root directory as local files
File root = Paths.get(dest.toString(), ROOT_STR).toFile();
if (root.exists() && root.isDirectory()) {
imagePaths.add(root.getAbsolutePath());
} else {
String msg = Bundle.AddLogicalImageTask_directoryDoesNotContainSparseImage(dest);
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
try {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingExtractedFiles());
addExtractedFiles(dest, resultsPath, newDataSources);
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingExtractedFiles());
} catch (IOException | TskCoreException ex) {
errorList.add(ex.getMessage());
LOGGER.log(Level.SEVERE, String.format("Failed to add datasource: %s", ex.getMessage()), ex); // NON-NLS
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
} else {
createVHD = true;
// ingest the VHDs
try {
synchronized (addMultipleImagesLock) {
if (cancelled) {
LOGGER.log(Level.SEVERE, "Add VHD cancelled"); // NON-NLS
errorList.add(Bundle.AddLogicalImageTask_addImageCancelled());
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
addMultipleImagesTask = new AddMultipleImagesTask(deviceId, imagePaths, timeZone , progressMonitor);
}
addMultipleImagesTask.run();
if (addMultipleImagesTask.getResult() == DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS) {
LOGGER.log(Level.SEVERE, "Failed to add VHD datasource"); // NON-NLS
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, addMultipleImagesTask.getErrorMessages(), emptyDataSources);
return;
}
} catch (NoCurrentCaseException ex) {
String msg = Bundle.AddLogicalImageTask_noCurrentCase();
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
}
if (cancelled) {
if (!createVHD) {
// TODO: When 5453 is fixed, we should be able to delete it when adding VHD.
deleteDestinationDirectory();
}
errorList.add(Bundle.AddLogicalImageTask_addImageCancelled());
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
try {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFiles());
addInterestingFiles(dest, Paths.get(dest.toString(), resultsFilename));
addInterestingFiles(Paths.get(dest.toString(), resultsFilename), createVHD);
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingInterestingFiles());
callback.done(super.getResult(), super.getErrorMessages(), super.getNewDataSources());
if (createVHD) {
callback.done(addMultipleImagesTask.getResult(), addMultipleImagesTask.getErrorMessages(), addMultipleImagesTask.getNewDataSources());
} else {
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS, errorList, newDataSources);
}
} catch (IOException | TskCoreException ex) {
errorList.add(Bundle.AddLogicalImageTask_failedToAddInterestingFiles(ex.getMessage()));
LOGGER.log(Level.SEVERE, "Failed to add interesting files", ex); // NON-NLS
@ -171,44 +301,58 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
}
}
/**
* Attempts to cancel the processing of the input image files. May result in
* partial processing of the input.
*/
void cancelTask() {
LOGGER.log(Level.WARNING, "AddLogicalImageTask cancelled, processing may be incomplete"); // NON-NLS
synchronized (addMultipleImagesLock) {
cancelled = true;
if (addMultipleImagesTask != null) {
addMultipleImagesTask.cancelTask();
}
}
}
private Map<String, Long> imagePathsToDataSourceObjId(Map<Long, List<String>> imagePaths) {
Map<String, Long> imagePathToObjIdMap = new HashMap<>();
Map<String, Long> imagePathToObjId = new HashMap<>();
for (Map.Entry<Long, List<String>> entry : imagePaths.entrySet()) {
Long key = entry.getKey();
List<String> names = entry.getValue();
for (String name : names) {
imagePathToObjIdMap.put(name, key);
imagePathToObjId.put(name, key);
}
}
return imagePathToObjIdMap;
return imagePathToObjId;
}
@Messages({
"# {0} - line number", "# {1} - fields length", "# {2} - expected length", "AddLogicalImageTask.notEnoughFields=File does not contain enough fields at line {0}, got {1}, expecting {2}",
"# {0} - target image path", "AddLogicalImageTask.cannotFindDataSourceObjId=Cannot find obj_id in tsk_image_names for {0}"
"# {0} - target image path", "AddLogicalImageTask.cannotFindDataSourceObjId=Cannot find obj_id in tsk_image_names for {0}",
"# {0} - file number", "# {1} - total files", "AddLogicalImageTask.addingInterestingFile=Adding interesting files ({0}/{1})"
})
private void addInterestingFiles(File src, Path resultsPath) throws IOException, TskCoreException {
Map<Long, List<String>> imagePaths = currentCase.getSleuthkitCase().getImagePaths();
Map<String, Long> imagePathToObjIdMap = imagePathsToDataSourceObjId(imagePaths);
private void addInterestingFiles(Path resultsPath, boolean createVHD) throws IOException, TskCoreException {
Map<Long, List<String>> objIdToimagePathsMap = currentCase.getSleuthkitCase().getImagePaths();
imagePathToObjIdMap = imagePathsToDataSourceObjId(objIdToimagePathsMap);
try (BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(resultsPath.toFile()), "UTF8"))) { // NON-NLS
List<BlackboardArtifact> artifacts = new ArrayList<>();
String line;
br.readLine(); // skip the header line
int lineNumber = 2;
while ((line = br.readLine()) != null) {
if (cancelled) {
// Don't delete destination directory once we started adding interesting files.
// At this point the database and destination directory are complete.
break;
}
String[] fields = line.split("\t", -1); // NON-NLS
if (fields.length != 9) {
throw new IOException(Bundle.AddLogicalImageTask_notEnoughFields(lineNumber, fields.length, 9));
if (fields.length != 14) {
throw new IOException(Bundle.AddLogicalImageTask_notEnoughFields(lineNumber, fields.length, 14));
}
String vhdFilename = fields[0];
String targetImagePath = Paths.get(src.toString(), vhdFilename).toString();
Long dataSourceObjId = imagePathToObjIdMap.get(targetImagePath);
if (dataSourceObjId == null) {
throw new TskCoreException(Bundle.AddLogicalImageTask_cannotFindDataSourceObjId(targetImagePath));
}
// String fileSystemOffsetStr = fields[1];
String fileMetaAddressStr = fields[2];
// String extractStatusStr = fields[3];
@ -216,37 +360,151 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
String ruleName = fields[5];
// String description = fields[6];
String filename = fields[7];
// String parentPath = fields[8];
String parentPath = fields[8];
String query = String.format("data_source_obj_id = '%s' AND meta_addr = '%s' AND name = '%s'", // NON-NLS
dataSourceObjId.toString(), fileMetaAddressStr, filename);
if (lineNumber % 100 == 0) {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFile(lineNumber, totalFiles));
}
String query = makeQuery(createVHD, vhdFilename, fileMetaAddressStr, parentPath, filename);
// TODO - findAllFilesWhere should SQL-escape the query
List<AbstractFile> matchedFiles = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(query);
for (AbstractFile file : matchedFiles) {
addInterestingFile(file, ruleSetName, ruleName);
addInterestingFileToArtifacts(file, ruleSetName, ruleName, artifacts);
}
lineNumber++;
} // end reading file
try {
// index the artifact for keyword search
blackboard.postArtifacts(artifacts, MODULE_NAME);
} catch (Blackboard.BlackboardException ex) {
LOGGER.log(Level.SEVERE, "Unable to post artifacts to blackboard", ex); //NON-NLS
}
}
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME,
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
}
private void addInterestingFile(AbstractFile file, String ruleSetName, String ruleName) throws TskCoreException {
private void addInterestingFileToArtifacts(AbstractFile file, String ruleSetName, String ruleName, List<BlackboardArtifact> artifacts) throws TskCoreException {
Collection<BlackboardAttribute> attributes = new ArrayList<>();
BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, ruleSetName);
attributes.add(setNameAttribute);
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, MODULE_NAME, ruleName);
attributes.add(ruleNameAttribute);
org.sleuthkit.datamodel.Blackboard tskBlackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard();
if (!tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
if (!blackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact artifact = this.currentCase.getSleuthkitCase().newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, file.getId());
artifact.addAttributes(attributes);
artifacts.add(artifact);
}
}
@Messages({
"# {0} - file number", "# {1} - total files", "AddLogicalImageTask.addingExtractedFile=Adding extracted files ({0}/{1})"
})
private void addExtractedFiles(File src, Path resultsPath, List<Content> newDataSources) throws TskCoreException, IOException {
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
SleuthkitCase.CaseDbTransaction trans = null;
try {
trans = skCase.beginTransaction();
LocalFilesDataSource localFilesDataSource = skCase.addLocalFilesDataSource(deviceId, this.src.getName(), timeZone, trans);
LocalFileImporter fileImporter = new LocalFileImporter(skCase, trans);
try (BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(resultsPath.toFile()), "UTF8"))) { // NON-NLS
String line;
br.readLine(); // skip the header line
int lineNumber = 2;
while ((line = br.readLine()) != null) {
if (cancelled) {
rollbackTransaction(trans);
return;
}
String[] fields = line.split("\t", -1); // NON-NLS
if (fields.length != 14) {
rollbackTransaction(trans);
throw new IOException(Bundle.AddLogicalImageTask_notEnoughFields(lineNumber, fields.length, 14));
}
String vhdFilename = fields[0];
// String fileSystemOffsetStr = fields[1];
// String fileMetaAddressStr = fields[2];
// String extractStatusStr = fields[3];
// String ruleSetName = fields[4];
// String ruleName = fields[5];
// String description = fields[6];
String filename = fields[7];
String parentPath = fields[8];
String extractedFilePath = fields[9];
String crtime = fields[10];
String mtime = fields[11];
String atime = fields[12];
String ctime = fields[13];
parentPath = ROOT_STR + "/" + vhdFilename + "/" + parentPath;
if (lineNumber % 100 == 0) {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingExtractedFile(lineNumber, totalFiles));
}
//addLocalFile here
fileImporter.addLocalFile(
Paths.get(src.toString(), extractedFilePath).toFile(),
filename,
parentPath,
Long.parseLong(ctime),
Long.parseLong(crtime),
Long.parseLong(atime),
Long.parseLong(mtime),
localFilesDataSource);
lineNumber++;
} // end reading file
}
trans.commit();
newDataSources.add(localFilesDataSource);
} catch (NumberFormatException | TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding extracted files", ex); // NON-NLS
rollbackTransaction(trans);
throw new TskCoreException("Error adding extracted files", ex);
}
}
private void rollbackTransaction(SleuthkitCase.CaseDbTransaction trans) throws TskCoreException {
if (null != trans) {
try {
// index the artifact for keyword search
blackboard.indexArtifact(artifact);
} catch (Blackboard.BlackboardException ex) {
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
trans.rollback();
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Failed to rollback transaction: %s", ex.getMessage()), ex); // NON-NLS
}
}
}
private boolean deleteDestinationDirectory() {
try {
FileUtils.deleteDirectory(dest);
LOGGER.log(Level.INFO, String.format("Cancellation: Deleted directory %s", dest.toString())); // NON-NLS
return true;
} catch (IOException ex) {
LOGGER.log(Level.WARNING, String.format("Cancellation: Failed to delete directory %s", dest.toString()), ex); // NON-NLS
return false;
}
}
String makeQuery(boolean createVHD, String vhdFilename, String fileMetaAddressStr, String parentPath, String filename) throws TskCoreException {
String query;
if (createVHD) {
String targetImagePath = Paths.get(dest.toString(), vhdFilename).toString();
Long dataSourceObjId = imagePathToObjIdMap.get(targetImagePath);
if (dataSourceObjId == null) {
throw new TskCoreException(Bundle.AddLogicalImageTask_cannotFindDataSourceObjId(targetImagePath));
}
query = String.format("data_source_obj_id = '%s' AND meta_addr = '%s' AND name = '%s'", // NON-NLS
dataSourceObjId.toString(), fileMetaAddressStr, filename.replace("'", "''"));
} else {
String newParentPath = "/" + ROOT_STR + "/" + vhdFilename + "/" + parentPath;
query = String.format("name = '%s' AND parent_path = '%s'", // NON-NLS
filename.replace("'", "''"), newParentPath.replace("'", "''"));
}
return query;
}
}

View File

@ -21,10 +21,10 @@ package org.sleuthkit.autopsy.logicalimager.dsp;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.annotation.concurrent.GuardedBy;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -42,27 +42,34 @@ import org.sleuthkit.datamodel.TskFileRange;
*
*/
@Messages({
"AddMultipleImageTask.fsTypeUnknownErr=Cannot determine file system type"
"AddMultipleImagesTask.fsTypeUnknownErr=Cannot determine file system type"
})
class AddMultipleImageTask implements Runnable {
class AddMultipleImagesTask implements Runnable {
private static final Logger LOGGER = Logger.getLogger(AddMultipleImageTask.class.getName());
public static final String TSK_FS_TYPE_UNKNOWN_ERR_MSG = Bundle.AddMultipleImageTask_fsTypeUnknownErr();
private static final Logger LOGGER = Logger.getLogger(AddMultipleImagesTask.class.getName());
public static final String TSK_FS_TYPE_UNKNOWN_ERR_MSG = Bundle.AddMultipleImagesTask_fsTypeUnknownErr();
private static final long TWO_GB = 2000000000L;
private final String deviceId;
private final List<String> imageFilePaths;
private final String timeZone;
private final long chunkSize = TWO_GB;
private final DataSourceProcessorProgressMonitor progressMonitor;
private final DataSourceProcessorCallback callback;
private final Case currentCase;
private boolean criticalErrorOccurred;
private volatile boolean cancelled;
private List<Content> newDataSources;
private List<String> errorMessages;
private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess = null;
private List<String> errorMessages = new ArrayList<>();
private DataSourceProcessorResult result;
private List<Content> newDataSources = new ArrayList<>();
/*
* The cancellation requested flag and SleuthKit add image process are
* guarded by a lock to synchronize cancelling the process (setting the flag
* and calling its stop method) and calling either its commit or revert
* method.
*/
private final Object tskAddImageProcessLock;
@GuardedBy("tskAddImageProcessLock")
private boolean tskAddImageProcessStopped;
/**
* Constructs a runnable that adds multiple image files to a case database.
@ -78,41 +85,57 @@ class AddMultipleImageTask implements Runnable {
* java.util.TimeZone.getID.
* @param progressMonitor Progress monitor for reporting progress during
* processing.
* @param callback Callback to call when processing is done.
*
* @throws NoCurrentCaseException The exception if there is no open case.
*/
@Messages({
"# {0} - file", "AddMultipleImageTask.addingFileAsLogicalFile=Adding: {0} as an unallocated space file.",
"# {0} - file", "AddMultipleImagesTask.addingFileAsLogicalFile=Adding: {0} as an unallocated space file.",
"# {0} - deviceId", "# {1} - exceptionMessage",
"AddMultipleImageTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device %s: %s",})
AddMultipleImageTask(String deviceId, List<String> imageFilePaths, String timeZone,
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) throws NoCurrentCaseException {
"AddMultipleImagesTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device {0}: {1}",})
AddMultipleImagesTask(String deviceId, List<String> imageFilePaths, String timeZone,
DataSourceProcessorProgressMonitor progressMonitor) throws NoCurrentCaseException {
this.deviceId = deviceId;
this.imageFilePaths = imageFilePaths;
this.timeZone = timeZone;
this.callback = callback;
this.progressMonitor = progressMonitor;
currentCase = Case.getCurrentCaseThrows();
this.criticalErrorOccurred = false;
this.result = DataSourceProcessorResult.NO_ERRORS;
tskAddImageProcessLock = new Object();
}
@Messages({
"AddMultipleImagesTask.cancelled=Cancellation: Add image process reverted",
})
@Override
public void run() {
newDataSources = new ArrayList<>();
errorMessages = new ArrayList<>();
newDataSources = new ArrayList<>();
List<Content> emptyDataSources = new ArrayList<>();
/*
* Try to add the input image files as images.
*/
List<String> corruptedImageFilePaths = new ArrayList<>();
currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
try {
currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
progressMonitor.setIndeterminate(true);
for (String imageFilePath : imageFilePaths) {
if (!cancelled) {
addImageToCase(imageFilePath, newDataSources, corruptedImageFilePaths, errorMessages);
synchronized (tskAddImageProcessLock) {
if (!tskAddImageProcessStopped) {
addImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, false, false, "");
} else {
return;
}
}
run(imageFilePath, corruptedImageFilePaths, errorMessages);
commitOrRevertAddImageProcess(imageFilePath, errorMessages, newDataSources);
synchronized (tskAddImageProcessLock) {
if (tskAddImageProcessStopped) {
errorMessages.add(Bundle.AddMultipleImagesTask_cancelled());
result = DataSourceProcessorResult.CRITICAL_ERRORS;
newDataSources = emptyDataSources;
return;
}
}
}
} finally {
@ -124,11 +147,11 @@ class AddMultipleImageTask implements Runnable {
* single an unallocated space file with the device id as the root virtual
* directory name.
*/
if (!cancelled && !corruptedImageFilePaths.isEmpty()) {
if (!tskAddImageProcessStopped && !corruptedImageFilePaths.isEmpty()) {
SleuthkitCase caseDatabase;
caseDatabase = currentCase.getSleuthkitCase();
try {
progressMonitor.setProgressText(Bundle.AddMultipleImageTask_addingFileAsLogicalFile(corruptedImageFilePaths.toString()));
progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_addingFileAsLogicalFile(corruptedImageFilePaths.toString()));
caseDatabase.acquireSingleUserCaseWriteLock();
@ -146,14 +169,13 @@ class AddMultipleImageTask implements Runnable {
start += TWO_GB;
sequence++;
}
}
double leftoverSize = imageSize - sequence * TWO_GB;
fileRanges.add(new TskFileRange(start, (long)leftoverSize, sequence));
caseDatabase.addLayoutFiles(dataSource, fileRanges);
} catch (TskCoreException ex) {
errorMessages.add(Bundle.AddMultipleImageTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
errorMessages.add(Bundle.AddMultipleImagesTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
criticalErrorOccurred = true;
} finally {
caseDatabase.releaseSingleUserCaseWriteLock();
@ -167,9 +189,6 @@ class AddMultipleImageTask implements Runnable {
progressMonitor.setProgress(0);
progressMonitor.setProgress(100);
/*
* Pass the results back via the callback.
*/
if (criticalErrorOccurred) {
result = DataSourceProcessorResult.CRITICAL_ERRORS;
} else if (!errorMessages.isEmpty()) {
@ -184,38 +203,50 @@ class AddMultipleImageTask implements Runnable {
* partial processing of the input.
*/
void cancelTask() {
LOGGER.log(Level.WARNING, "AddMultipleImageTask cancelled, processing may be incomplete"); // NON-NLS
cancelled = true;
LOGGER.log(Level.WARNING, "AddMultipleImagesTask cancelled, processing may be incomplete"); // NON-NLS
synchronized (tskAddImageProcessLock) {
tskAddImageProcessStopped = true;
if (addImageProcess != null) {
try {
/*
* All this does is set a flag that will make the TSK add
* image process exit when the flag is checked between
* processing steps. The state of the flag is not
* accessible, so record it here so that it is known that
* the revert method of the process object needs to be
* called.
*/
addImageProcess.stop();
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Cancellation: addImagePRocess.stop failed", ex); // NON-NLS
}
}
}
}
/**
* Attempts to add an input image to the case.
*
* @param imageFilePath The image file path.
* @param newDataSources If the image is added, a data source is
* added to this list for eventual return to
* the caller via the callback.
* @param corruptedImageFilePaths If the image cannot be added because
* Sleuth Kit cannot detect a filesystem,
* the image file path is added to this list
* for later addition as an unallocated space file.
* @param errorMessages If there are any error messages, the
* error messages are added to this list for
* eventual return to the caller via the
* callback.
* eventual return to the caller via the getter
* method.
*/
@Messages({
"# {0} - imageFilePath", "AddMultipleImageTask.adding=Adding: {0}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}",})
private void addImageToCase(String imageFilePath, List<Content> newDataSources, List<String> corruptedImageFilePaths, List<String> errorMessages) {
"# {0} - imageFilePath", "AddMultipleImagesTask.adding=Adding: {0}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImagesTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImagesTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImagesTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}",})
private void run(String imageFilePath, List<String> corruptedImageFilePaths, List<String> errorMessages) {
/*
* Try to add the image to the case database as a data source.
*/
progressMonitor.setProgressText(Bundle.AddMultipleImageTask_adding(imageFilePath));
SleuthkitCase caseDatabase = currentCase.getSleuthkitCase();
SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess = caseDatabase.makeAddImageProcess(timeZone, false, false, "");
progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_adding(imageFilePath));
try {
addImageProcess.run(deviceId, new String[]{imageFilePath});
} catch (TskCoreException ex) {
@ -228,62 +259,89 @@ class AddMultipleImageTask implements Runnable {
*/
corruptedImageFilePaths.add(imageFilePath);
} else {
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
criticalErrorOccurred = true;
}
} catch (TskDataException ex) {
errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
}
}
/**
* Commits or reverts the results of the TSK add image process. If the
* process was stopped before it completed or there was a critical error the
* results are reverted, otherwise they are committed.
*
* @param imageFilePath The image file path.
* @param errorMessages Error messages, if any, are added to this list for
* eventual return via the getter method.
* @param newDataSources If the new image is successfully committed, it is
* added to this list for eventual return via the
* getter method.
*/
private void commitOrRevertAddImageProcess(String imageFilePath, List<String> errorMessages, List<Content> newDataSources) {
synchronized (tskAddImageProcessLock) {
if (tskAddImageProcessStopped || criticalErrorOccurred) {
try {
addImageProcess.revert();
} catch (TskCoreException ex) {
errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorReverting(imageFilePath, deviceId, ex.getLocalizedMessage()));
criticalErrorOccurred = true;
}
return;
}
/*
* Either way, the add image process needs to be reverted.
* Try to commit the results of the add image process, retrieve the new
* image from the case database, and add it to the list of new data
* sources to be returned via the getter method.
*/
try {
addImageProcess.revert();
} catch (TskCoreException e) {
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorReverting(imageFilePath, deviceId, e.getLocalizedMessage()));
long imageId = addImageProcess.commit();
Image dataSource = currentCase.getSleuthkitCase().getImageById(imageId);
newDataSources.add(dataSource);
/*
* Verify the size of the new image. Note that it may not be what is
* expected, but at least part of it was added to the case.
*/
String verificationError = dataSource.verifyImageSize();
if (!verificationError.isEmpty()) {
errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
}
} catch (TskCoreException ex) {
/*
* The add image process commit failed or querying the case database
* for the newly added image failed. Either way, this is a critical
* error.
*/
errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
criticalErrorOccurred = true;
}
return;
} catch (TskDataException ex) {
errorMessages.add(Bundle.AddMultipleImageTask_nonCriticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
}
/*
* Try to commit the results of the add image process, retrieve the new
* image from the case database, and add it to the list of new data
* sources to be returned via the callback.
*/
try {
long imageId = addImageProcess.commit();
Image dataSource = caseDatabase.getImageById(imageId);
newDataSources.add(dataSource);
/*
* Verify the size of the new image. Note that it may not be what is
* expected, but at least part of it was added to the case.
*/
String verificationError = dataSource.verifyImageSize();
if (!verificationError.isEmpty()) {
errorMessages.add(Bundle.AddMultipleImageTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
}
} catch (TskCoreException ex) {
/*
* The add image process commit failed or querying the case database
* for the newly added image failed. Either way, this is a critical
* error.
*/
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
criticalErrorOccurred = true;
}
}
public List<Content> getNewDataSources() {
return newDataSources;
}
/**
* Return the error messages from the AddMultipleImagesTask run
* @return List of error message
*/
public List<String> getErrorMessages() {
return errorMessages;
}
/**
* Return the result the AddMultipleImagesTask run
* @return The result of the run
*/
public DataSourceProcessorResult getResult() {
return result;
}
/**
* Return the new data sources the AddMultipleImagesTask run
* @return The new data sources of the run
*/
public List<Content> getNewDataSources() {
return newDataSources;
}
}

View File

@ -2,15 +2,28 @@
# To change this template file, choose Tools | Templates
# and open the template in the editor.
AddLogicalImageTask.addImageCancelled=Add image cancelled
# {0} - file number
# {1} - total files
AddLogicalImageTask.addingExtractedFile=Adding extracted files ({0}/{1})
AddLogicalImageTask.addingExtractedFiles=Adding extracted files
# {0} - file number
# {1} - total files
AddLogicalImageTask.addingInterestingFile=Adding interesting files ({0}/{1})
AddLogicalImageTask.addingInterestingFiles=Adding search results as interesting files
# {0} - file
AddLogicalImageTask.addingToReport=Adding {0} to report
# {0} - target image path
AddLogicalImageTask.cannotFindDataSourceObjId=Cannot find obj_id in tsk_image_names for {0}
# {0} - SearchResults.txt
# {1} - directory
AddLogicalImageTask.cannotFindFiles=Cannot find {0} in {1}
# {0} - src
# {1} - dest
AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1}
# {0} - sparseImageDirectory
AddLogicalImageTask.directoryDoesNotContainSparseImage=Directory {0} does not contain any images
AddLogicalImageTask.doneAddingExtractedFiles=Done adding extracted files
AddLogicalImageTask.doneAddingInterestingFiles=Done adding search results as interesting files
# {0} - file
AddLogicalImageTask.doneAddingToReport=Done adding {0} to report
@ -23,37 +36,45 @@ AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1}
# {0} - src
# {1} - dest
AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}
# {0} - reason
AddLogicalImageTask.failedToGetTotalFilesCount=Failed to get total files count: {0}
# {0} - file
AddLogicalImageTask.failToGetCanonicalPath=Fail to get canonical path for {0}
AddLogicalImageTask.ingestionCancelled=Ingestion cancelled
AddLogicalImageTask.noCurrentCase=No current case
# {0} - line number
# {1} - fields length
# {2} - expected length
AddLogicalImageTask.notEnoughFields=File does not contain enough fields at line {0}, got {1}, expecting {2}
# {0} - imageFilePath
AddMultipleImageTask.adding=Adding: {0}
AddMultipleImagesTask.adding=Adding: {0}
# {0} - file
AddMultipleImageTask.addingFileAsLogicalFile=Adding: {0} as an unallocated space file.
AddMultipleImagesTask.addingFileAsLogicalFile=Adding: {0} as an unallocated space file.
AddMultipleImagesTask.cancelled=Cancellation: Add image process reverted
# {0} - imageFilePath
# {1} - deviceId
# {2} - exceptionMessage
AddMultipleImageTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}
AddMultipleImagesTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}
# {0} - imageFilePath
# {1} - deviceId
# {2} - exceptionMessage
AddMultipleImageTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}
AddMultipleImagesTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}
# {0} - deviceId
# {1} - exceptionMessage
AddMultipleImageTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device %s: %s
AddMultipleImageTask.fsTypeUnknownErr=Cannot determine file system type
AddMultipleImagesTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device {0}: {1}
AddMultipleImagesTask.fsTypeUnknownErr=Cannot determine file system type
# {0} - imageFilePath
# {1} - deviceId
# {2} - exceptionMessage
AddMultipleImageTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}
AddMultipleImagesTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}
LogicalImagerDSProcessor.dataSourceType=Autopsy Logical Imager Results
LogicalImagerDSProcessor.destinationDirectoryConfirmation=Destination directory confirmation
# {0} - directory
LogicalImagerDSProcessor.destinationDirectoryConfirmationMsg=The logical imager folder {0} already exists,\ndo you want to add it again using a new folder name?
# {0} - directory
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
# {0} - directory
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
# {0} - file
LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}
# {0} - imageDirPath
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
LogicalImagerDSProcessor.noCurrentCase=No current case

View File

@ -19,15 +19,15 @@
package org.sleuthkit.autopsy.logicalimager.dsp;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.YES_OPTION;
import javax.swing.JPanel;
import org.apache.commons.io.FileUtils;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders;
@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
import org.sleuthkit.datamodel.Content;
/**
@ -131,8 +132,10 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor {
"# {0} - imageDirPath", "LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.",
"# {0} - directory", "LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}",
"# {0} - directory", "LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists",
"# {0} - file", "LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}",
"LogicalImagerDSProcessor.noCurrentCase=No current case",})
"LogicalImagerDSProcessor.destinationDirectoryConfirmation=Destination directory confirmation",
"# {0} - directory", "LogicalImagerDSProcessor.destinationDirectoryConfirmationMsg=The logical imager folder {0} already exists,\ndo you want to add it again using a new folder name?",
"LogicalImagerDSProcessor.noCurrentCase=No current case",
})
@Override
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
configPanel.storeSettings();
@ -164,44 +167,27 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor {
File dest = Paths.get(logicalImagerDir.toString(), imageDirPath.getFileName().toString()).toFile();
if (dest.exists()) {
// Destination directory already exists
String msg = Bundle.LogicalImagerDSProcessor_directoryAlreadyExists(dest.toString());
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
int showConfirmDialog = JOptionPane.showConfirmDialog(configPanel,
Bundle.LogicalImagerDSProcessor_destinationDirectoryConfirmationMsg(dest.toString()),
Bundle.LogicalImagerDSProcessor_destinationDirectoryConfirmation(),
JOptionPane.YES_NO_OPTION);
if (showConfirmDialog == YES_OPTION) {
// Get unique dest directory
String uniqueDirectory = imageDirPath.getFileName() + "_" + TimeStampUtils.createTimeStamp();
dest = Paths.get(logicalImagerDir.toString(), uniqueDirectory).toFile();
} else {
String msg = Bundle.LogicalImagerDSProcessor_directoryAlreadyExists(dest.toString());
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
}
File src = imageDirPath.toFile();
try {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_copyingImageFromTo(src.toString(), dest.toString()));
FileUtils.copyDirectory(src, dest);
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneCopying());
} catch (IOException ex) {
// Copy directory failed
String msg = Bundle.AddLogicalImageTask_failedToCopyDirectory(src.toString(), dest.toString());
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
// Get all VHD files in the src directory
List<String> imagePaths = new ArrayList<>();
for (File f : dest.listFiles()) {
if (f.getName().endsWith(".vhd")) {
try {
imagePaths.add(f.getCanonicalPath());
} catch (IOException ex) {
String msg = Bundle.LogicalImagerDSProcessor_failToGetCanonicalPath(f.getName());
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
}
}
try {
String deviceId = UUID.randomUUID().toString();
String timeZone = Calendar.getInstance().getTimeZone().getID();
run(deviceId, imagePaths,
timeZone, src, dest,
run(deviceId, timeZone, src, dest,
progressMonitor, callback);
} catch (NoCurrentCaseException ex) {
String msg = Bundle.LogicalImagerDSProcessor_noCurrentCase();
@ -220,7 +206,6 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor {
* @param deviceId An ASCII-printable identifier for the device
* associated with the data source that is intended
* to be unique across multiple cases (e.g., a UUID).
* @param imagePaths Paths to the image files.
* @param timeZone The time zone to use when processing dates and
* times for the image, obtained from
* java.util.TimeZone.getID.
@ -230,13 +215,14 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor {
* processing.
* @param callback Callback to call when processing is done.
*/
private void run(String deviceId, List<String> imagePaths, String timeZone,
private void run(String deviceId, String timeZone,
File src, File dest,
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback
) throws NoCurrentCaseException {
addLogicalImageTask = new AddLogicalImageTask(deviceId, imagePaths, timeZone, src, dest,
addLogicalImageTask = new AddLogicalImageTask(deviceId, timeZone, src, dest,
progressMonitor, callback);
new Thread(addLogicalImageTask).start();
Thread thread = new Thread(addLogicalImageTask);
thread.start();
}
@Override

View File

@ -333,9 +333,19 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener {
}
});
if (vhdFiles.length == 0) {
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path));
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
return;
// No VHD files, try directories for individual files
String[] directories = dir.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return Paths.get(dir.toString(), name).toFile().isDirectory();
}
});
if (directories.length == 0) {
// No directories, bail
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path));
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
return;
}
}
manualImageDirPath = Paths.get(path);
setNormalMessage(path);
@ -360,11 +370,11 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener {
}
}
private boolean dirHasVhdFiles(File dir) {
File[] fList = dir.listFiles(new FilenameFilter() {
private boolean dirHasImagerResult(File dir) {
String[] fList = dir.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".vhd");
return name.endsWith(".vhd") || Paths.get(dir.toString(), name).toFile().isDirectory();
}
});
return (fList != null && fList.length != 0);
@ -382,9 +392,9 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener {
if (fList != null) {
imageTableModel = new ImageTableModel();
// Find all directories with name like Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
// and has vhd files in it
// and has Logical Imager result in it
for (File file : fList) {
if (file.isDirectory() && dirHasVhdFiles(file)) {
if (file.isDirectory() && dirHasImagerResult(file)) {
String dir = file.getName();
Matcher m = regex.matcher(dir);
if (m.find()) {
@ -508,7 +518,7 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener {
}
} catch (IOException ignored) {
//unable to get this removable drive for default selection will try and select next removable drive by default
logger.log(Level.INFO, "Unable to select first removable drive found", ignored);
logger.log(Level.INFO, String.format("Unable to select first removable drive found: %s", ignored.getMessage()));
}
}
i++;

View File

@ -31,6 +31,9 @@ PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged f
PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files
PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results
PortableCaseReportModule.generateReport.errorCopyingTags=Error copying tags
PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table
PortableCaseReportModule.generateReport.errorCreatingReportFolder=Could not make report folder
PortableCaseReportModule.generateReport.errorGeneratingUCOreport=Problem while generating CASE-UCO report
# {0} - attribute type name
PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}
PortableCaseReportModule.generateReport.interestingItemError=Error loading intersting items

View File

@ -206,7 +206,7 @@ class PortableCaseInterestingItemsListPanel extends javax.swing.JPanel {
*/
private static class GetInterestingItemSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(GetInterestingItemSetNamesCallback.class.getName());
private static final Logger logger = Logger.getLogger(GetInterestingItemSetNamesCallback.class.getName());
private final Map<String, Long> setCounts = new HashMap<>();
@Override

View File

@ -36,6 +36,7 @@ import org.openide.modules.InstalledFileLocator;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
import org.sleuthkit.autopsy.coreutils.FileUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
@ -179,9 +180,12 @@ class PortableCaseReportModule implements ReportModule {
"PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
"PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
"PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
"PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table",
"# {0} - attribute type name",
"PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
"PortableCaseReportModule.generateReport.compressingCase=Compressing case...",
"PortableCaseReportModule.generateReport.errorCreatingReportFolder=Could not make report folder",
"PortableCaseReportModule.generateReport.errorGeneratingUCOreport=Problem while generating CASE-UCO report"
})
void generateReport(String reportPath, PortableCaseOptions options, ReportProgressPanel progressPanel) {
@ -240,6 +244,14 @@ class PortableCaseReportModule implements ReportModule {
return;
}
// Set up the table for the image tags
try {
initializeImageTags(progressPanel);
} catch (TskCoreException ex) {
handleError("Error creating image tag table", Bundle.PortableCaseReportModule_generateReport_errorCreatingImageTagTable(), ex, progressPanel); // NON-NLS
return;
}
// Copy the selected tags
progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
try {
@ -358,7 +370,7 @@ class PortableCaseReportModule implements ReportModule {
File reportsFolder = Paths.get(caseFolder.toString(), "Reports").toFile();
if(!reportsFolder.mkdir()) {
handleError("Could not make report folder", "Could not make report folder", null, progressPanel); // NON-NLS
handleError("Could not make report folder", Bundle.PortableCaseReportModule_generateReport_errorCreatingReportFolder(), null, progressPanel); // NON-NLS
return;
}
@ -366,7 +378,7 @@ class PortableCaseReportModule implements ReportModule {
CaseUcoFormatExporter.export(tagNames, setNames, reportsFolder, progressPanel);
} catch (IOException | SQLException | NoCurrentCaseException | TskCoreException ex) {
handleError("Problem while generating CASE-UCO report",
"Problem while generating CASE-UCO report", ex, progressPanel); // NON-NLS
Bundle.PortableCaseReportModule_generateReport_errorGeneratingUCOreport(), ex, progressPanel); // NON-NLS
}
// Compress the case (if desired)
@ -484,6 +496,22 @@ class PortableCaseReportModule implements ReportModule {
currentCaseDbManager.select("max(examiner_id) as max_id from tsk_examiners", new StoreMaxIdCallback("tsk_examiners")); // NON-NLS
}
/**
* Set up the image tag table in the portable case
*
* @param progressPanel
*
* @throws TskCoreException
*/
private void initializeImageTags(ReportProgressPanel progressPanel) throws TskCoreException {
// Create the image tags table in the portable case
CaseDbAccessManager portableDbAccessManager = portableSkCase.getCaseDbAccessManager();
if (! portableDbAccessManager.tableExists(ContentViewerTagManager.TABLE_NAME)) {
portableDbAccessManager.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_SQLITE);
}
}
/**
* Add all files with a given tag to the portable case.
*
@ -507,17 +535,89 @@ class PortableCaseReportModule implements ReportModule {
Content content = tag.getContent();
if (content instanceof AbstractFile) {
long newFileId = copyContentToPortableCase(content, progressPanel);
// Tag the file
if (! oldTagNameToNewTagName.containsKey(tag.getName())) {
throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName()); // NON-NLS
}
portableSkCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
ContentTag newContentTag = portableSkCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
// Get the image tag data associated with this tag (empty string if there is none)
// and save it if present
String appData = getImageTagDataForContentTag(tag);
if (! appData.isEmpty()) {
addImageTagToPortableCase(newContentTag, appData);
}
}
}
}
/**
* Gets the image tag data for a given content tag
*
* @param tag The ContentTag in the current case
*
* @return The app_data string for this content tag or an empty string if there was none
*
* @throws TskCoreException
*/
private String getImageTagDataForContentTag(ContentTag tag) throws TskCoreException {
GetImageTagCallback callback = new GetImageTagCallback();
String query = "* FROM " + ContentViewerTagManager.TABLE_NAME + " WHERE content_tag_id = " + tag.getId();
currentCase.getSleuthkitCase().getCaseDbAccessManager().select(query, callback);
return callback.getAppData();
}
/**
* CaseDbAccessManager callback to get the app_data string for the image tag
*/
private static class GetImageTagCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
private static final Logger logger = Logger.getLogger(PortableCaseReportModule.class.getName());
private String appData = "";
@Override
public void process(ResultSet rs) {
try {
while (rs.next()) {
try {
appData = rs.getString("app_data"); // NON-NLS
} catch (SQLException ex) {
logger.log(Level.WARNING, "Unable to get app_data from result set", ex); // NON-NLS
}
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "Failed to get next result for app_data", ex); // NON-NLS
}
}
/**
* Get the app_data string
*
* @return the app_data string
*/
String getAppData() {
return appData;
}
}
/**
* Add an image tag to the portable case.
*
* @param newContentTag The content tag in the portable case
* @param appData The string to copy into app_data
*
* @throws TskCoreException
*/
private void addImageTagToPortableCase(ContentTag newContentTag, String appData) throws TskCoreException {
String insert = "(content_tag_id, app_data) VALUES (" + newContentTag.getId() + ", '" + appData + "')";
portableSkCase.getCaseDbAccessManager().insert(ContentViewerTagManager.TABLE_NAME, insert);
}
/**
* Add all artifacts with a given tag to the portable case.
*

View File

@ -205,7 +205,7 @@ class PortableCaseTagsListPanel extends javax.swing.JPanel {
*/
static class GetTagCountsCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(GetTagCountsCallback.class.getName());
private static final Logger logger = Logger.getLogger(GetTagCountsCallback.class.getName());
private final Map<Long, Long> tagCounts = new HashMap<>();
@Override

View File

@ -136,6 +136,7 @@ final class TikaTextExtractor implements TextExtractor {
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS
"application/pdf"); //NON-NLS
// Used to log to the tika file that is why it uses the java.util.logging.logger class instead of the Autopsy one
private static final java.util.logging.Logger TIKA_LOGGER = java.util.logging.Logger.getLogger("Tika"); //NON-NLS
private static final Logger AUTOPSY_LOGGER = Logger.getLogger(TikaTextExtractor.class.getName());

View File

@ -356,12 +356,8 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
scene.addEventFilter(KeyEvent.KEY_PRESSED, keyEvent -> {
if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
new Back(controller).handle(null);
} else if (new KeyCodeCombination(KeyCode.BACK_SPACE).match(keyEvent)) {
new Back(controller).handle(null);
} else if (new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
new Forward(controller).handle(null);
} else if (new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCodeCombination.SHIFT_DOWN).match(keyEvent)) {
new Forward(controller).handle(null);
}
});

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Copyright 2018-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,7 +22,9 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
@ -35,6 +37,8 @@ import org.sleuthkit.datamodel.Content;
*/
public final class IngestJobRunner {
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
/**
* Runs an ingest job, blocking until the job is completed.
*
@ -51,7 +55,7 @@ public final class IngestJobRunner {
Object ingestMonitor = new Object();
IngestJobCompletiontListener completiontListener = new IngestJobCompletiontListener(ingestMonitor);
IngestManager ingestManager = IngestManager.getInstance();
ingestManager.addIngestJobEventListener(completiontListener);
ingestManager.addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, completiontListener);
try {
synchronized (ingestMonitor) {
IngestJobStartResult jobStartResult = ingestManager.beginIngestJob(dataSources, settings);

View File

@ -28,6 +28,7 @@ import org.opencv.core.Core;
*/
public final class OpenCvLoader {
// Uses java logger since the Autopsy class logger (Autopsy-core) is not part of this module
private static final Logger logger = Logger.getLogger(OpenCvLoader.class.getName());
private static boolean openCvLoaded;
private static UnsatisfiedLinkError exception = null; // Deprecated

View File

@ -142,6 +142,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
ControlEventType.SHUTDOWN.toString(),
Event.CANCEL_JOB.toString(),
Event.REPROCESS_JOB.toString()}));
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final long JOB_STATUS_EVENT_INTERVAL_SECONDS = 10;
private static final String JOB_STATUS_PUBLISHING_THREAD_NAME = "AIM-job-status-event-publisher-%d";
private static final long MAX_MISSED_JOB_STATUS_UPDATES = 10;
@ -2670,7 +2671,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
Path caseDirectoryPath = currentJob.getCaseDirectoryPath();
AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath);
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
try {
synchronized (ingestLock) {
IngestJobSettings ingestJobSettings = new IngestJobSettings(AutoIngestUserPreferences.getAutoModeIngestModuleContextString());

View File

@ -26,7 +26,9 @@ import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import org.apache.commons.io.FileUtils;
@ -68,6 +70,7 @@ class MultiUserTestTool {
private static final Logger LOGGER = Logger.getLogger(MultiUserTestTool.class.getName());
private static final String TEST_FILE_NAME = "AutopsyTempFile";
private static final Object INGEST_LOCK = new Object();
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
static final String MULTI_USER_TEST_SUCCESSFUL = NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.Success");
private MultiUserTestTool() {
@ -225,10 +228,12 @@ class MultiUserTestTool {
/**
* Creates a new multi user case.
*
* @param baseCaseName Case name (will get time stamp appended to it)
* @param baseCaseName Case name (will get time stamp appended to it)
* @param rootOutputDirectory Full path to directory in which the case will
* be created
* be created
*
* @return Case object
*
* @throws CaseActionException
*/
private static Case createCase(String baseCaseName, String rootOutputDirectory) throws CaseActionException {
@ -251,10 +256,11 @@ class MultiUserTestTool {
* @param dataSource The data source.
*
* @return Error String if there was an error, empty string if the data
* source was added successfully
* source was added successfully
*
* @throws InterruptedException if the thread running the job processing
* task is interrupted while blocked, i.e., if ingest is shutting down.
* task is interrupted while blocked, i.e., if
* ingest is shutting down.
*/
@NbBundle.Messages({
"MultiUserTestTool.noContent=Test data source failed to produce content",
@ -298,10 +304,11 @@ class MultiUserTestTool {
* @param dataSource The data source to analyze.
*
* @return Error String if there was an error, empty string if the data
* source was analyzed successfully
* source was analyzed successfully
*
* @throws InterruptedException if the thread running the job processing
* task is interrupted while blocked, i.e., if auto ingest is shutting down.
* task is interrupted while blocked, i.e., if
* auto ingest is shutting down.
*/
@NbBundle.Messages({
"# {0} - cancellationReason",
@ -314,7 +321,7 @@ class MultiUserTestTool {
LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", dataSource.getPath());
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
try {
synchronized (INGEST_LOCK) {
IngestJobSettings ingestJobSettings = new IngestJobSettings(AutoIngestUserPreferences.getAutoModeIngestModuleContextString());
@ -324,9 +331,9 @@ class MultiUserTestTool {
IngestJob ingestJob = ingestJobStartResult.getJob();
if (null != ingestJob) {
/*
* Block until notified by the ingest job event
* listener or until interrupted because auto ingest
* is shutting down.
* Block until notified by the ingest job event listener
* or until interrupted because auto ingest is shutting
* down.
*/
INGEST_LOCK.wait();
LOGGER.log(Level.INFO, "Finished ingest modules analysis for {0} ", dataSource.getPath());
@ -381,7 +388,7 @@ class MultiUserTestTool {
* @return True if the service is running, false otherwise.
*
* @throws ServicesMonitorException if there is an error querying the
* services monitor.
* services monitor.
*/
private static boolean isServiceUp(String serviceName) throws ServicesMonitor.ServicesMonitorException {
return (ServicesMonitor.getInstance().getServiceStatus(serviceName).equals(ServicesMonitor.ServiceStatus.UP.toString()));

View File

@ -89,7 +89,8 @@ import org.sleuthkit.datamodel.TskData;
public final class ImageGalleryController {
private static final Logger logger = Logger.getLogger(ImageGalleryController.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED, IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED, IngestManager.IngestModuleEvent.FILE_DONE);
/*
* The file limit for image gallery. If the selected data source (or all
* data sources, if that option is selected) has more than this many files
@ -267,8 +268,8 @@ public final class ImageGalleryController {
dbTaskQueueSize.addListener(obs -> this.updateRegroupDisabled());
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, caseEventListener);
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
IngestManager.getInstance().addIngestModuleEventListener(ingestModuleEventListener);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, ingestModuleEventListener);
SwingUtilities.invokeLater(() -> {
topComponent = ImageGalleryTopComponent.getTopComponent();

View File

@ -35,6 +35,8 @@ OpenAction.multiUserDialog.Header=Multi-user Image Gallery
OpenAction.noControllerDialog.header=Cannot open Image Gallery
OpenAction.noControllerDialog.text=An initialization error ocurred.\nPlease see the log for details.
OpenAction.notAnalyzedDlg.msg=No image/video files available to display yet.\nPlease run FileType and EXIF ingest modules.
OpenAction.openTopComponent.error.message=An error occurred while attempting to open Image Gallery.
OpenAction.openTopComponent.error.title=Failed to open Image Gallery
OpenAction.stale.confDlg.msg=The image / video database may be out of date. Do you want to update and listen for further ingest results?\nChoosing 'yes' will update the database and enable listening to future ingests.
OpenAction.stale.confDlg.title=Image Gallery
OpenExternalViewerAction.displayName=External Viewer

View File

@ -34,6 +34,7 @@ import javafx.stage.Modality;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
@ -43,6 +44,7 @@ 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.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.Installer;
@ -292,13 +294,15 @@ public final class OpenAction extends CallableSystemAction {
);
}
@Messages({"OpenAction.openTopComponent.error.message=An error occurred while attempting to open Image Gallery.",
"OpenAction.openTopComponent.error.title=Failed to open Image Gallery"})
private void openTopComponent() {
SwingUtilities.invokeLater(() -> {
try {
ImageGalleryTopComponent.openTopComponent();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to open Image Gallery top component", ex); //NON-NLS}
// TODO (JIRA-5217): Give the user some feedback here
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.OpenAction_openTopComponent_error_message(), Bundle.OpenAction_openTopComponent_error_title(), JOptionPane.PLAIN_MESSAGE);
}
});
}

View File

@ -572,12 +572,12 @@ public final class DrawableDB {
String sql = "CREATE TABLE if not exists drawable_files " //NON-NLS
+ "( obj_id BIGINT PRIMARY KEY, " //NON-NLS
+ " data_source_obj_id BIGINT NOT NULL, "
+ " path VARCHAR(255), " //NON-NLS
+ " name VARCHAR(255), " //NON-NLS
+ " path TEXT, " //NON-NLS
+ " name TEXT, " //NON-NLS
+ " created_time integer, " //NON-NLS
+ " modified_time integer, " //NON-NLS
+ " make VARCHAR(255) DEFAULT NULL, " //NON-NLS
+ " model VARCHAR(255) DEFAULT NULL, " //NON-NLS
+ " make TEXT DEFAULT NULL, " //NON-NLS
+ " model TEXT DEFAULT NULL, " //NON-NLS
+ " analyzed integer DEFAULT 0)"; //NON-NLS
stmt.execute(sql);
} catch (SQLException ex) {
@ -588,7 +588,7 @@ public final class DrawableDB {
try {
String sql = "CREATE TABLE if not exists hash_sets " //NON-NLS
+ "( hash_set_id INTEGER primary key," //NON-NLS
+ " hash_set_name VARCHAR(255) UNIQUE NOT NULL)"; //NON-NLS
+ " hash_set_name TEXT UNIQUE NOT NULL)"; //NON-NLS
stmt.execute(sql);
} catch (SQLException ex) {
logger.log(Level.SEVERE, "Failed to create hash_sets table", ex); //NON-NLS
@ -692,8 +692,8 @@ public final class DrawableDB {
String tableSchema
= "( group_id " + autogenKeyType + " PRIMARY KEY, " //NON-NLS
+ " data_source_obj_id BIGINT DEFAULT 0, "
+ " value VARCHAR(255) not null, " //NON-NLS
+ " attribute VARCHAR(255) not null, " //NON-NLS
+ " value TEXT not null, " //NON-NLS
+ " attribute TEXT not null, " //NON-NLS
+ " is_analyzed integer DEFAULT 0, "
+ " UNIQUE(data_source_obj_id, value, attribute) )"; //NON-NLS

View File

@ -0,0 +1,143 @@
"""
Autopsy Forensic Browser
Copyright 2019 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.
"""
from java.io import File
from java.lang import Class
from java.lang import ClassNotFoundException
from java.lang import Long
from java.lang import String
from java.sql import ResultSet
from java.sql import SQLException
from java.sql import Statement
from java.util.logging import Level
from java.util import ArrayList
from org.apache.commons.codec.binary import Base64
from org.sleuthkit.autopsy.casemodule import Case
from org.sleuthkit.autopsy.coreutils import Logger
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
from org.sleuthkit.autopsy.coreutils import AppSQLiteDB
from org.sleuthkit.autopsy.coreutils import AppDBParserHelper
from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import MessageReadStatusEnum
from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection
from org.sleuthkit.autopsy.datamodel import ContentUtils
from org.sleuthkit.autopsy.ingest import IngestJobContext
from org.sleuthkit.datamodel import AbstractFile
from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
import traceback
import general
"""
Finds the SQLite DB for IMO, parses the DB for contacts & messages,
and adds artifacts to the case.
"""
class IMOAnalyzer(general.AndroidComponentAnalyzer):
def __init__(self):
self._logger = Logger.getLogger(self.__class__.__name__)
def analyze(self, dataSource, fileManager, context):
selfAccountAddress = None
accountDbs = AppSQLiteDB.findAppDatabases(dataSource, "accountdb.db", True, "com.imo.android.imous")
for accountDb in accountDbs:
try:
accountResultSet = accountDb.runQuery("SELECT uid, name FROM account")
if accountResultSet:
# We can determine the IMO user ID of the device owner.
# Therefore we can create and use a app account and use that
# as a 'self' account instead of a Device account
if not selfAccountAddress:
selfAccountAddress = Account.Address(accountResultSet.getString("uid"), accountResultSet.getString("name"))
except SQLException as ex:
self._logger.log(Level.SEVERE, "Error processing query result for account", ex)
finally:
accountDb.close()
friendsDbs = AppSQLiteDB.findAppDatabases(dataSource, "imofriends.db", True, "com.imo.android.imous")
for friendsDb in friendsDbs:
try:
friendsDBHelper = AppDBParserHelper("IMO Parser", friendsDb.getDBFile(),
Account.Type.IMO, Account.Type.IMO, selfAccountAddress )
contactsResultSet = friendsDb.runQuery("SELECT buid, name FROM friends")
if contactsResultSet is not None:
while contactsResultSet.next():
friendsDBHelper.addContact( contactsResultSet.getString("buid"), ## unique id for account
contactsResultSet.getString("name"), ## contact name
"", ## phone
"", ## home phone
"", ## mobile
"") ## email
queryString = "SELECT messages.buid AS buid, imdata, last_message, timestamp, message_type, message_read, name FROM messages "\
"INNER JOIN friends ON friends.buid = messages.buid"
messagesResultSet = friendsDb.runQuery(queryString)
if messagesResultSet is not None:
while messagesResultSet.next():
direction = ""
fromAddress = None
toAddress = None
name = messagesResultSet.getString("name")
uniqueId = messagesResultSet.getString("buid")
if (messagesResultSet.getInt("message_type") == 1):
direction = CommunicationDirection.INCOMING
fromAddress = Account.Address(uniqueId, name)
else:
direction = CommunicationDirection.OUTGOING
toAddress = Account.Address(uniqueId, name)
message_read = messagesResultSet.getInt("message_read")
if (message_read == 1):
msgReadStatus = MessageReadStatusEnum.READ
elif (message_read == 0):
msgReadStatus = MessageReadStatusEnum.UNREAD
else:
msgReadStatus = MessageReadStatusEnum.UNKNOWN
timeStamp = messagesResultSet.getLong("timestamp") / 1000000000
messageArtifact = friendsDBHelper.addMessage(
"IMO Message",
direction,
fromAddress,
toAddress,
timeStamp,
msgReadStatus,
"", # subject
messagesResultSet.getString("last_message"),
"") # thread id
# TBD: parse the imdata JSON structure to figure out if there is an attachment.
# If one exists, add the attachment as a derived file and a child of the message artifact.
except SQLException as ex:
self._logger.log(Level.WARNING, "Error processing query result for IMO friends", ex)
except TskCoreException as ex:
self._logger.log(Level.WARNING, "Failed to create AppDBParserHelper for adding artifacts.", ex)
finally:
friendsDb.close()

View File

@ -46,6 +46,7 @@ import googlemaplocation
import tangomessage
import textmessage
import wwfmessage
import imo
class AndroidModuleFactory(IngestModuleFactoryAdapter):
@ -87,7 +88,10 @@ class AndroidIngestModule(DataSourceIngestModule):
errors = []
fileManager = Case.getCurrentCase().getServices().getFileManager()
analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), cachelocation.CacheLocationAnalyzer()]
analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(),
tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(),
googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(),
cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer()]
self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers")
progressBar.switchToDeterminate(len(analyzers))

View File

@ -483,6 +483,7 @@ final class IngestSearchRunner {
if (progressGroup != null) {
progressGroup.setDisplayName(displayName + " " + NbBundle.getMessage(this.getClass(), "SearchRunner.doInBackGround.cancelMsg"));
}
progressGroup.finish();
return IngestSearchRunner.Searcher.this.cancel(true);
}
}, null);

View File

@ -1,3 +1,48 @@
---------------- VERSION 4.12.0 --------------
Collection
- Added ability to configure a USB drive to use new logical imager tool.
- Added logical imager tool that runs on a live Windows computer and saves results to a USB drive.
- Added ability to import logical imager results into Autopsy as a data source.
Ingest Modules:
- Changed file type detection so that Tika does not rely only on extension.
- Email ingest module assigns thread IDs to messages
- Android ingest modules store thread ID from their databases.
Content Viewers (lower right of UI):
- New “Text” viewer that consolidates previous Strings and “Indexed Text” viewers.
- New “Translation” panel was added to the new “Text” viewer.
- Added integration with Google and Bing translation (credentials required)
- Redesigned “Other Occurrences” viewer to have 4th column with details of selected item.
- Added Willi Ballentins “Registry Hive Viewer” panel to the “Application” viewer.
- Improved HTML viewer to use style sheets and better layout.
- Added ability to draw a box on a picture while tagging it.
Result Table (upper right of UI)
- Added paging to all views for faster loading of large data sets.
- Improved speed of displaying results when a column was sorted.
Reporting
- Portable cases can contain files marked as Interesting Items
- Portable cases can be compressed and chunked
- “Files - Text” report can use either tabs or commas as the delimiter
- “Files - Text” report better handles Unicode text.
- Added ability to create a CSV report for the contents of a table
- HTML report for tagged pictures includes a copy with the overlay box
Communications:
- Added Account Summary view
- Added Contacts panel to show all contacts associated with an account.
- Added Media panel to show media attachments associated with an account
- Added filter to show accounts if they involved with the most recent messages.
- Messages can be grouped by thread.
Auto Ingest
- New Test button was added to help diagnose permission and configuration issues.
Documentation:
- Created new Triage Standard Operating Procedure (SOP) section to the User Docs
---------------- VERSION 4.11.0 --------------
New Features:

View File

@ -236,6 +236,10 @@ abstract class Extract {
return moduleName;
}
protected String getRAModuleName() {
return RecentActivityExtracterModuleFactory.getModuleName();
}
/**
* Returns the state of foundData
* @return

View File

@ -54,6 +54,7 @@ import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.nio.file.Path;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
@ -66,8 +67,6 @@ import static java.util.TimeZone.getTimeZone;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -90,6 +89,36 @@ import org.sleuthkit.datamodel.TskCoreException;
})
class ExtractRegistry extends Extract {
private static final String USERNAME_KEY = "Username"; //NON-NLS
private static final String SID_KEY = "SID"; //NON-NLS
private static final String RID_KEY = "RID"; //NON-NLS
private static final String ACCOUNT_CREATED_KEY = "Account Created"; //NON-NLS
private static final String LAST_LOGIN_KEY = "Last Login Date"; //NON-NLS
private static final String LOGIN_COUNT_KEY = "Login Count"; //NON-NLS
private static final String FULL_NAME_KEY = "Full Name"; //NON-NLS
private static final String USER_COMMENT_KEY = "User Comment"; //NON-NLS
private static final String ACCOUNT_TYPE_KEY = "Account Type"; //NON-NLS
private static final String NAME_KEY = "Name"; //NON-NLS
private static final String PWD_RESET_KEY = "Pwd Rest Date"; //NON-NLS
private static final String PWD_FAILE_KEY = "Pwd Fail Date"; //NON-NLS
private static final String INTERNET_NAME_KEY = "InternetName"; //NON-NLS
private static final String PWD_DOES_NOT_EXPIRE_KEY = "Password does not expire"; //NON-NLS
private static final String ACCOUNT_DISABLED_KEY = "Account Disabled"; //NON-NLS
private static final String PWD_NOT_REQUIRED_KEY = "Password not required"; //NON-NLS
private static final String NORMAL_ACCOUNT_KEY = "Normal user account"; //NON-NLS
private static final String HOME_DIRECTORY_REQUIRED_KEY = "Home directory required";
private static final String TEMPORARY_DUPLICATE_ACCOUNT = "Temporary duplicate account";
private static final String MNS_LOGON_ACCOUNT_KEY = "MNS logon user account";
private static final String INTERDOMAIN_TRUST_ACCOUNT_KEY = "Interdomain trust account";
private static final String WORKSTATION_TRUST_ACCOUNT = "Workstation trust account";
private static final String SERVER_TRUST_ACCOUNT = "Server trust account";
private static final String ACCOUNT_AUTO_LOCKED = "Account auto locked";
private static final String PASSWORD_HINT = "Password Hint";
private static final String[] PASSWORD_SETTINGS_FLAGS = {PWD_DOES_NOT_EXPIRE_KEY, PWD_NOT_REQUIRED_KEY};
private static final String[] ACCOUNT_SETTINGS_FLAGS = {ACCOUNT_AUTO_LOCKED, HOME_DIRECTORY_REQUIRED_KEY, ACCOUNT_DISABLED_KEY};
private static final String[] ACCOUNT_TYPE_FLAGS = {NORMAL_ACCOUNT_KEY, SERVER_TRUST_ACCOUNT, WORKSTATION_TRUST_ACCOUNT, INTERDOMAIN_TRUST_ACCOUNT_KEY, MNS_LOGON_ACCOUNT_KEY, TEMPORARY_DUPLICATE_ACCOUNT};
final private static UsbDeviceIdMapper USB_MAPPER = new UsbDeviceIdMapper();
final private static String RIP_EXE = "rip.exe";
final private static String RIP_PL = "rip.pl";
@ -840,27 +869,29 @@ class ExtractRegistry extends Extract {
*/
private boolean parseSamPluginOutput(String regFilePath, AbstractFile regAbstractFile) {
File regfile = new File(regFilePath);
String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'");
regRipperTimeFormat.setTimeZone(getTimeZone("GMT"));
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(regfile))) {
// Read the file in and create a Document and elements
String userInfoSection = "User Information";
String previousLine = null;
String line = bufferedReader.readLine();
Set<UserInfo> userSet = new HashSet<>();
Set<Map<String, String>> userSet = new HashSet<>();
Map<String, List<String>> groupMap = null;
while (line != null) {
if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains(userInfoSection)) {
readUsers(bufferedReader, userSet);
}
if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains("Group Membership Information")) {
groupMap = readGroups(bufferedReader);
}
previousLine = line;
line = bufferedReader.readLine();
}
Map<String, UserInfo> userInfoMap = new HashMap<>();
Map<String, Map<String, String>> userInfoMap = new HashMap<>();
//load all the user info which was read into a map
for (UserInfo userInfo : userSet) {
userInfoMap.put(userInfo.getUserSid(), userInfo);
for (Map<String, String> userInfo : userSet) {
userInfoMap.put(userInfo.get(SID_KEY), userInfo);
}
//get all existing OS account artifacts
List<BlackboardArtifact> existingOsAccounts = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
@ -869,45 +900,19 @@ class ExtractRegistry extends Extract {
if (osAccount.getDataSource().getId() == regAbstractFile.getDataSourceObjectId()) {
BlackboardAttribute existingUserId = osAccount.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID));
if (existingUserId != null) {
UserInfo userInfo = userInfoMap.remove(existingUserId.getValueString().trim());
String userID = existingUserId.getValueString().trim();
Map<String, String> userInfo = userInfoMap.remove(userID);
//if the existing user id matches a user id which we parsed information for check if that information exists and if it doesn't add it
if (userInfo != null) {
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
if (userInfo.getAccountCreatedDate() != null && !userInfo.getAccountCreatedDate().equals(NEVER_DATE)) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
parentModuleName, regRipperTimeFormat.parse(userInfo.getAccountCreatedDate()).getTime() / MS_IN_SEC));
}
if (userInfo.getLastLoginDate() != null && !userInfo.getLastLoginDate().equals(NEVER_DATE)) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
parentModuleName, regRipperTimeFormat.parse(userInfo.getLastLoginDate()).getTime() / MS_IN_SEC));
}
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
parentModuleName, userInfo.getLoginCount()));
osAccount.addAttributes(bbattributes);
osAccount.addAttributes(getAttributesForAccount(userInfo, groupMap.get(userID), true));
}
}
}
}
//add remaining userinfos as accounts;
for (String userId : userInfoMap.keySet()) {
UserInfo userInfo = userInfoMap.get(userId);
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
for (Map<String, String> userInfo : userInfoMap.values()) {
BlackboardArtifact bbart = regAbstractFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
parentModuleName, userInfo.getUserName()));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID,
parentModuleName, userId));
if (userInfo.getAccountCreatedDate() != null && !userInfo.getAccountCreatedDate().equals(NEVER_DATE)) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
parentModuleName, regRipperTimeFormat.parse(userInfo.getAccountCreatedDate()).getTime() / MS_IN_SEC));
}
if (userInfo.getLastLoginDate() != null && !userInfo.getLastLoginDate().equals(NEVER_DATE)) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
parentModuleName, regRipperTimeFormat.parse(userInfo.getLastLoginDate()).getTime() / MS_IN_SEC));
}
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
parentModuleName, userInfo.getLoginCount()));
bbart.addAttributes(bbattributes);
bbart.addAttributes(getAttributesForAccount(userInfo, groupMap.get(userInfo.get(SID_KEY)), false));
// index the artifact for keyword search
postArtifact(bbart);
}
@ -925,6 +930,149 @@ class ExtractRegistry extends Extract {
return false;
}
/**
* Creates the attribute list for the given user information and group list.
*
* @param userInfo Map of key\value pairs of user information
* @param groupList List of the groups that user belongs
* @param existingUser
*
* @return List
*
* @throws ParseException
*/
Collection<BlackboardAttribute> getAttributesForAccount(Map<String, String> userInfo, List<String> groupList, boolean existingUser) throws ParseException {
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'");
regRipperTimeFormat.setTimeZone(getTimeZone("GMT"));
if (!existingUser) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID,
getRAModuleName(), userInfo.get(SID_KEY)));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
this.moduleName, userInfo.get(USERNAME_KEY)));
}
String value = userInfo.get(ACCOUNT_CREATED_KEY);
if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
getRAModuleName(), regRipperTimeFormat.parse(value).getTime() / MS_IN_SEC));
}
value = userInfo.get(LAST_LOGIN_KEY);
if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
getRAModuleName(), regRipperTimeFormat.parse(value).getTime() / MS_IN_SEC));
}
value = userInfo.get(LOGIN_COUNT_KEY);
if (value != null && !value.isEmpty()) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
getRAModuleName(), Integer.parseInt(value)));
}
value = userInfo.get(ACCOUNT_TYPE_KEY);
if (value != null && !value.isEmpty()) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE,
getRAModuleName(), value));
}
value = userInfo.get(USER_COMMENT_KEY);
if (value != null && !value.isEmpty()) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION,
getRAModuleName(), value));
}
value = userInfo.get(NAME_KEY);
if (value != null && !value.isEmpty()) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
getRAModuleName(), value));
}
value = userInfo.get(INTERNET_NAME_KEY);
if (value != null && !value.isEmpty()) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
getRAModuleName(), value));
}
value = userInfo.get(FULL_NAME_KEY);
if (value != null && !value.isEmpty()) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DISPLAY_NAME,
getRAModuleName(), value));
}
value = userInfo.get(PWD_RESET_KEY);
if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET,
getRAModuleName(), regRipperTimeFormat.parse(value).getTime() / MS_IN_SEC));
}
value = userInfo.get(PASSWORD_HINT);
if (value != null && !value.isEmpty()) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT,
getRAModuleName(), value));
}
value = userInfo.get(PWD_FAILE_KEY);
if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL,
getRAModuleName(), regRipperTimeFormat.parse(value).getTime() / MS_IN_SEC));
}
String settingString = "";
for (String setting : PASSWORD_SETTINGS_FLAGS) {
if (userInfo.containsKey(setting)) {
settingString += setting + ", ";
}
}
if (!settingString.isEmpty()) {
settingString = settingString.substring(0, settingString.length() - 2);
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS,
getRAModuleName(), settingString));
}
settingString = "";
for (String setting : ACCOUNT_SETTINGS_FLAGS) {
if (userInfo.containsKey(setting)) {
settingString += setting + ", ";
}
}
if (!settingString.isEmpty()) {
settingString = settingString.substring(0, settingString.length() - 2);
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS,
getRAModuleName(), settingString));
}
settingString = "";
for (String setting : ACCOUNT_TYPE_FLAGS) {
if (userInfo.containsKey(setting)) {
settingString += setting + ", ";
}
}
if (!settingString.isEmpty()) {
settingString = settingString.substring(0, settingString.length() - 2);
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_FLAG,
getRAModuleName(), settingString));
}
if (groupList != null && groupList.isEmpty()) {
String groups = "";
for (String group : groupList) {
groups += group + ", ";
}
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GROUPS,
getRAModuleName(), groups.substring(0, groups.length() - 2)));
}
return bbattributes;
}
/**
* Read the User Information section of the SAM regripper plugin's output
* and collect user account information from the file.
@ -936,42 +1084,125 @@ class ExtractRegistry extends Extract {
*
* @throws IOException
*/
private void readUsers(BufferedReader bufferedReader, Set<UserInfo> users) throws IOException {
String userNameLabel = "Username :";
String sidLabel = "SID :";
String accountCreatedLabel = "Account Created :";
String loginCountLabel = "Login Count :";
String lastLoginLabel = "Last Login Date :";
private void readUsers(BufferedReader bufferedReader, Set<Map<String, String>> users) throws IOException {
String line = bufferedReader.readLine();
//read until end of file or next section divider
String userName = "";
String user_rid = "";
while (line != null && !line.contains(SECTION_DIVIDER)) {
//when a user name field exists read the name and id number
if (line.contains(userNameLabel)) {
String userNameAndIdString = line.replace(userNameLabel, "");
if (line.contains(USERNAME_KEY)) {
String regx = USERNAME_KEY + "\\s*?:";
String userNameAndIdString = line.replaceAll(regx, "");
userName = userNameAndIdString.substring(0, userNameAndIdString.lastIndexOf('[')).trim();
} else if (line.contains(sidLabel) && !userName.isEmpty()) {
String sid = line.replace(sidLabel, "").trim();
UserInfo userInfo = new UserInfo(userName, sid);
user_rid = userNameAndIdString.substring(userNameAndIdString.lastIndexOf('['), userNameAndIdString.lastIndexOf(']'));
} else if (line.contains(SID_KEY) && !userName.isEmpty()) {
Map.Entry<String, String> entry = getSAMKeyValue(line);
HashMap<String, String> userInfo = new HashMap<>();
userInfo.put(USERNAME_KEY, userName);
userInfo.put(RID_KEY, user_rid);
userInfo.put(entry.getKey(), entry.getValue());
//continue reading this users information until end of file or a blank line between users
line = bufferedReader.readLine();
while (line != null && !line.isEmpty()) {
if (line.contains(accountCreatedLabel)) {
userInfo.setAccountCreatedDate(line.replace(accountCreatedLabel, "").trim());
} else if (line.contains(loginCountLabel)) {
userInfo.setLoginCount(Integer.parseInt(line.replace(loginCountLabel, "").trim()));
} else if (line.contains(lastLoginLabel)) {
userInfo.setLastLoginDate(line.replace(lastLoginLabel, "").trim());
}
entry = getSAMKeyValue(line);
userInfo.put(entry.getKey(), entry.getValue());
line = bufferedReader.readLine();
}
users.add(userInfo);
userName = "";
}
line = bufferedReader.readLine();
}
}
/**
* Maps the user groups to the sid that are a part of them.
*
* @param bufferedReader
*
* @return A map if sid and the groups they map too
*
* @throws IOException
*/
Map<String, List<String>> readGroups(BufferedReader bufferedReader) throws IOException {
Map<String, List<String>> groupMap = new HashMap<>();
String line = bufferedReader.readLine();
int userCount = 0;
String groupName = null;
while (line != null && !line.contains(SECTION_DIVIDER)) {
if (line.contains("Group Name")) {
String value = line.replaceAll("Group Name\\s*?:", "").trim();
groupName = (value.replaceAll("\\[\\d*?\\]", "")).trim();
int startIndex = value.indexOf('[');
int endIndex = value.indexOf(']');
if (startIndex != -1 && endIndex != -1) {
String countStr = value.substring(startIndex + 1, endIndex);
userCount = Integer.parseInt(countStr);
}
} else if (line.matches("Users\\s*?:")) {
for (int i = 0; i < userCount; i++) {
line = bufferedReader.readLine();
if (line != null) {
String sid = line.trim();
List<String> groupList = groupMap.get(sid);
if (groupList == null) {
groupList = new ArrayList<>();
groupMap.put(sid, groupList);
}
groupList.add(groupName);
}
}
groupName = null;
}
line = bufferedReader.readLine();
}
return groupMap;
}
/**
* Gets the key value from user account strings of the format
* key:value or
* --> value
*
* @param line String to parse
*
* @return key value pair
*/
private Map.Entry<String, String> getSAMKeyValue(String line) {
int index = line.indexOf(':');
Map.Entry<String, String> returnValue = null;
String key = null;
String value = null;
if (index != -1) {
key = line.substring(0, index).trim();
if (index + 1 < line.length()) {
value = line.substring(index + 1).trim();
} else {
value = "";
}
} else if (line.contains("-->")) {
key = line.replace("-->", "").trim();
value = "true";
}
if (key != null) {
returnValue = new AbstractMap.SimpleEntry<>(key, value);
}
return returnValue;
}
@Override
public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
this.dataSource = dataSource;
@ -990,101 +1221,4 @@ class ExtractRegistry extends Extract {
public String autopsyPlugins = "";
public String fullPlugins = "";
}
/**
* Class for organizing information associated with a TSK_OS_ACCOUNT before
* the artifact is created.
*/
private class UserInfo {
private final String userName;
private final String userSid;
private String lastLoginDate;
private String accountCreatedDate;
private int loginCount = 0;
/**
* Create a UserInfo object
*
* @param name - the os user account name
* @param userSidString - the SID for the user account
*/
private UserInfo(String name, String userSidString) {
userName = name;
userSid = userSidString;
}
/**
* Get the user name.
*
* @return the userName
*/
String getUserName() {
return userName;
}
/**
* Get the user SID.
*
* @return the user SID
*/
String getUserSid() {
return userSid;
}
/**
* Get the last login date for the user
*
* @return the lastLoginDate
*/
String getLastLoginDate() {
return lastLoginDate;
}
/**
* Set the last login date for the users
*
* @param lastLoginDate the lastLoginDate to set
*/
void setLastLoginDate(String lastLoginDate) {
this.lastLoginDate = lastLoginDate;
}
/**
* Get the account creation date.
*
* @return the accountCreatedDate
*/
String getAccountCreatedDate() {
return accountCreatedDate;
}
/**
* Set the account creation date.
*
* @param accountCreatedDate the accountCreatedDate to set
*/
void setAccountCreatedDate(String accountCreatedDate) {
this.accountCreatedDate = accountCreatedDate;
}
/**
* Get the number of times the user logged in.
*
* @return the loginCount
*/
int getLoginCount() {
return loginCount;
}
/**
* Set the number of times the user logged in.
*
* @param loginCount the loginCount to set
*/
void setLoginCount(int loginCount) {
this.loginCount = loginCount;
}
}
}

View File

@ -31,8 +31,8 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.Level;
import javax.imageio.ImageIO;
import javax.swing.JDialog;
import javax.swing.text.JTextComponent;
@ -66,7 +66,7 @@ import org.sleuthkit.datamodel.TskData;
public class AutopsyTestCases {
private static final Logger logger = Logger.getLogger(AutopsyTestCases.class.getName());
private static final Logger logger = Logger.getLogger(AutopsyTestCases.class.getName()); // DO NOT USE AUTOPSY LOGGER
private long start;
/**

View File

@ -40,7 +40,7 @@ import org.netbeans.junit.NbModuleSuite;
*/
public class RegressionTest extends TestCase {
private static final Logger logger = Logger.getLogger(RegressionTest.class.getName());
private static final Logger logger = Logger.getLogger(RegressionTest.class.getName()); // DO NOT USE AUTOPSY LOGGER
private static final AutopsyTestCases autopsyTests = new AutopsyTestCases(Boolean.parseBoolean(System.getProperty("isMultiUser")));
/**

View File

@ -77,7 +77,7 @@
</delete>
<delete includeemptydirs="true" failonerror="false">
<fileset dir="${basedir}/docs/doxygen-dev/dev-docs" includes="**/*"/>
<fileset dir="${basedir}/docs/doxygen-dev/build-docs" includes="**/*"/>
</delete>
</target>
@ -265,7 +265,7 @@
<fileset dir="${basedir}/docs/doxygen-user/user-docs" includes="**/*"/>
</delete>
<delete includeemptydirs="true" failonerror="false">
<fileset dir="${basedir}/docs/doxygen-dev/dev-docs" includes="**/*"/>
<fileset dir="${basedir}/docs/doxygen-dev/build-docs" includes="**/*"/>
</delete>
<!-- Generate new -->

View File

@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = dev-docs
OUTPUT_DIRECTORY = build-docs
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and

View File

@ -322,6 +322,7 @@ class TskDbDiff(object):
id_fs_info_table = build_id_fs_info_table(conn.cursor(), isMultiUser)
id_objects_table = build_id_objects_table(conn.cursor(), isMultiUser)
id_artifact_types_table = build_id_artifact_types_table(conn.cursor(), isMultiUser)
id_legacy_artifact_types = build_id_legacy_artifact_types_table(conn.cursor(), isMultiUser)
id_reports_table = build_id_reports_table(conn.cursor(), isMultiUser)
id_images_table = build_id_image_names_table(conn.cursor(), isMultiUser)
id_obj_path_table = build_id_obj_path_table(id_files_table, id_objects_table, id_artifact_types_table, id_reports_table, id_images_table)
@ -347,7 +348,7 @@ class TskDbDiff(object):
if 'INSERT INTO image_gallery_groups_seen' in dump_line:
dump_line = ''
continue;
dump_line = normalize_db_entry(dump_line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table, id_reports_table, id_images_table)
dump_line = normalize_db_entry(dump_line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table, id_reports_table, id_images_table, id_legacy_artifact_types)
db_log.write('%s\n' % dump_line)
dump_line = ''
postgreSQL_db.close()
@ -361,7 +362,7 @@ class TskDbDiff(object):
for line in conn.iterdump():
if 'INSERT INTO "image_gallery_groups_seen"' in line:
continue
line = normalize_db_entry(line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table, id_reports_table, id_images_table)
line = normalize_db_entry(line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table, id_reports_table, id_images_table, id_legacy_artifact_types)
db_log.write('%s\n' % line)
# Now sort the file
srtcmdlst = ["sort", dump_file, "-o", dump_file]
@ -414,7 +415,7 @@ class PGSettings(object):
return self.password
def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info_table, objects_table, reports_table, images_table):
def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info_table, objects_table, reports_table, images_table, artifact_table):
""" Make testing more consistent and reasonable by doctoring certain db entries.
Args:
@ -591,10 +592,15 @@ def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info
# replace object ids with information that is deterministic
file_obj_id = int(fields_list[5])
object_id = int(fields_list[4])
legacy_artifact_id = 'NULL'
if (fields_list[6] != 'NULL'):
legacy_artifact_id = int(fields_list[6])
if file_obj_id != 'NULL' and file_obj_id in files_table.keys():
fields_list[5] = files_table[file_obj_id]
if object_id != 'NULL' and object_id in files_table.keys():
fields_list[4] = files_table[object_id]
if legacy_artifact_id != 'NULL' and legacy_artifact_id in artifact_table.keys():
fields_list[6] = artifact_table[legacy_artifact_id]
newLine = ('INSERT INTO "tsk_event_descriptions" VALUES(' + ','.join(fields_list[1:]) + ');') # remove report_id
return newLine
else:
@ -689,6 +695,17 @@ def build_id_artifact_types_table(db_cursor, isPostgreSQL):
mapping = dict([(row[0], row[1]) for row in sql_select_execute(db_cursor, isPostgreSQL, "SELECT blackboard_artifacts.artifact_obj_id, blackboard_artifact_types.type_name FROM blackboard_artifacts INNER JOIN blackboard_artifact_types ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id ")])
return mapping
def build_id_legacy_artifact_types_table(db_cursor, isPostgreSQL):
"""Build the map of legacy artifact ids to artifact type.
Args:
db_cursor: the database cursor
"""
# for each row in the db, take the legacy artifact id then create a tuple in the dictionary
# with the artifact id as the key and artifact type as the value
mapping = dict([(row[0], row[1]) for row in sql_select_execute(db_cursor, isPostgreSQL, "SELECT blackboard_artifacts.artifact_id, blackboard_artifact_types.type_name FROM blackboard_artifacts INNER JOIN blackboard_artifact_types ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id ")])
return mapping
def build_id_reports_table(db_cursor, isPostgreSQL):
"""Build the map of report object ids to report path.

View File

@ -1,4 +1,4 @@
MboxParser.handleAttch.noOpenCase.errMsg=Exception while getting open case.
MimeJ4MessageParser.handleAttch.noOpenCase.errMsg=Exception while getting open case.
OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Email Parser ingest module.\n\nThe module extracts MBOX and PST e-mail files and posts the results to the blackboard.\nIt knows about the Thunderbird folder structure for MBOX files.
OpenIDE-Module-Name=Email Parser

View File

@ -0,0 +1,72 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 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.thunderbirdparser;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.dom.Message;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ReadContentInputStream;
/**
* EML file parser. An .eml file contains a single email message.
*
*/
class EMLParser extends MimeJ4MessageParser {
/**
* If the extention of the AbstractFile is eml and 'To:' is found close to
* the beginning of the file, then its probably an eml file.
*
* @param abFile AbstractFile to test
* @param buffer A byte buffer of the beginning of the file.
*
* @return True, if we think this is an eml file, false otherwise.
*/
static boolean isEMLFile(AbstractFile abFile, byte[] buffer) {
String ext = abFile.getNameExtension();
boolean isEMLFile = ext != null && ext.equals("eml");
if (isEMLFile) {
isEMLFile = (new String(buffer)).contains("To:"); //NON-NLS
}
return isEMLFile;
}
/**
*
* @param sourceFile AbstractFile source file for eml message
* @param localPath The local path to the eml file
*
* @return EmailMessage object for message in eml file
*
* @throws FileNotFoundException
* @throws IOException
* @throws MimeException
*/
static EmailMessage parse(AbstractFile sourceFile) throws FileNotFoundException, IOException, MimeException {
try (ReadContentInputStream fis = new ReadContentInputStream(sourceFile)) {
EMLParser parser = new EMLParser();
parser.setLocalPath(sourceFile.getParentPath());
Message mimeMsg = parser.getMessageBuilder().parseMessage(fis);
return parser.extractEmail(mimeMsg, "", sourceFile.getId());
}
}
}

Some files were not shown because too many files have changed in this diff Show More