mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 19:14:55 +00:00
Merge branch 'file-search' of https://github.com/sleuthkit/autopsy into 5368-GroupByPathModifications
This commit is contained in:
commit
aa01285223
3
.gitignore
vendored
3
.gitignore
vendored
@ -82,7 +82,8 @@ hs_err_pid*.log
|
|||||||
/RecentActivity/release/
|
/RecentActivity/release/
|
||||||
/CentralRepository/release/
|
/CentralRepository/release/
|
||||||
|
|
||||||
/.idea/
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
*.img
|
*.img
|
||||||
*.vhd
|
*.vhd
|
||||||
|
49
.travis.yml
49
.travis.yml
@ -1,24 +1,65 @@
|
|||||||
language: java
|
language: java
|
||||||
sudo: required
|
sudo: required
|
||||||
dist: trusty
|
dist: bionic
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- TSK_HOME=$TRAVIS_BUILD_DIR/sleuthkit/sleuthkit
|
- 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:
|
python:
|
||||||
- "2.7"
|
- "2.7"
|
||||||
jdk:
|
|
||||||
- oraclejdk8
|
|
||||||
before_install:
|
before_install:
|
||||||
- git clone https://github.com/sleuthkit/sleuthkit.git sleuthkit/sleuthkit
|
- git clone https://github.com/sleuthkit/sleuthkit.git sleuthkit/sleuthkit
|
||||||
- python setupSleuthkitBranch.py
|
- python setupSleuthkitBranch.py
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- sudo apt-get install testdisk
|
- sudo apt-get install testdisk
|
||||||
- cd sleuthkit/sleuthkit
|
- 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:
|
script:
|
||||||
- set -e
|
- 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'
|
- echo "Building Autopsy..." && echo -en 'travis_fold:start:script.build\\r'
|
||||||
- cd $TRAVIS_BUILD_DIR/
|
- cd $TRAVIS_BUILD_DIR/
|
||||||
- ant build
|
- ant build
|
||||||
|
@ -22,12 +22,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
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.LocalFilesDataSource;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskDataException;
|
import org.sleuthkit.datamodel.TskDataException;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2017 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -24,6 +24,7 @@ import java.beans.PropertyChangeListener;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
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 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,
|
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);
|
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 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 String PERIODIC_TASK_THREAD_NAME = "collab-monitor-periodic-tasks-%d"; //NON-NLS
|
||||||
private static final long HEARTBEAT_INTERVAL_MINUTES = 1;
|
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.
|
* Create a local tasks manager to track and broadcast local tasks.
|
||||||
*/
|
*/
|
||||||
localTasksManager = new LocalTasksManager();
|
localTasksManager = new LocalTasksManager();
|
||||||
IngestManager.getInstance().addIngestJobEventListener(localTasksManager);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, localTasksManager);
|
||||||
Case.addEventTypeSubscriber(CASE_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
|
* @return A mapping of task IDs to current tasks
|
||||||
*/
|
*/
|
||||||
Map<Long, Task> getCurrentTasks() {
|
Map<Long, Task> getCurrentTasks() {
|
||||||
return currentTasks;
|
return Collections.unmodifiableMap(currentTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ import java.text.DateFormat;
|
|||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
@ -44,6 +46,7 @@ import org.sleuthkit.datamodel.DataSource;
|
|||||||
public final class IngestJobInfoPanel extends javax.swing.JPanel {
|
public final class IngestJobInfoPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(IngestJobInfoPanel.class.getName());
|
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 List<IngestJobInfo> ingestJobs;
|
||||||
private final List<IngestJobInfo> ingestJobsForSelectedDataSource = new ArrayList<>();
|
private final List<IngestJobInfo> ingestJobsForSelectedDataSource = new ArrayList<>();
|
||||||
private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel();
|
private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel();
|
||||||
@ -69,7 +72,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
|
|||||||
this.ingestModuleTable.setModel(this.ingestModuleTableModel);
|
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())
|
if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.STARTED.toString())
|
||||||
|| evt.getPropertyName().equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
|| evt.getPropertyName().equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||||
|| evt.getPropertyName().equals(IngestManager.IngestJobEvent.COMPLETED.toString())) {
|
|| evt.getPropertyName().equals(IngestManager.IngestJobEvent.COMPLETED.toString())) {
|
||||||
|
@ -30,7 +30,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
@ -22,7 +22,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
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.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -24,7 +24,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.CaseDbAccessManager;
|
import org.sleuthkit.datamodel.CaseDbAccessManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.CaseDbAccessManager;
|
import org.sleuthkit.datamodel.CaseDbAccessManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.logging.Level;
|
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.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.datamodel.CaseDbAccessManager;
|
import org.sleuthkit.datamodel.CaseDbAccessManager;
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="byMimeTypeLabel">
|
<Component class="javax.swing.JLabel" name="byMimeTypeLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryCountsPanel.byMimeTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
@ -104,14 +104,14 @@
|
|||||||
<Component class="javax.swing.JLabel" name="byCategoryLabel">
|
<Component class="javax.swing.JLabel" name="byCategoryLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryCountsPanel.byCategoryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryCountsPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
|
@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
import javax.swing.table.DefaultTableCellRenderer;
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="displayNameLabel">
|
<Component class="javax.swing.JLabel" name="displayNameLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.displayNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="originalNameLabel">
|
<Component class="javax.swing.JLabel" name="originalNameLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.originalNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -76,7 +76,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="sha1HashValue">
|
<Component class="javax.swing.JLabel" name="sha1HashValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha1HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -88,10 +88,10 @@
|
|||||||
<Component class="javax.swing.JLabel" name="operatingSystemValue">
|
<Component class="javax.swing.JLabel" name="operatingSystemValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.operatingSystemValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.operatingSystemValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -103,7 +103,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="displayNameValue">
|
<Component class="javax.swing.JLabel" name="displayNameValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.displayNameValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -115,7 +115,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="sha256HashValue">
|
<Component class="javax.swing.JLabel" name="sha256HashValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha256HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -127,7 +127,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="originalNameValue">
|
<Component class="javax.swing.JLabel" name="originalNameValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.originalNameValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -139,10 +139,10 @@
|
|||||||
<Component class="javax.swing.JLabel" name="deviceIdValue">
|
<Component class="javax.swing.JLabel" name="deviceIdValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -179,7 +179,7 @@
|
|||||||
<TableColumnModel selectionModel="0">
|
<TableColumnModel selectionModel="0">
|
||||||
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
|
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
|
||||||
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.filePathsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Title>
|
</Title>
|
||||||
<Editor/>
|
<Editor/>
|
||||||
<Renderer/>
|
<Renderer/>
|
||||||
@ -196,7 +196,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="dataSourceUsageValue">
|
<Component class="javax.swing.JLabel" name="dataSourceUsageValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.dataSourceUsageValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -208,7 +208,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="timeZoneValue">
|
<Component class="javax.swing.JLabel" name="timeZoneValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.timeZoneValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -220,10 +220,10 @@
|
|||||||
<Component class="javax.swing.JLabel" name="imageTypeValue">
|
<Component class="javax.swing.JLabel" name="imageTypeValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -235,10 +235,10 @@
|
|||||||
<Component class="javax.swing.JLabel" name="md5HashValue">
|
<Component class="javax.swing.JLabel" name="md5HashValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashValue.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -250,7 +250,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="sectorSizeValue">
|
<Component class="javax.swing.JLabel" name="sectorSizeValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sectorSizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -262,7 +262,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="sizeValue">
|
<Component class="javax.swing.JLabel" name="sizeValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -274,7 +274,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="filePathsLabel">
|
<Component class="javax.swing.JLabel" name="filePathsLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.filePathsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -286,7 +286,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="sha256HashLabel">
|
<Component class="javax.swing.JLabel" name="sha256HashLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha256HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -298,7 +298,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="sha1HashLabel">
|
<Component class="javax.swing.JLabel" name="sha1HashLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sha1HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -310,7 +310,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="md5HashLabel">
|
<Component class="javax.swing.JLabel" name="md5HashLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.md5HashLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -322,7 +322,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="sectorSizeLabel">
|
<Component class="javax.swing.JLabel" name="sectorSizeLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sectorSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -334,7 +334,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="sizeLabel">
|
<Component class="javax.swing.JLabel" name="sizeLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.sizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -346,7 +346,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="imageTypeLabel">
|
<Component class="javax.swing.JLabel" name="imageTypeLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.imageTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -358,7 +358,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="acquisitionDetailsLabel">
|
<Component class="javax.swing.JLabel" name="acquisitionDetailsLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.acquisitionDetailsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -370,7 +370,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="timeZoneLabel">
|
<Component class="javax.swing.JLabel" name="timeZoneLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -382,7 +382,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="dataSourceUsageLabel">
|
<Component class="javax.swing.JLabel" name="dataSourceUsageLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.dataSourceUsageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -394,7 +394,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="deviceIdLabel">
|
<Component class="javax.swing.JLabel" name="deviceIdLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.deviceIdLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -427,7 +427,7 @@
|
|||||||
</Property>
|
</Property>
|
||||||
<Property name="rows" type="int" value="4"/>
|
<Property name="rows" type="int" value="4"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.acquisitionDetailsTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
<Border info="null"/>
|
<Border info="null"/>
|
||||||
@ -469,7 +469,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="unallocatedSizeLabel">
|
<Component class="javax.swing.JLabel" name="unallocatedSizeLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.unallocatedSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
@ -481,7 +481,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="unallocatedSizeValue">
|
<Component class="javax.swing.JLabel" name="unallocatedSizeValue">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryDetailsPanel.unallocatedSizeValue.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
|
@ -22,7 +22,7 @@ import java.text.DecimalFormat;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import javax.swing.table.DefaultTableModel;
|
import javax.swing.table.DefaultTableModel;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
|
@ -20,9 +20,11 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary;
|
|||||||
|
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.Set;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel;
|
import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel;
|
||||||
@ -38,6 +40,7 @@ import org.sleuthkit.datamodel.IngestJobInfo;
|
|||||||
final class DataSourceSummaryDialog extends javax.swing.JDialog implements Observer {
|
final class DataSourceSummaryDialog extends javax.swing.JDialog implements Observer {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
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 DataSourceSummaryCountsPanel countsPanel;
|
||||||
private final DataSourceSummaryDetailsPanel detailsPanel;
|
private final DataSourceSummaryDetailsPanel detailsPanel;
|
||||||
private final DataSourceBrowser dataSourcesPanel;
|
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
|
//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) {
|
if (evt instanceof DataSourceAnalysisCompletedEvent) {
|
||||||
DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt;
|
DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt;
|
||||||
if (dsEvent.getResult() == Reason.ANALYSIS_COMPLETED) {
|
if (dsEvent.getResult() == Reason.ANALYSIS_COMPLETED) {
|
||||||
|
@ -25,8 +25,10 @@ import static java.lang.Boolean.FALSE;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -38,10 +40,8 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
|
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.centralrepository.datamodel.EamDbException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||||
@ -51,10 +51,13 @@ import org.sleuthkit.datamodel.Blackboard;
|
|||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT;
|
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
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_ASSOCIATED_ARTIFACT;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
|
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.Content;
|
||||||
import org.sleuthkit.datamodel.Image;
|
import org.sleuthkit.datamodel.Image;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
@ -68,17 +71,18 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
public class IngestEventsListener {
|
public class IngestEventsListener {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName());
|
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();
|
private static final String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name();
|
||||||
|
|
||||||
final Collection<String> recentlyAddedCeArtifacts = new LinkedHashSet<>();
|
|
||||||
private static int correlationModuleInstanceCount;
|
private static int correlationModuleInstanceCount;
|
||||||
private static boolean flagNotableItems;
|
private static boolean flagNotableItems;
|
||||||
private static boolean flagSeenDevices;
|
private static boolean flagSeenDevices;
|
||||||
private static boolean createCrProperties;
|
private static boolean createCrProperties;
|
||||||
private final ExecutorService jobProcessingExecutor;
|
|
||||||
private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d";
|
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 pcl1 = new IngestModuleEventListener();
|
||||||
private final PropertyChangeListener pcl2 = new IngestJobEventListener();
|
private final PropertyChangeListener pcl2 = new IngestJobEventListener();
|
||||||
|
final Collection<String> recentlyAddedCeArtifacts = new LinkedHashSet<>();
|
||||||
|
|
||||||
IngestEventsListener() {
|
IngestEventsListener() {
|
||||||
jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(INGEST_EVENT_THREAD_NAME).build());
|
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.
|
* Add all of our Ingest Event Listeners to the IngestManager Instance.
|
||||||
*/
|
*/
|
||||||
public void installListeners() {
|
public void installListeners() {
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl1);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl1);
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl2);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -348,8 +352,7 @@ public class IngestEventsListener {
|
|||||||
String dataSourceName = "";
|
String dataSourceName = "";
|
||||||
long dataSourceObjectId = -1;
|
long dataSourceObjectId = -1;
|
||||||
try {
|
try {
|
||||||
dataSource = ((DataSourceAnalysisCompletedEvent) event).getDataSource();
|
dataSource = ((DataSourceAnalysisEvent) event).getDataSource();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only care about Images for the purpose of
|
* We only care about Images for the purpose of
|
||||||
* updating hash values.
|
* updating hash values.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Central Repository
|
* Central Repository
|
||||||
*
|
*
|
||||||
* Copyright 2015-2018 Basis Technology Corp.
|
* Copyright 2015-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -24,6 +24,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.Set;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import org.netbeans.spi.options.OptionsPanelController;
|
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 long serialVersionUID = 1L;
|
||||||
private static final Logger logger = Logger.getLogger(GlobalSettingsPanel.class.getName());
|
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;
|
private final IngestJobEventPropertyChangeListener ingestJobEventListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,7 +73,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addIngestJobEventsListener() {
|
private void addIngestJobEventsListener() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
|
||||||
ingestStateUpdated(Case.isCaseOpen());
|
ingestStateUpdated(Case.isCaseOpen());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,9 @@ import java.nio.file.Paths;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.netbeans.spi.sendopts.OptionProcessor;
|
import org.netbeans.spi.sendopts.OptionProcessor;
|
||||||
import org.openide.LifecycleManager;
|
import org.openide.LifecycleManager;
|
||||||
@ -65,6 +67,7 @@ import org.sleuthkit.datamodel.Content;
|
|||||||
public class CommandLineIngestManager {
|
public class CommandLineIngestManager {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CommandLineIngestManager.class.getName());
|
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;
|
private Path rootOutputDirectory;
|
||||||
|
|
||||||
public CommandLineIngestManager() {
|
public CommandLineIngestManager() {
|
||||||
@ -100,6 +103,7 @@ public class CommandLineIngestManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOGGER.log(Level.INFO, "Job processing task started");
|
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...");
|
System.out.println("Unable to ingest data source " + dataSourcePath + ". Exiting...");
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
/*
|
/*
|
||||||
* Unexpected runtime exceptions firewall. This task is designed to
|
* Unexpected runtime exceptions firewall. This task is
|
||||||
* be able to be run in an executor service thread pool without
|
* designed to be able to be run in an executor service
|
||||||
* calling get() on the task's Future<Void>, so this ensures that
|
* thread pool without calling get() on the task's
|
||||||
* such errors get logged.
|
* Future<Void>, so this ensures that such errors get
|
||||||
|
* logged.
|
||||||
*/
|
*/
|
||||||
LOGGER.log(Level.SEVERE, "Unexpected error while ingesting data source " + dataSourcePath, ex);
|
LOGGER.log(Level.SEVERE, "Unexpected error while ingesting data source " + dataSourcePath, ex);
|
||||||
System.out.println("Unexpected error while ingesting data source " + dataSourcePath + ". Exiting...");
|
System.out.println("Unexpected error while ingesting data source " + dataSourcePath + ". Exiting...");
|
||||||
@ -229,6 +234,7 @@ public class CommandLineIngestManager {
|
|||||||
* object.
|
* object.
|
||||||
*
|
*
|
||||||
* @param dataSource DataSource object
|
* @param dataSource DataSource object
|
||||||
|
*
|
||||||
* @return object ID
|
* @return object ID
|
||||||
*/
|
*/
|
||||||
private Long getDataSourceId(AutoIngestDataSource dataSource) {
|
private Long getDataSourceId(AutoIngestDataSource dataSource) {
|
||||||
@ -268,12 +274,11 @@ public class CommandLineIngestManager {
|
|||||||
* @param dataSource The data source.
|
* @param dataSource The data source.
|
||||||
*
|
*
|
||||||
* @throws
|
* @throws
|
||||||
* AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
|
* AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException if
|
||||||
* if there was a DSP processing error
|
* there was a DSP processing error
|
||||||
*
|
*
|
||||||
* @throws InterruptedException if the thread running the job processing
|
* @throws InterruptedException if the thread running the job processing
|
||||||
* task is interrupted while blocked, i.e., if auto ingest is shutting
|
* task is interrupted while blocked, i.e., if auto ingest is shutting down.
|
||||||
* down.
|
|
||||||
*/
|
*/
|
||||||
private void runDataSourceProcessor(Case caseForJob, AutoIngestDataSource dataSource) throws InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException {
|
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());
|
LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", dataSource.getPath());
|
||||||
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
|
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
|
||||||
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
|
||||||
try {
|
try {
|
||||||
synchronized (ingestLock) {
|
synchronized (ingestLock) {
|
||||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(UserPreferences.getCommandLineModeIngestModuleContextString());
|
IngestJobSettings ingestJobSettings = new IngestJobSettings(UserPreferences.getCommandLineModeIngestModuleContextString());
|
||||||
@ -461,8 +466,8 @@ public class CommandLineIngestManager {
|
|||||||
* for a case.
|
* for a case.
|
||||||
*
|
*
|
||||||
* @param folderToSearch The folder to be searched.
|
* @param folderToSearch The folder to be searched.
|
||||||
* @param caseName The name of the case for which a case folder is to be
|
* @param caseName The name of the case for which a case folder is
|
||||||
* found.
|
* to be found.
|
||||||
*
|
*
|
||||||
* @return The path of the case folder, or null if it is not found.
|
* @return The path of the case folder, or null if it is not found.
|
||||||
*/
|
*/
|
||||||
|
@ -23,7 +23,7 @@ import java.util.HashSet;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
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.api.sendopts.CommandException;
|
||||||
import org.netbeans.spi.sendopts.Env;
|
import org.netbeans.spi.sendopts.Env;
|
||||||
import org.netbeans.spi.sendopts.Option;
|
import org.netbeans.spi.sendopts.Option;
|
||||||
|
@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.commonpropertiessearch;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
|
@ -24,7 +24,7 @@ import java.util.Enumeration;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
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.TableColumn;
|
||||||
import javax.swing.table.TableColumnModel;
|
import javax.swing.table.TableColumnModel;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2017-2018 Basis Technology Corp.
|
* Copyright 2017-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -34,6 +34,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -81,7 +82,8 @@ final public class FiltersPanel extends JPanel {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Logger logger = Logger.getLogger(FiltersPanel.class.getName());
|
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.
|
* 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);
|
updateFilters(true);
|
||||||
UserPreferences.addChangeListener(preferenceChangeEvent -> {
|
UserPreferences.addChangeListener(preferenceChangeEvent -> {
|
||||||
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME) ||
|
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)
|
||||||
preferenceChangeEvent.getKey().equals(UserPreferences.TIME_ZONE_FOR_DISPLAYS)) {
|
|| preferenceChangeEvent.getKey().equals(UserPreferences.TIME_ZONE_FOR_DISPLAYS)) {
|
||||||
updateTimeZone();
|
updateTimeZone();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -166,8 +168,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
&& (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|
&& (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_CONTACT.getTypeID()
|
||||||
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
||||||
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()))
|
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())) {
|
||||||
{
|
|
||||||
updateFilters(true);
|
updateFilters(true);
|
||||||
needsRefresh = true;
|
needsRefresh = true;
|
||||||
validateFilters();
|
validateFilters();
|
||||||
@ -177,8 +178,8 @@ final public class FiltersPanel extends JPanel {
|
|||||||
|
|
||||||
this.ingestJobListener = pce -> {
|
this.ingestJobListener = pce -> {
|
||||||
String eventType = pce.getPropertyName();
|
String eventType = pce.getPropertyName();
|
||||||
if (eventType.equals(COMPLETED.toString()) &&
|
if (eventType.equals(COMPLETED.toString())
|
||||||
updateFilters(true)) {
|
&& updateFilters(true)) {
|
||||||
|
|
||||||
needsRefresh = true;
|
needsRefresh = true;
|
||||||
validateFilters();
|
validateFilters();
|
||||||
@ -210,14 +211,14 @@ final public class FiltersPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateLimitValue() {
|
private boolean validateLimitValue() {
|
||||||
String selectedValue = (String)limitComboBox.getSelectedItem();
|
String selectedValue = (String) limitComboBox.getSelectedItem();
|
||||||
if(selectedValue.trim().equalsIgnoreCase("all")) {
|
if (selectedValue.trim().equalsIgnoreCase("all")) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
try{
|
try {
|
||||||
int value = Integer.parseInt(selectedValue);
|
int value = Integer.parseInt(selectedValue);
|
||||||
return value > 0;
|
return value > 0;
|
||||||
} catch( NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,8 +251,8 @@ final public class FiltersPanel extends JPanel {
|
|||||||
@Override
|
@Override
|
||||||
public void addNotify() {
|
public void addNotify() {
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, ingestListener);
|
||||||
IngestManager.getInstance().addIngestJobEventListener(ingestJobListener);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobListener);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
|
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
|
||||||
//clear the device filter widget when the case changes.
|
//clear the device filter widget when the case changes.
|
||||||
devicesMap.clear();
|
devicesMap.clear();
|
||||||
@ -339,7 +340,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
|
|
||||||
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
|
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
|
||||||
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
|
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
|
||||||
if(devicesMap.containsKey(dataSource.getDeviceId())) {
|
if (devicesMap.containsKey(dataSource.getDeviceId())) {
|
||||||
continue;
|
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);
|
logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(newOneFound) {
|
if (newOneFound) {
|
||||||
devicesListPane.revalidate();
|
devicesListPane.revalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,12 +374,12 @@ final public class FiltersPanel extends JPanel {
|
|||||||
public void setFilters(CommunicationsFilter commFilter) {
|
public void setFilters(CommunicationsFilter commFilter) {
|
||||||
List<CommunicationsFilter.SubFilter> subFilters = commFilter.getAndFilters();
|
List<CommunicationsFilter.SubFilter> subFilters = commFilter.getAndFilters();
|
||||||
subFilters.forEach(subFilter -> {
|
subFilters.forEach(subFilter -> {
|
||||||
if( subFilter instanceof DeviceFilter ) {
|
if (subFilter instanceof DeviceFilter) {
|
||||||
setDeviceFilter((DeviceFilter)subFilter);
|
setDeviceFilter((DeviceFilter) subFilter);
|
||||||
} else if( subFilter instanceof AccountTypeFilter) {
|
} else if (subFilter instanceof AccountTypeFilter) {
|
||||||
setAccountTypeFilter((AccountTypeFilter) subFilter);
|
setAccountTypeFilter((AccountTypeFilter) subFilter);
|
||||||
} else if (subFilter instanceof MostRecentFilter ) {
|
} else if (subFilter instanceof MostRecentFilter) {
|
||||||
setMostRecentFilter((MostRecentFilter)subFilter);
|
setMostRecentFilter((MostRecentFilter) subFilter);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -396,11 +397,12 @@ 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
|
* @param typeFilter Account Types to be selected
|
||||||
*/
|
*/
|
||||||
private void setAccountTypeFilter(AccountTypeFilter typeFilter){
|
private void setAccountTypeFilter(AccountTypeFilter typeFilter) {
|
||||||
|
|
||||||
accountTypeMap.forEach((type, cb) -> {
|
accountTypeMap.forEach((type, cb) -> {
|
||||||
cb.setSelected(typeFilter.getAccountTypes().contains(type));
|
cb.setSelected(typeFilter.getAccountTypes().contains(type));
|
||||||
@ -439,7 +441,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
*/
|
*/
|
||||||
private void setMostRecentFilter(MostRecentFilter filter) {
|
private void setMostRecentFilter(MostRecentFilter filter) {
|
||||||
int limit = filter.getLimit();
|
int limit = filter.getLimit();
|
||||||
if(limit > 0) {
|
if (limit > 0) {
|
||||||
limitComboBox.setSelectedItem(filter.getLimit());
|
limitComboBox.setSelectedItem(filter.getLimit());
|
||||||
} else {
|
} else {
|
||||||
limitComboBox.setSelectedItem("All");
|
limitComboBox.setSelectedItem("All");
|
||||||
@ -448,7 +450,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
void filtersBack(CVTEvents.StateChangeEvent event) {
|
void filtersBack(CVTEvents.StateChangeEvent event) {
|
||||||
if(event.getCommunicationsState().getCommunicationsFilter() != null){
|
if (event.getCommunicationsState().getCommunicationsFilter() != null) {
|
||||||
setFilters(event.getCommunicationsState().getCommunicationsFilter());
|
setFilters(event.getCommunicationsState().getCommunicationsFilter());
|
||||||
setStartDateControlState(event.getCommunicationsState().getStartControlState());
|
setStartDateControlState(event.getCommunicationsState().getStartControlState());
|
||||||
setEndDateControlState(event.getCommunicationsState().getEndControlState());
|
setEndDateControlState(event.getCommunicationsState().getEndControlState());
|
||||||
@ -831,7 +833,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
*
|
*
|
||||||
* @return an instance of CommunicationsFilter
|
* @return an instance of CommunicationsFilter
|
||||||
*/
|
*/
|
||||||
protected CommunicationsFilter getFilter() {
|
private CommunicationsFilter getFilter() {
|
||||||
CommunicationsFilter commsFilter = new CommunicationsFilter();
|
CommunicationsFilter commsFilter = new CommunicationsFilter();
|
||||||
commsFilter.addAndFilter(getDeviceFilter());
|
commsFilter.addAndFilter(getDeviceFilter());
|
||||||
commsFilter.addAndFilter(getAccountTypeFilter());
|
commsFilter.addAndFilter(getAccountTypeFilter());
|
||||||
@ -878,35 +880,36 @@ final public class FiltersPanel extends JPanel {
|
|||||||
private DateRangeFilter getDateRangeFilter() {
|
private DateRangeFilter getDateRangeFilter() {
|
||||||
ZoneId zone = Utils.getUserPreferredZoneId();
|
ZoneId zone = Utils.getUserPreferredZoneId();
|
||||||
|
|
||||||
return new DateRangeFilter( startCheckBox.isSelected() ? startDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0,
|
return new DateRangeFilter(startCheckBox.isSelected() ? startDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0,
|
||||||
endCheckBox.isSelected() ? endDatePicker.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
|
* @return A new instance of MostRecentFilter
|
||||||
*/
|
*/
|
||||||
private MostRecentFilter getMostRecentFilter() {
|
private MostRecentFilter getMostRecentFilter() {
|
||||||
String value = (String)limitComboBox.getSelectedItem();
|
String value = (String) limitComboBox.getSelectedItem();
|
||||||
if(value.trim().equalsIgnoreCase("all")){
|
if (value.trim().equalsIgnoreCase("all")) {
|
||||||
return new MostRecentFilter(-1);
|
return new MostRecentFilter(-1);
|
||||||
} else{
|
} else {
|
||||||
try {
|
try {
|
||||||
int count = Integer.parseInt(value);
|
int count = Integer.parseInt(value);
|
||||||
return new MostRecentFilter(count);
|
return new MostRecentFilter(count);
|
||||||
} catch(NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DateControlState getStartControlState() {
|
private DateControlState getStartControlState() {
|
||||||
return new DateControlState (startDatePicker.getDate(), startCheckBox.isSelected());
|
return new DateControlState(startDatePicker.getDate(), startCheckBox.isSelected());
|
||||||
}
|
}
|
||||||
|
|
||||||
private DateControlState getEndControlState() {
|
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() {
|
private void initalizeDateTimeFilters() {
|
||||||
Case currentCase = null;
|
Case currentCase = null;
|
||||||
try{
|
try {
|
||||||
currentCase = Case.getCurrentCaseThrows();
|
currentCase = Case.getCurrentCaseThrows();
|
||||||
} catch (NoCurrentCaseException ex) {
|
} 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();
|
setDateTimeFiltersToDefault();
|
||||||
openCase = null;
|
openCase = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!currentCase.equals(openCase)) {
|
if (!currentCase.equals(openCase)) {
|
||||||
setDateTimeFiltersToDefault();
|
setDateTimeFiltersToDefault();
|
||||||
openCase = currentCase;
|
openCase = currentCase;
|
||||||
(new DatePickerWorker()).execute();
|
(new DatePickerWorker()).execute();
|
||||||
@ -1002,11 +1005,12 @@ final public class FiltersPanel extends JPanel {
|
|||||||
}//GEN-LAST:event_limitComboBoxActionPerformed
|
}//GEN-LAST:event_limitComboBoxActionPerformed
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to wrap the state of the date controls that consist of a date picker
|
* A class to wrap the state of the date controls that consist of a date
|
||||||
* and a checkbox.
|
* picker and a checkbox.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
final class DateControlState {
|
final class DateControlState {
|
||||||
|
|
||||||
private final LocalDate date;
|
private final LocalDate date;
|
||||||
private final boolean enabled;
|
private final boolean enabled;
|
||||||
|
|
||||||
@ -1027,7 +1031,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
*
|
*
|
||||||
* @return Current state LocalDate
|
* @return Current state LocalDate
|
||||||
*/
|
*/
|
||||||
public LocalDate getDate(){
|
public LocalDate getDate() {
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1078,13 +1082,15 @@ final public class FiltersPanel extends JPanel {
|
|||||||
private final javax.swing.JButton unCheckAllDevicesButton = new javax.swing.JButton();
|
private final javax.swing.JButton unCheckAllDevicesButton = new javax.swing.JButton();
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is a small panel that appears to just be a checkbox but
|
* This class is a small panel that appears to just be a checkbox but adds
|
||||||
* adds the functionality of being able to show an icon between the checkbox
|
* the functionality of being able to show an icon between the checkbox and
|
||||||
* and label.
|
* label.
|
||||||
*/
|
*/
|
||||||
final class CheckBoxIconPanel extends JPanel{
|
final class CheckBoxIconPanel extends JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final JCheckBox checkbox;
|
private final JCheckBox checkbox;
|
||||||
private final JLabel label;
|
private final JLabel label;
|
||||||
|
|
||||||
@ -1139,8 +1145,8 @@ final public class FiltersPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple class that implements CaseDbAccessQueryCallback. Can be used
|
* A simple class that implements CaseDbAccessQueryCallback. Can be used as
|
||||||
* as an anonymous innerclass with the CaseDbAccessManager select function.
|
* an anonymous innerclass with the CaseDbAccessManager select function.
|
||||||
*/
|
*/
|
||||||
class FilterPanelQueryCallback implements CaseDbAccessQueryCallback {
|
class FilterPanelQueryCallback implements CaseDbAccessQueryCallback {
|
||||||
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
ContactDetailsPane.nameLabel.text=Placeholder
|
ContactDetailsPane.nameLabel.text=Placeholder
|
||||||
SummaryViewer.countsPanel.border.title=Counts
|
SummaryViewer.countsPanel.border.title=Counts
|
||||||
SummaryViewer.contactsLabel.text=Contacts:
|
SummaryViewer.contactsLabel.text=Contacts:
|
||||||
SummaryViewer.attachmentsLabel.text=Media Attachments:
|
|
||||||
OutlineViewPanel.messageLabel.text=<Control Disabled>
|
OutlineViewPanel.messageLabel.text=<Control Disabled>
|
||||||
SummaryViewer.messagesDataLabel.text=messages
|
SummaryViewer.messagesDataLabel.text=messages
|
||||||
SummaryViewer.callLogsDataLabel.text=callLogs
|
SummaryViewer.callLogsDataLabel.text=callLogs
|
||||||
SummaryViewer.contactsDataLabel.text=contacts
|
SummaryViewer.contactsDataLabel.text=contacts
|
||||||
SummaryViewer.attachmentsDataLabel.text=attachments
|
|
||||||
SummaryViewer.messagesLabel.text=Messages:
|
SummaryViewer.messagesLabel.text=Messages:
|
||||||
SummaryViewer.callLogsLabel.text=Call Logs:
|
SummaryViewer.callLogsLabel.text=Call Logs:
|
||||||
ThreadRootMessagePanel.showAllCheckBox.text=Show All Messages
|
ThreadRootMessagePanel.showAllCheckBox.text=Show All Messages
|
||||||
@ -19,3 +17,7 @@ MessageViewer.showingMessagesLabel.text=Showing Messages for Thread:
|
|||||||
MessageViewer.backButton.AccessibleContext.accessibleDescription=
|
MessageViewer.backButton.AccessibleContext.accessibleDescription=
|
||||||
MessageViewer.backButton.text=Threads
|
MessageViewer.backButton.text=Threads
|
||||||
MessageViewer.showAllButton.text=All Messages
|
MessageViewer.showAllButton.text=All Messages
|
||||||
|
SummaryViewer.thumbnailCntLabel.text=Media Attachments:
|
||||||
|
SummaryViewer.attachmentsLable.text=Total Attachments:
|
||||||
|
SummaryViewer.thumbnailsDataLabel.text=attachments
|
||||||
|
SummaryViewer.attachmentDataLabel.text=count
|
||||||
|
@ -37,12 +37,10 @@ MessageViewer_viewMessage_selected=Selected
|
|||||||
MessageViewer_viewMessage_unthreaded=Unthreaded
|
MessageViewer_viewMessage_unthreaded=Unthreaded
|
||||||
SummaryViewer.countsPanel.border.title=Counts
|
SummaryViewer.countsPanel.border.title=Counts
|
||||||
SummaryViewer.contactsLabel.text=Contacts:
|
SummaryViewer.contactsLabel.text=Contacts:
|
||||||
SummaryViewer.attachmentsLabel.text=Media Attachments:
|
|
||||||
OutlineViewPanel.messageLabel.text=<Control Disabled>
|
OutlineViewPanel.messageLabel.text=<Control Disabled>
|
||||||
SummaryViewer.messagesDataLabel.text=messages
|
SummaryViewer.messagesDataLabel.text=messages
|
||||||
SummaryViewer.callLogsDataLabel.text=callLogs
|
SummaryViewer.callLogsDataLabel.text=callLogs
|
||||||
SummaryViewer.contactsDataLabel.text=contacts
|
SummaryViewer.contactsDataLabel.text=contacts
|
||||||
SummaryViewer.attachmentsDataLabel.text=attachments
|
|
||||||
SummaryViewer.messagesLabel.text=Messages:
|
SummaryViewer.messagesLabel.text=Messages:
|
||||||
SummaryViewer.callLogsLabel.text=Call Logs:
|
SummaryViewer.callLogsLabel.text=Call Logs:
|
||||||
SummaryViewer_CaseRefNameColumn_Title=Case Name
|
SummaryViewer_CaseRefNameColumn_Title=Case Name
|
||||||
@ -61,3 +59,7 @@ MessageViewer.showingMessagesLabel.text=Showing Messages for Thread:
|
|||||||
MessageViewer.backButton.AccessibleContext.accessibleDescription=
|
MessageViewer.backButton.AccessibleContext.accessibleDescription=
|
||||||
MessageViewer.backButton.text=Threads
|
MessageViewer.backButton.text=Threads
|
||||||
MessageViewer.showAllButton.text=All Messages
|
MessageViewer.showAllButton.text=All Messages
|
||||||
|
SummaryViewer.thumbnailCntLabel.text=Media Attachments:
|
||||||
|
SummaryViewer.attachmentsLable.text=Total Attachments:
|
||||||
|
SummaryViewer.thumbnailsDataLabel.text=attachments
|
||||||
|
SummaryViewer.attachmentDataLabel.text=count
|
||||||
|
@ -21,9 +21,10 @@ package org.sleuthkit.autopsy.communications.relationships;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
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.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
@ -102,6 +103,7 @@ public final class SelectionInfo {
|
|||||||
* Get the set of relationship sources from the case database
|
* Get the set of relationship sources from the case database
|
||||||
*
|
*
|
||||||
* @return the relationship sources (may be empty)
|
* @return the relationship sources (may be empty)
|
||||||
|
*
|
||||||
* @throws TskCoreException
|
* @throws TskCoreException
|
||||||
*/
|
*/
|
||||||
Set<Content> getRelationshipSources() throws TskCoreException {
|
Set<Content> getRelationshipSources() throws TskCoreException {
|
||||||
@ -131,7 +133,7 @@ public final class SelectionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Set<BlackboardArtifact> getArtifacts() {
|
public Set<BlackboardArtifact> getArtifacts() {
|
||||||
if(accountArtifacts == null) {
|
if (accountArtifacts == null) {
|
||||||
accountArtifacts = new HashSet<>();
|
accountArtifacts = new HashSet<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -149,28 +151,31 @@ public final class SelectionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SelectionSummary getSummary() {
|
public SelectionSummary getSummary() {
|
||||||
if(summary == null) {
|
if (summary == null) {
|
||||||
summary = new SelectionSummary();
|
summary = new SelectionSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SelectionSummary{
|
final class SelectionSummary {
|
||||||
|
|
||||||
int attachmentCnt;
|
int attachmentCnt;
|
||||||
int messagesCnt;
|
int messagesCnt;
|
||||||
int emailCnt;
|
int emailCnt;
|
||||||
int callLogCnt;
|
int callLogCnt;
|
||||||
int contactsCnt;
|
int contactsCnt;
|
||||||
|
int mediaCnt;
|
||||||
|
|
||||||
SelectionSummary() {
|
SelectionSummary() {
|
||||||
getCounts();
|
getCounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getCounts(){
|
private void getCounts() {
|
||||||
for(BlackboardArtifact artifact: getArtifacts()) {
|
for (BlackboardArtifact artifact : getArtifacts()) {
|
||||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||||
if(null != fromID) switch (fromID) {
|
if (null != fromID) {
|
||||||
|
switch (fromID) {
|
||||||
case TSK_EMAIL_MSG:
|
case TSK_EMAIL_MSG:
|
||||||
emailCnt++;
|
emailCnt++;
|
||||||
break;
|
break;
|
||||||
@ -186,8 +191,14 @@ public final class SelectionInfo {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
try{
|
}
|
||||||
attachmentCnt+= artifact.getChildrenCount();
|
try {
|
||||||
|
attachmentCnt += artifact.getChildrenCount();
|
||||||
|
for (Content childContent : artifact.getChildren()) {
|
||||||
|
if (ImageUtils.thumbnailSupported(childContent)) {
|
||||||
|
mediaCnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, String.format("Exception thrown "
|
logger.log(Level.WARNING, String.format("Exception thrown "
|
||||||
+ "from getChildrenCount artifactID: %d",
|
+ "from getChildrenCount artifactID: %d",
|
||||||
@ -215,12 +226,17 @@ public final class SelectionInfo {
|
|||||||
public int getContactsCnt() {
|
public int getContactsCnt() {
|
||||||
return contactsCnt;
|
return contactsCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getThumbnailCnt() {
|
||||||
|
return mediaCnt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to represent an edge from the graph visualization.
|
* Utility class to represent an edge from the graph visualization.
|
||||||
*/
|
*/
|
||||||
public static class GraphEdge {
|
public static class GraphEdge {
|
||||||
|
|
||||||
AccountDeviceInstance startNode;
|
AccountDeviceInstance startNode;
|
||||||
AccountDeviceInstance endNode;
|
AccountDeviceInstance endNode;
|
||||||
|
|
||||||
|
@ -41,16 +41,18 @@
|
|||||||
<Component id="messagesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
<Component id="messagesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="callLogsLabel" 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="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>
|
</Group>
|
||||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" 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="contactsDataLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="callLogsDataLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="callLogsDataLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="messagesDataLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="messagesDataLabel" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace pref="959" max="32767" attributes="0"/>
|
<EmptySpace pref="845" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
@ -74,10 +76,14 @@
|
|||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
<Component id="attachmentsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Component id="thumbnailCntLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="attachmentsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Component id="thumbnailsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
<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>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
@ -104,17 +110,17 @@
|
|||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="attachmentsLabel">
|
<Component class="javax.swing.JLabel" name="thumbnailCntLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.thumbnailCntLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="attachmentsDataLabel">
|
<Component class="javax.swing.JLabel" name="thumbnailsDataLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.thumbnailsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
@ -139,6 +145,20 @@
|
|||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="fileReferencesPanel">
|
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="fileReferencesPanel">
|
||||||
|
@ -104,10 +104,11 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
} else {
|
} else {
|
||||||
SelectionSummary summaryDetails = info.getSummary();
|
SelectionSummary summaryDetails = info.getSummary();
|
||||||
|
|
||||||
attachmentsDataLabel.setText(Integer.toString(summaryDetails.getAttachmentCnt()));
|
thumbnailsDataLabel.setText(Integer.toString(summaryDetails.getThumbnailCnt()));
|
||||||
callLogsDataLabel.setText(Integer.toString(summaryDetails.getCallLogCnt()));
|
callLogsDataLabel.setText(Integer.toString(summaryDetails.getCallLogCnt()));
|
||||||
contactsDataLabel.setText(Integer.toString(summaryDetails.getContactsCnt()));
|
contactsDataLabel.setText(Integer.toString(summaryDetails.getContactsCnt()));
|
||||||
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt() + summaryDetails.getEmailCnt()));
|
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt() + summaryDetails.getEmailCnt()));
|
||||||
|
attachmentDataLabel.setText(Integer.toString(summaryDetails.getAttachmentCnt()));
|
||||||
|
|
||||||
fileReferencesPanel.showOutlineView();
|
fileReferencesPanel.showOutlineView();
|
||||||
|
|
||||||
@ -131,7 +132,7 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
@Override
|
@Override
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
super.setEnabled(enabled);
|
super.setEnabled(enabled);
|
||||||
attachmentsLabel.setEnabled(enabled);
|
thumbnailCntLabel.setEnabled(enabled);
|
||||||
callLogsLabel.setEnabled(enabled);
|
callLogsLabel.setEnabled(enabled);
|
||||||
contactsLabel.setEnabled(enabled);
|
contactsLabel.setEnabled(enabled);
|
||||||
messagesLabel.setEnabled(enabled);
|
messagesLabel.setEnabled(enabled);
|
||||||
@ -144,10 +145,11 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
* Clears the text fields and OutlookViews.
|
* Clears the text fields and OutlookViews.
|
||||||
*/
|
*/
|
||||||
private void clearControls() {
|
private void clearControls() {
|
||||||
attachmentsDataLabel.setText("");
|
thumbnailsDataLabel.setText("");
|
||||||
callLogsDataLabel.setText("");
|
callLogsDataLabel.setText("");
|
||||||
contactsDataLabel.setText("");
|
contactsDataLabel.setText("");
|
||||||
messagesDataLabel.setText("");
|
messagesDataLabel.setText("");
|
||||||
|
attachmentDataLabel.setText("");
|
||||||
|
|
||||||
fileReferencesPanel.setNode(new AbstractNode(Children.LEAF));
|
fileReferencesPanel.setNode(new AbstractNode(Children.LEAF));
|
||||||
caseReferencesPanel.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();
|
contactsLabel = new javax.swing.JLabel();
|
||||||
messagesLabel = new javax.swing.JLabel();
|
messagesLabel = new javax.swing.JLabel();
|
||||||
callLogsLabel = new javax.swing.JLabel();
|
callLogsLabel = new javax.swing.JLabel();
|
||||||
attachmentsLabel = new javax.swing.JLabel();
|
thumbnailCntLabel = new javax.swing.JLabel();
|
||||||
attachmentsDataLabel = new javax.swing.JLabel();
|
thumbnailsDataLabel = new javax.swing.JLabel();
|
||||||
messagesDataLabel = new javax.swing.JLabel();
|
messagesDataLabel = new javax.swing.JLabel();
|
||||||
callLogsDataLabel = new javax.swing.JLabel();
|
callLogsDataLabel = new javax.swing.JLabel();
|
||||||
contactsDataLabel = 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();
|
fileReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||||
caseReferencesPanel = 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(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
|
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(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);
|
javax.swing.GroupLayout countsPanelLayout = new javax.swing.GroupLayout(countsPanel);
|
||||||
countsPanel.setLayout(countsPanelLayout);
|
countsPanel.setLayout(countsPanelLayout);
|
||||||
countsPanelLayout.setHorizontalGroup(
|
countsPanelLayout.setHorizontalGroup(
|
||||||
@ -225,14 +233,16 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
.addComponent(messagesLabel)
|
.addComponent(messagesLabel)
|
||||||
.addComponent(callLogsLabel)
|
.addComponent(callLogsLabel)
|
||||||
.addComponent(contactsLabel)
|
.addComponent(contactsLabel)
|
||||||
.addComponent(attachmentsLabel))
|
.addComponent(thumbnailCntLabel)
|
||||||
|
.addComponent(attachmentsLable))
|
||||||
.addGap(18, 18, 18)
|
.addGap(18, 18, 18)
|
||||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(attachmentsDataLabel)
|
.addComponent(attachmentDataLabel)
|
||||||
|
.addComponent(thumbnailsDataLabel)
|
||||||
.addComponent(contactsDataLabel)
|
.addComponent(contactsDataLabel)
|
||||||
.addComponent(callLogsDataLabel)
|
.addComponent(callLogsDataLabel)
|
||||||
.addComponent(messagesDataLabel))
|
.addComponent(messagesDataLabel))
|
||||||
.addContainerGap(959, Short.MAX_VALUE))
|
.addContainerGap(845, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
countsPanelLayout.setVerticalGroup(
|
countsPanelLayout.setVerticalGroup(
|
||||||
countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
@ -251,9 +261,12 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
.addComponent(contactsDataLabel))
|
.addComponent(contactsDataLabel))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(attachmentsLabel)
|
.addComponent(thumbnailCntLabel)
|
||||||
.addComponent(attachmentsDataLabel))
|
.addComponent(thumbnailsDataLabel))
|
||||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
.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();
|
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
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JLabel attachmentsDataLabel;
|
private javax.swing.JLabel attachmentDataLabel;
|
||||||
private javax.swing.JLabel attachmentsLabel;
|
private javax.swing.JLabel attachmentsLable;
|
||||||
private javax.swing.JLabel callLogsDataLabel;
|
private javax.swing.JLabel callLogsDataLabel;
|
||||||
private javax.swing.JLabel callLogsLabel;
|
private javax.swing.JLabel callLogsLabel;
|
||||||
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel caseReferencesPanel;
|
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 org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel fileReferencesPanel;
|
||||||
private javax.swing.JLabel messagesDataLabel;
|
private javax.swing.JLabel messagesDataLabel;
|
||||||
private javax.swing.JLabel messagesLabel;
|
private javax.swing.JLabel messagesLabel;
|
||||||
|
private javax.swing.JLabel thumbnailCntLabel;
|
||||||
|
private javax.swing.JLabel thumbnailsDataLabel;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import java.io.IOException;
|
|||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
@ -22,7 +22,7 @@ import java.util.HashSet;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
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.api.sendopts.CommandException;
|
||||||
import org.netbeans.spi.sendopts.Env;
|
import org.netbeans.spi.sendopts.Env;
|
||||||
import org.netbeans.spi.sendopts.Option;
|
import org.netbeans.spi.sendopts.Option;
|
||||||
|
@ -436,7 +436,7 @@
|
|||||||
<folder name="Windows2">
|
<folder name="Windows2">
|
||||||
<folder name="Components">
|
<folder name="Components">
|
||||||
<file name="DirectoryTreeTopComponent.settings" url="DirectoryTreeTopComponentSettings.xml"/>
|
<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"/>
|
<file name="IngestMessageTopComponent.settings" url="IngestMessageTopComponentSettings.xml"/>
|
||||||
</folder>
|
</folder>
|
||||||
<folder name="Modes">
|
<folder name="Modes">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -40,9 +40,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
* startup).
|
* startup).
|
||||||
*/
|
*/
|
||||||
// Registered as a service provider in layer.xml
|
// 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
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
public final class DataContentTopComponent extends TopComponent implements DataContent, ExplorerManager.Provider {
|
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() {
|
public static synchronized DataContentTopComponent findInstance() {
|
||||||
TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
|
TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
|
||||||
if (win == null) {
|
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();
|
return getDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (win instanceof DataContentTopComponent) {
|
if (win instanceof DataContentTopComponent) {
|
||||||
return (DataContentTopComponent) win;
|
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
|
+ "' ID. That is a potential source of errors and unexpected behavior."); //NON-NLS
|
||||||
|
|
||||||
return getDefault();
|
return getDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1321
Core/src/org/sleuthkit/autopsy/coreutils/AppDBParserHelper.java
Normal file
1321
Core/src/org/sleuthkit/autopsy/coreutils/AppDBParserHelper.java
Normal file
File diff suppressed because it is too large
Load Diff
326
Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java
Normal file
326
Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.coreutils;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.filesystems.FileObject;
|
import org.openide.filesystems.FileObject;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -172,6 +174,18 @@ public class FileUtil {
|
|||||||
return fileName.replaceAll("[\\p{Cntrl}/:\"*?<>|]+", "_");
|
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.
|
* Test if the current user has read and write access to the dirPath.
|
||||||
*
|
*
|
||||||
|
@ -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.NoSuchEventBusException;
|
||||||
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.RefreshKeysEvent;
|
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.RefreshKeysEvent;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
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.ingest.ModuleContentEvent;
|
||||||
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
|
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
|
||||||
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
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,
|
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);
|
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
|
* @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
|
// If this is an archive file we will listen for ingest events
|
||||||
// that will notify us when new content has been identified.
|
// that will notify us when new content has been identified.
|
||||||
if (FileTypeExtensions.getArchiveExtensions().contains(ext)) {
|
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()) {
|
if (EamDb.isEnabled()) {
|
||||||
properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), VALUE_LOADING, ""));
|
properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), VALUE_LOADING, ""));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Get the SCO columns data in a background task
|
// Get the SCO columns data in a background task
|
||||||
backgroundTasksPool.submit(new GetSCOTask(
|
backgroundTasksPool.submit(new GetSCOTask(
|
||||||
new WeakReference<>(this), weakPcl));
|
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<>(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<>(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)));
|
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_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<>(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<>(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<>(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<>(MIMETYPE.toString(), MIMETYPE.toString(), NO_DESCR, StringUtils.defaultString(content.getMIMEType())));
|
||||||
properties.add(new NodeProperty<>(EXTENSION.toString(), EXTENSION.toString(), NO_DESCR, content.getNameExtension()));
|
properties.add(new NodeProperty<>(EXTENSION.toString(), EXTENSION.toString(), NO_DESCR, content.getNameExtension()));
|
||||||
|
@ -28,7 +28,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import java.util.prefs.PreferenceChangeEvent;
|
import java.util.prefs.PreferenceChangeEvent;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
|
@ -369,11 +369,10 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
if (EamDb.isEnabled()) {
|
if (EamDb.isEnabled()) {
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, ""));
|
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
|
// Get the SCO columns data in a background task
|
||||||
backgroundTasksPool.submit(new GetSCOTask(
|
backgroundTasksPool.submit(new GetSCOTask(
|
||||||
new WeakReference<>(this), weakPcl));
|
new WeakReference<>(this), weakPcl));
|
||||||
|
}
|
||||||
|
|
||||||
if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
||||||
try {
|
try {
|
||||||
|
@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
|||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
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.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentVisitor;
|
import org.sleuthkit.datamodel.ContentVisitor;
|
||||||
@ -190,10 +191,12 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
Case.Events.DATA_SOURCE_ADDED,
|
Case.Events.DATA_SOURCE_ADDED,
|
||||||
Case.Events.CURRENT_CASE
|
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() {
|
DeletedContentsChildrenObservable() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_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_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text");
|
||||||
private static final String MAIL_PATH_SEPARATOR = "/";
|
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
|
* Parse the path of the email msg to get the account name and folder in
|
||||||
* which the email is contained.
|
* which the email is contained.
|
||||||
@ -88,8 +91,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
private final EmailResults emailResults;
|
private final EmailResults emailResults;
|
||||||
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
@ -112,11 +113,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
emailResults = new EmailResults();
|
emailResults = new EmailResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||||
return visitor.visit(this);
|
return visitor.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class EmailResults extends Observable {
|
private final class EmailResults extends Observable {
|
||||||
|
|
||||||
// NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
|
// NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
|
||||||
@ -307,8 +308,8 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
emailResults.update();
|
emailResults.update();
|
||||||
emailResults.addObserver(this);
|
emailResults.addObserver(this);
|
||||||
|
@ -26,6 +26,7 @@ import java.util.Comparator;
|
|||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
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 static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parent of the "extracted content" artifacts to be displayed in the tree.
|
* 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 {
|
public class ExtractedContent implements AutopsyVisitableItem {
|
||||||
|
|
||||||
private SleuthkitCase skCase; // set to null after case has been closed
|
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
||||||
private Blackboard blackboard;
|
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");
|
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 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
|
* Constructs extracted content object
|
||||||
@ -144,8 +146,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
return filePath + "gps-search.png"; //NON-NLS
|
return filePath + "gps-search.png"; //NON-NLS
|
||||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID()) {
|
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID()) {
|
||||||
return filePath + "installed.png"; //NON-NLS
|
return filePath + "installed.png"; //NON-NLS
|
||||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() ||
|
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()
|
||||||
typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID()) {
|
|| typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID()) {
|
||||||
return filePath + "encrypted-file.png"; //NON-NLS
|
return filePath + "encrypted-file.png"; //NON-NLS
|
||||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
|
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
|
||||||
return filePath + "mismatch-16.png"; //NON-NLS
|
return filePath + "mismatch-16.png"; //NON-NLS
|
||||||
@ -223,7 +225,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
// maps the artifact type to its child node
|
// maps the artifact type to its child node
|
||||||
private final HashMap<BlackboardArtifact.Type, TypeNode> typeNodeList = new HashMap<>();
|
private final HashMap<BlackboardArtifact.Type, TypeNode> typeNodeList = new HashMap<>();
|
||||||
|
|
||||||
public TypeFactory() {
|
TypeFactory() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
// these are shown in other parts of the UI tree
|
// 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_INTERESTING_ARTIFACT_HIT));
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT));
|
doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT));
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE));
|
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) -> {
|
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||||
@ -288,8 +290,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), 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) {
|
protected boolean createKeys(List<BlackboardArtifact.Type> list) {
|
||||||
if (skCase != null) {
|
if (skCase != null) {
|
||||||
try {
|
try {
|
||||||
List<BlackboardArtifact.Type> types = (filteringDSObjId > 0) ?
|
List<BlackboardArtifact.Type> types = (filteringDSObjId > 0)
|
||||||
blackboard.getArtifactTypesInUse(filteringDSObjId) :
|
? blackboard.getArtifactTypesInUse(filteringDSObjId)
|
||||||
skCase.getArtifactTypesInUse() ;
|
: skCase.getArtifactTypesInUse();
|
||||||
|
|
||||||
types.removeAll(doNotShow);
|
types.removeAll(doNotShow);
|
||||||
Collections.sort(types,
|
Collections.sort(types,
|
||||||
@ -370,10 +372,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
// a performance increase might be had by adding a
|
// a performance increase might be had by adding a
|
||||||
// "getBlackboardArtifactCount()" method to skCase
|
// "getBlackboardArtifactCount()" method to skCase
|
||||||
try {
|
try {
|
||||||
this.childCount = (filteringDSObjId > 0) ?
|
this.childCount = (filteringDSObjId > 0)
|
||||||
blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId) :
|
? blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId)
|
||||||
skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
|
: skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
|
||||||
} catch (TskException ex) {
|
} catch (TskCoreException ex) {
|
||||||
Logger.getLogger(TypeNode.class.getName())
|
Logger.getLogger(TypeNode.class.getName())
|
||||||
.log(Level.WARNING, "Error getting child count", ex); //NON-NLS
|
.log(Level.WARNING, "Error getting child count", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
@ -425,7 +427,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private BlackboardArtifact.Type type;
|
private BlackboardArtifact.Type type;
|
||||||
|
|
||||||
public ArtifactFactory(BlackboardArtifact.Type type) {
|
ArtifactFactory(BlackboardArtifact.Type type) {
|
||||||
super(type.getTypeName());
|
super(type.getTypeName());
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
@ -480,8 +482,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAdd() {
|
protected void onAdd() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -502,7 +504,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
return (filteringDSObjId > 0)
|
return (filteringDSObjId > 0)
|
||||||
? blackboard.getArtifacts(type.getTypeID(), filteringDSObjId)
|
? blackboard.getArtifacts(type.getTypeID(), filteringDSObjId)
|
||||||
: skCase.getBlackboardArtifacts(type.getTypeID());
|
: 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
|
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
private void setIcon(AbstractFile file) {
|
private void setIcon(AbstractFile file) {
|
||||||
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
||||||
if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) {
|
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 {
|
} else {
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,7 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
long filteringDataSourceObjId() {
|
long filteringDataSourceObjId() {
|
||||||
return this.filteringDSObjId;
|
return this.filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Root node. Children are nodes for specific sizes.
|
* Root node. Children are nodes for specific sizes.
|
||||||
*/
|
*/
|
||||||
@ -185,10 +186,12 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
private static final class FileSizeRootChildrenObservable extends Observable {
|
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<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() {
|
FileSizeRootChildrenObservable() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(CASE_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 {
|
public class FileSizeNode extends DisplayableItemNode {
|
||||||
|
|
||||||
private FileSizeFilter filter;
|
private final FileSizeFilter filter;
|
||||||
private final long datasourceObjId;
|
private final long datasourceObjId;
|
||||||
|
|
||||||
// use version with observer instead so that it updates
|
// use version with observer instead so that it updates
|
||||||
@ -282,9 +285,10 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
*
|
*
|
||||||
* @param skCase
|
* @param skCase
|
||||||
* @param filter
|
* @param filter
|
||||||
* @param o Observable that provides updates when events are
|
* @param o Observable that provides updates when
|
||||||
* fired
|
* events are fired
|
||||||
* @param datasourceObjId filter by data source, if configured in user preferences
|
* @param datasourceObjId filter by data source, if configured in
|
||||||
|
* user preferences
|
||||||
*/
|
*/
|
||||||
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o, long datasourceObjId) {
|
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o, long datasourceObjId) {
|
||||||
super(Children.create(new FileSizeChildren(filter, skCase, o, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
|
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> {
|
static class FileSizeChildren extends BaseChildFactory<AbstractFile> {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
|
||||||
private final SleuthkitCase skCase;
|
private final SleuthkitCase skCase;
|
||||||
private final FileSizeFilter filter;
|
private final FileSizeFilter filter;
|
||||||
private final Observable notifier;
|
private final Observable notifier;
|
||||||
private final long datasourceObjId;
|
private final long datasourceObjId;
|
||||||
private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -53,6 +53,8 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
public final class FileTypesByExtension implements AutopsyVisitableItem {
|
public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||||
|
|
||||||
private final static Logger logger = Logger.getLogger(FileTypesByExtension.class.getName());
|
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 SleuthkitCase skCase;
|
||||||
private final FileTypes typesRoot;
|
private final FileTypes typesRoot;
|
||||||
|
|
||||||
@ -115,8 +117,8 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(CASE_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
|
* Node for a specific file type / extension. Children of it will be the
|
||||||
* files of that type.
|
* files of that type.
|
||||||
*/
|
*/
|
||||||
class FileExtensionNode extends FileTypes.BGCountUpdatingNode {
|
final class FileExtensionNode extends FileTypes.BGCountUpdatingNode {
|
||||||
|
|
||||||
private final FileTypesByExtension.SearchFilterInterface filter;
|
private final FileTypesByExtension.SearchFilterInterface filter;
|
||||||
|
|
||||||
@ -369,7 +371,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
: " ")
|
: " ")
|
||||||
+ " AND (extension IN (" + filter.getFilter().stream()
|
+ " AND (extension IN (" + filter.getFilter().stream()
|
||||||
.map(String::toLowerCase)
|
.map(String::toLowerCase)
|
||||||
.map(s -> "'"+StringUtils.substringAfter(s, ".")+"'")
|
.map(s -> "'" + StringUtils.substringAfter(s, ".") + "'")
|
||||||
.collect(Collectors.joining(", ")) + "))";
|
.collect(Collectors.joining(", ")) + "))";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +495,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getFilter() {
|
public List<String> getFilter() {
|
||||||
return this.filter;
|
return Collections.unmodifiableList(this.filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,7 +552,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getFilter() {
|
public List<String> getFilter() {
|
||||||
return this.filter;
|
return Collections.unmodifiableList(this.filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,7 +599,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getFilter() {
|
public List<String> getFilter() {
|
||||||
return this.filter;
|
return Collections.unmodifiableList(this.filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
|
public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
|
||||||
|
|
||||||
private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName());
|
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;
|
private final SleuthkitCase skCase;
|
||||||
/**
|
/**
|
||||||
* The nodes of this tree will be determined dynamically by the mimetypes
|
* 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()
|
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
|
||||||
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.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() + ")") : "");
|
+ (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);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
populateHashMap();
|
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
|
* 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 /.
|
* 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",
|
@NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype",
|
||||||
"FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype",
|
"FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype",
|
||||||
|
@ -51,7 +51,6 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
|||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
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.
|
* Hash set hits node support. Inner classes have all of the nodes in the tree.
|
||||||
@ -61,11 +60,12 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
private static final String HASHSET_HITS = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getLabel();
|
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 String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName();
|
||||||
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
|
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 SleuthkitCase skCase;
|
||||||
private final HashsetResults hashsetResults;
|
private final HashsetResults hashsetResults;
|
||||||
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
@ -151,7 +151,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
String setName = resultSet.getString("value_text"); //NON-NLS
|
String setName = resultSet.getString("value_text"); //NON-NLS
|
||||||
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
|
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
|
||||||
if (!hashSetHitsMap.containsKey(setName)) {
|
if (!hashSetHitsMap.containsKey(setName)) {
|
||||||
hashSetHitsMap.put(setName, new HashSet<Long>());
|
hashSetHitsMap.put(setName, new HashSet<>());
|
||||||
}
|
}
|
||||||
hashSetHitsMap.get(setName).add(artifactId);
|
hashSetHitsMap.get(setName).add(artifactId);
|
||||||
}
|
}
|
||||||
@ -275,8 +275,8 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
hashsetResults.update();
|
hashsetResults.update();
|
||||||
hashsetResults.addObserver(this);
|
hashsetResults.addObserver(this);
|
||||||
@ -377,8 +377,8 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
private class HitFactory extends BaseChildFactory<BlackboardArtifact> implements Observer {
|
private class HitFactory extends BaseChildFactory<BlackboardArtifact> implements Observer {
|
||||||
|
|
||||||
private String hashsetName;
|
private final String hashsetName;
|
||||||
private Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
private final Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
||||||
|
|
||||||
private HitFactory(String hashsetName) {
|
private HitFactory(String hashsetName) {
|
||||||
super(hashsetName);
|
super(hashsetName);
|
||||||
@ -415,7 +415,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
||||||
artifactHits.put(id, art);
|
artifactHits.put(id, art);
|
||||||
}
|
}
|
||||||
} catch (TskException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
@ -59,6 +60,7 @@ import org.sleuthkit.datamodel.Tag;
|
|||||||
public class ImageNode extends AbstractContentNode<Image> {
|
public class ImageNode extends AbstractContentNode<Image> {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ImageNode.class.getName());
|
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
|
* 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
|
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)
|
// 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
|
// Listen for case events so that we can detect when case is closed
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
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 RunIngestModulesAction(Collections.<Content>singletonList(content)));
|
||||||
actionsList.add(new NewWindowViewAction(
|
actionsList.add(new NewWindowViewAction(
|
||||||
NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this));
|
NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this));
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[actionsList.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,6 +57,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
.getMessage(InterestingHits.class, "InterestingHits.interestingItems.text");
|
.getMessage(InterestingHits.class, "InterestingHits.interestingItems.text");
|
||||||
private static final String DISPLAY_NAME = NbBundle.getMessage(InterestingHits.class, "InterestingHits.displayName.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 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 SleuthkitCase skCase;
|
||||||
private final InterestingResults interestingResults = new InterestingResults();
|
private final InterestingResults interestingResults = new InterestingResults();
|
||||||
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
@ -217,17 +219,17 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||||
/**
|
/**
|
||||||
* Checking for a current case is a stop gap measure until a
|
* Checking for a current case is a stop gap measure until a
|
||||||
* different way of handling the closing of cases is worked
|
* different way of handling the closing of cases is worked out.
|
||||||
* out. Currently, remote events may be received for a case
|
* Currently, remote events may be received for a case that is
|
||||||
* that is already closed.
|
* already closed.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
Case.getCurrentCaseThrows();
|
Case.getCurrentCaseThrows();
|
||||||
/**
|
/**
|
||||||
* Even with the check above, it is still possible that
|
* Even with the check above, it is still possible that the
|
||||||
* the case will be closed in a different thread before
|
* case will be closed in a different thread before this
|
||||||
* this code executes. If that happens, it is possible
|
* code executes. If that happens, it is possible for the
|
||||||
* for the event to have a null oldValue.
|
* event to have a null oldValue.
|
||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()
|
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())) {
|
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||||
/**
|
/**
|
||||||
* Checking for a current case is a stop gap measure until a
|
* Checking for a current case is a stop gap measure until a
|
||||||
* different way of handling the closing of cases is worked
|
* different way of handling the closing of cases is worked out.
|
||||||
* out. Currently, remote events may be received for a case
|
* Currently, remote events may be received for a case that is
|
||||||
* that is already closed.
|
* already closed.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
Case.getCurrentCaseThrows();
|
Case.getCurrentCaseThrows();
|
||||||
@ -266,8 +268,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
interestingResults.update();
|
interestingResults.update();
|
||||||
interestingResults.addObserver(this);
|
interestingResults.addObserver(this);
|
||||||
|
@ -62,7 +62,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
public class KeywordHits implements AutopsyVisitableItem {
|
public class KeywordHits implements AutopsyVisitableItem {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(KeywordHits.class.getName());
|
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")
|
@NbBundle.Messages("KeywordHits.kwHits.text=Keyword Hits")
|
||||||
private static final String KEYWORD_HITS = KeywordHits_kwHits_text();
|
private static final String KEYWORD_HITS = KeywordHits_kwHits_text();
|
||||||
@NbBundle.Messages("KeywordHits.simpleLiteralSearch.text=Single Literal Keyword Search")
|
@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
|
// doesn't know about Keyword Search NBM
|
||||||
if (o1.startsWith("Single Literal Keyword Search")) {
|
if (o1.startsWith("Single Literal Keyword Search")) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else if (o2.startsWith("Single Literal Keyword Search")) {
|
||||||
else if (o2.startsWith("Single Literal Keyword Search")) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else if (o1.startsWith("Single Regular Expression Search")) {
|
||||||
else if (o1.startsWith("Single Regular Expression Search")) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else if (o2.startsWith("Single Regular Expression Search")) {
|
||||||
else if (o2.startsWith("Single Regular Expression Search")) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return o1.compareTo(o2);
|
return o1.compareTo(o2);
|
||||||
@ -501,8 +499,8 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
keywordResults.update();
|
keywordResults.update();
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
@ -529,6 +527,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private abstract class KWHitsNodeBase extends DisplayableItemNode implements Observer {
|
private abstract class KWHitsNodeBase extends DisplayableItemNode implements Observer {
|
||||||
|
|
||||||
private String displayName;
|
private String displayName;
|
||||||
|
|
||||||
private KWHitsNodeBase(Children children, Lookup lookup, String displayName) {
|
private KWHitsNodeBase(Children children, Lookup lookup, String displayName) {
|
||||||
|
@ -73,7 +73,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
|||||||
this.setDisplayName(nameForLayoutFile(lf));
|
this.setDisplayName(nameForLayoutFile(lf));
|
||||||
|
|
||||||
if (lf.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED)) {
|
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)) {
|
} else if (lf.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE)) {
|
||||||
if (lf.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
if (lf.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
|
||||||
|
@ -63,7 +63,7 @@ public class SlackFileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
// set name, display name, and icon
|
// set name, display name, and icon
|
||||||
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
||||||
if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) {
|
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 {
|
} else {
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -54,9 +54,10 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
|
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
|
||||||
// override of Children.Keys<T>.createNodes().
|
// 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 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 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 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
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
@ -223,8 +224,7 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
|
||||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
tagResults.update();
|
tagResults.update();
|
||||||
tagResults.addObserver(this);
|
tagResults.addObserver(this);
|
||||||
@ -233,7 +233,6 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
|
||||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
tagResults.deleteObserver(this);
|
tagResults.deleteObserver(this);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -20,8 +20,6 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
@ -119,7 +117,19 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Otherwise default to the AAFN createSheet method.
|
//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
|
@Override
|
||||||
|
@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
@ -52,6 +53,7 @@ import org.sleuthkit.datamodel.Tag;
|
|||||||
public class VolumeNode extends AbstractContentNode<Volume> {
|
public class VolumeNode extends AbstractContentNode<Volume> {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(VolumeNode.class.getName());
|
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
|
* 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
|
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)
|
// 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
|
// Listen for case events so that we can detect when case is closed
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
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));
|
NbBundle.getMessage(this.getClass(), "VolumeNode.getActions.viewInNewWin.text"), this));
|
||||||
actionsList.addAll(ExplorerNodeActionVisitor.getActions(content));
|
actionsList.addAll(ExplorerNodeActionVisitor.getActions(content));
|
||||||
|
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[actionsList.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -89,6 +89,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName());
|
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 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")
|
@NbBundle.Messages("AccountsRootNode.name=Accounts")
|
||||||
final public static String NAME = Bundle.AccountsRootNode_name();
|
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");
|
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 boolean showRejected = false; //NOPMD redundant initializer
|
||||||
|
|
||||||
private final RejectAccounts rejectActionInstance;
|
private final RejectAccounts rejectActionInstance;
|
||||||
@ -127,7 +131,6 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
this.approveActionInstance = new ApproveAccounts();
|
this.approveActionInstance = new ApproveAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||||
return visitor.visit(this);
|
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
|
* Create of keys used by this Children object to represent the child
|
||||||
* nodes.
|
* nodes.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
abstract protected boolean createKeys(List<X> list);
|
abstract protected boolean createKeys(List<X> list);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -320,14 +324,14 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<String> list) {
|
protected boolean createKeys(List<String> list) {
|
||||||
String accountTypesInUseQuery =
|
String accountTypesInUseQuery
|
||||||
"SELECT DISTINCT blackboard_attributes.value_text as account_type "
|
= "SELECT DISTINCT blackboard_attributes.value_text as account_type "
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //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()
|
+ " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
|
||||||
+ getFilterByDataSourceClause();
|
+ getFilterByDataSourceClause();
|
||||||
|
|
||||||
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery );
|
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery);
|
||||||
ResultSet resultSet = executeQuery.getResultSet()) {
|
ResultSet resultSet = executeQuery.getResultSet()) {
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
String accountType = resultSet.getString("account_type");
|
String accountType = resultSet.getString("account_type");
|
||||||
@ -368,8 +372,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
refresh(true);
|
refresh(true);
|
||||||
@ -439,8 +443,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
}
|
}
|
||||||
@ -455,8 +459,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<Long> list) {
|
protected boolean createKeys(List<Long> list) {
|
||||||
String query =
|
String query
|
||||||
"SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //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
|
+ " 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
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
}
|
}
|
||||||
@ -727,8 +731,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
}
|
}
|
||||||
@ -755,8 +759,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<FileWithCCN> list) {
|
protected boolean createKeys(List<FileWithCCN> list) {
|
||||||
String query =
|
String query
|
||||||
"SELECT blackboard_artifacts.obj_id," //NON-NLS
|
= "SELECT blackboard_artifacts.obj_id," //NON-NLS
|
||||||
+ " solr_attribute.value_text AS solr_document_id, "; //NON-NLS
|
+ " solr_attribute.value_text AS solr_document_id, "; //NON-NLS
|
||||||
if (skCase.getDatabaseType().equals(DbType.POSTGRESQL)) {
|
if (skCase.getDatabaseType().equals(DbType.POSTGRESQL)) {
|
||||||
query += " string_agg(blackboard_artifacts.artifact_id::character varying, ',') AS artifact_IDs, " //NON-NLS
|
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",
|
"# {0} - number of children",
|
||||||
"Accounts.ByFileNode.displayName=By File ({0})"})
|
"Accounts.ByFileNode.displayName=By File ({0})"})
|
||||||
private void updateDisplayName() {
|
private void updateDisplayName() {
|
||||||
String query =
|
String query
|
||||||
"SELECT count(*) FROM ( SELECT count(*) AS documents "
|
= "SELECT count(*) FROM ( SELECT count(*) AS documents "
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //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
|
+ " 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
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
}
|
}
|
||||||
@ -972,8 +976,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
RangeMap<Integer, BinResult> binRanges = TreeRangeMap.create();
|
RangeMap<Integer, BinResult> binRanges = TreeRangeMap.create();
|
||||||
|
|
||||||
String query =
|
String query
|
||||||
"SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS
|
= "SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS
|
||||||
+ " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS
|
+ " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //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",
|
"# {0} - number of children",
|
||||||
"Accounts.ByBINNode.displayName=By BIN ({0})"})
|
"Accounts.ByBINNode.displayName=By BIN ({0})"})
|
||||||
private void updateDisplayName() {
|
private void updateDisplayName() {
|
||||||
String query =
|
String query
|
||||||
"SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS
|
= "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //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
|
+ " 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.
|
* @return the artifact ids of the account artifacts from this file.
|
||||||
*/
|
*/
|
||||||
public List<Long> getArtifactIDs() {
|
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.
|
* @return the status(s) of the account artifacts from this file.
|
||||||
*/
|
*/
|
||||||
public Set<BlackboardArtifact.ReviewStatus> getStatuses() {
|
public Set<BlackboardArtifact.ReviewStatus> getStatuses() {
|
||||||
return statuses;
|
return Collections.unmodifiableSet(statuses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1335,8 +1339,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<Long> list) {
|
protected boolean createKeys(List<Long> list) {
|
||||||
|
|
||||||
String query =
|
String query
|
||||||
"SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //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
|
+ " 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 {
|
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 final BinResult bin;
|
||||||
|
|
||||||
private BINNode(BinResult bin) {
|
private BINNode(BinResult bin) {
|
||||||
@ -1407,8 +1413,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateDisplayName() {
|
private void updateDisplayName() {
|
||||||
String query =
|
String query
|
||||||
"SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS
|
= "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //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
|
+ " 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The number of accounts with this BIN */
|
/**
|
||||||
|
* The number of accounts with this BIN
|
||||||
|
*/
|
||||||
private final long count;
|
private final long count;
|
||||||
|
|
||||||
private final BINRange binRange;
|
private final BINRange binRange;
|
||||||
@ -1726,8 +1734,10 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
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()
|
List<String[]> selectedPaths = Utilities.actionsGlobalContext().lookupAll(Node.class).stream()
|
||||||
.map(node -> {
|
.map(node -> {
|
||||||
String[] createPath;
|
String[] createPath;
|
||||||
@ -1746,9 +1756,11 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
: siblings.get(Integer.max(indexOf + 1, siblings.size() - 1));
|
: siblings.get(Integer.max(indexOf + 1, siblings.size() - 1));
|
||||||
createPath = NodeOp.createPath(sibling, null);
|
createPath = NodeOp.createPath(sibling, null);
|
||||||
} else {
|
} 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
|
* just return null, but note we need to filter
|
||||||
* this out of stream below */
|
* this out of stream below
|
||||||
|
*/
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -179,9 +179,7 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
newPs.setShortDescription(ps.getShortDescription());
|
newPs.setShortDescription(ps.getShortDescription());
|
||||||
|
|
||||||
newPs.put(ps.getProperties());
|
newPs.put(ps.getProperties());
|
||||||
if (newPs.remove(AbstractFsContentNode.HIDE_PARENT) != null) {
|
newPs.remove(AbstractFsContentNode.HIDE_PARENT);
|
||||||
newPs.remove(AbstractFilePropertyType.LOCATION.toString());
|
|
||||||
}
|
|
||||||
propertySets[i] = newPs;
|
propertySets[i] = newPs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,6 @@ import org.sleuthkit.autopsy.datamodel.Tags;
|
|||||||
import org.sleuthkit.autopsy.datamodel.ViewsNode;
|
import org.sleuthkit.autopsy.datamodel.ViewsNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
||||||
import org.sleuthkit.autopsy.datamodel.accounts.BINRange;
|
import org.sleuthkit.autopsy.datamodel.accounts.BINRange;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -128,7 +127,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
getTree().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
getTree().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||||
//Hook into the JTree and pre-expand the Views Node and Results node when a user
|
//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.
|
//expands an item in the tree that makes these nodes visible.
|
||||||
((ExpansionBeanTreeView )getTree()).addTreeExpansionListener(new TreeExpansionListener() {
|
((ExpansionBeanTreeView) getTree()).addTreeExpansionListener(new TreeExpansionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void treeExpanded(TreeExpansionEvent event) {
|
public void treeExpanded(TreeExpansionEvent event) {
|
||||||
//Bail immediately if we are not in the Group By view.
|
//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);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE, Case.Events.DATA_SOURCE_ADDED), this);
|
||||||
this.em.addPropertyChangeListener(this);
|
this.em.addPropertyChangeListener(this);
|
||||||
IngestManager.getInstance().addIngestJobEventListener(this);
|
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDirectoryListingActive() {
|
public void setDirectoryListingActive() {
|
||||||
@ -799,9 +796,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
} // change in node selection
|
} // change in node selection
|
||||||
else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||||
respondSelection((Node[]) event.getOldValue(), (Node[]) event.getNewValue());
|
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.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,6 +296,7 @@
|
|||||||
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||||
<Connection code="instancesListModel" type="code"/>
|
<Connection code="instancesListModel" type="code"/>
|
||||||
</Property>
|
</Property>
|
||||||
|
<Property name="selectionMode" type="int" value="0"/>
|
||||||
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||||
<Connection code="new InstancesCellRenderer()" type="code"/>
|
<Connection code="new InstancesCellRenderer()" type="code"/>
|
||||||
</Property>
|
</Property>
|
||||||
|
@ -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.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ResultsPanel.class, "ResultsPanel.instancesList.border.title"))); // NOI18N
|
||||||
instancesList.setModel(instancesListModel);
|
instancesList.setModel(instancesListModel);
|
||||||
|
instancesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||||
instancesList.setCellRenderer(new InstancesCellRenderer());
|
instancesList.setCellRenderer(new InstancesCellRenderer());
|
||||||
instancesScrollPane.setViewportView(instancesList);
|
instancesScrollPane.setViewportView(instancesList);
|
||||||
|
|
||||||
|
BIN
Core/src/org/sleuthkit/autopsy/images/carved-file-x-icon-16.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/carved-file-x-icon-16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.imagewriter;
|
|||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
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
|
* 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
|
* after the ingest process completes. The AddImageTask for this data source
|
||||||
* a non-empty imageWriterPath parameter to enable Image Writer.
|
* must have included a non-empty imageWriterPath parameter to enable Image
|
||||||
|
* Writer.
|
||||||
*
|
*
|
||||||
* Most of the cancellation/cleanup is handled through ImageWriterService
|
* Most of the cancellation/cleanup is handled through ImageWriterService
|
||||||
*/
|
*/
|
||||||
class ImageWriter implements PropertyChangeListener{
|
class ImageWriter implements PropertyChangeListener {
|
||||||
|
|
||||||
private final Logger logger = Logger.getLogger(ImageWriter.class.getName());
|
|
||||||
|
|
||||||
|
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 Long dataSourceId;
|
||||||
private final ImageWriterSettings settings;
|
private final ImageWriterSettings settings;
|
||||||
|
|
||||||
@ -70,11 +73,12 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
private SleuthkitCase caseDb = null;
|
private SleuthkitCase caseDb = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the Image Writer object.
|
* Create the Image Writer object. After creation, startListeners() should
|
||||||
* After creation, startListeners() should be called.
|
* be called.
|
||||||
|
*
|
||||||
* @param dataSourceId
|
* @param dataSourceId
|
||||||
*/
|
*/
|
||||||
ImageWriter(Long dataSourceId, ImageWriterSettings settings){
|
ImageWriter(Long dataSourceId, ImageWriterSettings settings) {
|
||||||
this.dataSourceId = dataSourceId;
|
this.dataSourceId = dataSourceId;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
doUI = RuntimeProperties.runningWithGUI();
|
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
|
// 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
|
// null before Image Writer finishes. The user can still elect to wait for image writer
|
||||||
// (in ImageWriterService.closeCaseResources) even though the case is closing.
|
// (in ImageWriterService.closeCaseResources) even though the case is closing.
|
||||||
try{
|
try {
|
||||||
caseDb = Case.getCurrentCaseThrows().getSleuthkitCase();
|
caseDb = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||||
} catch (NoCurrentCaseException ex){
|
} catch (NoCurrentCaseException ex) {
|
||||||
logger.log(Level.SEVERE, "Unable to load case. Image writer will be cancelled.");
|
logger.log(Level.SEVERE, "Unable to load case. Image writer will be cancelled.");
|
||||||
this.isCancelled = true;
|
this.isCancelled = true;
|
||||||
}
|
}
|
||||||
@ -93,33 +97,34 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
/**
|
/**
|
||||||
* Add this ImageWriter object as a listener to the necessary events
|
* Add this ImageWriter object as a listener to the necessary events
|
||||||
*/
|
*/
|
||||||
void subscribeToEvents(){
|
void subscribeToEvents() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(this);
|
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);
|
IngestManager.getInstance().removeIngestJobEventListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the events:
|
* Handle the events: DATA_SOURCE_ANALYSIS_COMPLETED - start the finish
|
||||||
* DATA_SOURCE_ANALYSIS_COMPLETED - start the finish image process and clean up after it is complete
|
* image process and clean up after it is complete
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
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();
|
long imageId = event.getDataSource().getId();
|
||||||
String name = event.getDataSource().getName();
|
String name = event.getDataSource().getName();
|
||||||
|
|
||||||
// Check that the event corresponds to this datasource
|
// Check that the event corresponds to this datasource
|
||||||
if(imageId != dataSourceId){
|
if (imageId != dataSourceId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
@ -136,25 +141,25 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
"# {0} - data source name",
|
"# {0} - data source name",
|
||||||
"ImageWriter.progressBar.message=Finishing acquisition of {0} (unplug device to cancel)"
|
"ImageWriter.progressBar.message=Finishing acquisition of {0} (unplug device to cancel)"
|
||||||
})
|
})
|
||||||
private void startFinishImage(String dataSourceName){
|
private void startFinishImage(String dataSourceName) {
|
||||||
|
|
||||||
synchronized(currentTasksLock){
|
synchronized (currentTasksLock) {
|
||||||
if(isCancelled){
|
if (isCancelled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've already started the finish process for this datasource, return.
|
// If we've already started the finish process for this datasource, return.
|
||||||
// Multiple DataSourceAnalysisCompletedEvent events can come from
|
// Multiple DataSourceAnalysisCompletedEvent events can come from
|
||||||
// the same image if more ingest modules are run later
|
// the same image if more ingest modules are run later
|
||||||
if(isStarted){
|
if (isStarted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image image;
|
Image image;
|
||||||
try{
|
try {
|
||||||
image = Case.getCurrentCaseThrows().getSleuthkitCase().getImageById(dataSourceId);
|
image = Case.getCurrentCaseThrows().getSleuthkitCase().getImageById(dataSourceId);
|
||||||
imageHandle = image.getImageHandle();
|
imageHandle = image.getImageHandle();
|
||||||
} catch (NoCurrentCaseException ex){
|
} catch (NoCurrentCaseException ex) {
|
||||||
// This exception means that getOpenCase() failed because no case was open.
|
// 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
|
// 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
|
// 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",
|
logger.log(Level.WARNING, String.format("Case closed before ImageWriter could start the finishing process for %s",
|
||||||
dataSourceName));
|
dataSourceName));
|
||||||
return;
|
return;
|
||||||
} catch (TskCoreException ex){
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Error loading image", ex);
|
logger.log(Level.SEVERE, "Error loading image", ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -170,7 +175,7 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
logger.log(Level.INFO, String.format("Finishing VHD image for %s",
|
logger.log(Level.INFO, String.format("Finishing VHD image for %s",
|
||||||
dataSourceName)); //NON-NLS
|
dataSourceName)); //NON-NLS
|
||||||
|
|
||||||
if(doUI){
|
if (doUI) {
|
||||||
periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("image-writer-progress-update-%d").build()); //NON-NLS
|
periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("image-writer-progress-update-%d").build()); //NON-NLS
|
||||||
progressHandle = ProgressHandle.createHandle(Bundle.ImageWriter_progressBar_message(dataSourceName));
|
progressHandle = ProgressHandle.createHandle(Bundle.ImageWriter_progressBar_message(dataSourceName));
|
||||||
progressHandle.start(100);
|
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 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
|
// the call to finishImageWriter returns before allowing the TSK data structures to be freed
|
||||||
// during case close.
|
// during case close.
|
||||||
finishTask = Executors.newSingleThreadExecutor().submit(new Callable<Integer>(){
|
finishTask = Executors.newSingleThreadExecutor().submit(new Callable<Integer>() {
|
||||||
@Override
|
@Override
|
||||||
public Integer call() throws TskCoreException{
|
public Integer call() throws TskCoreException {
|
||||||
try{
|
try {
|
||||||
int result = SleuthkitJNI.finishImageWriter(imageHandle);
|
int result = SleuthkitJNI.finishImageWriter(imageHandle);
|
||||||
|
|
||||||
// We've decided to always update the path to the VHD, even if it wasn't finished.
|
// 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
|
// 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.
|
// 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);
|
caseDb.updateImagePath(settings.getPath(), dataSourceId);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} catch (TskCoreException ex){
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -207,15 +212,15 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
|
|
||||||
// Wait for finishImageWriter to complete
|
// Wait for finishImageWriter to complete
|
||||||
int result = 0;
|
int result = 0;
|
||||||
try{
|
try {
|
||||||
// The call to get() can happen multiple times if the user closes the case, which is ok
|
// The call to get() can happen multiple times if the user closes the case, which is ok
|
||||||
result = finishTask.get();
|
result = finishTask.get();
|
||||||
} catch (InterruptedException | ExecutionException ex){
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized(currentTasksLock){
|
synchronized (currentTasksLock) {
|
||||||
if(doUI){
|
if (doUI) {
|
||||||
// Some of these may be called twice if the user closes the case
|
// Some of these may be called twice if the user closes the case
|
||||||
progressUpdateTask.cancel(true);
|
progressUpdateTask.cancel(true);
|
||||||
progressHandle.finish();
|
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
|
logger.log(Level.INFO, String.format("Successfully finished writing VHD image for %s", dataSourceName)); //NON-NLS
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.INFO, String.format("Finished VHD image for %s with errors", dataSourceName)); //NON-NLS
|
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
|
* If a task hasn't been started yet, set the cancel flag so it can no
|
||||||
* start.
|
* longer start. This is intended to be used in case close so a job doesn't
|
||||||
* This is intended to be used in case close so a job doesn't suddenly start
|
* suddenly start up during cleanup.
|
||||||
* up during cleanup.
|
|
||||||
*/
|
*/
|
||||||
void cancelIfNotStarted(){
|
void cancelIfNotStarted() {
|
||||||
synchronized(currentTasksLock){
|
synchronized (currentTasksLock) {
|
||||||
if(! isStarted){
|
if (!isStarted) {
|
||||||
isCancelled = true;
|
isCancelled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,25 +250,26 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the finishTask process is running.
|
* 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(){
|
boolean jobIsInProgress() {
|
||||||
synchronized(currentTasksLock){
|
synchronized (currentTasksLock) {
|
||||||
return((isStarted) && (! finishTask.isDone()));
|
return ((isStarted) && (!finishTask.isDone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels a single job.
|
* Cancels a single job. Does not wait for the job to complete. Safe to call
|
||||||
* Does not wait for the job to complete. Safe to call with Image Writer in any state.
|
* with Image Writer in any state.
|
||||||
*/
|
*/
|
||||||
void cancelJob(){
|
void cancelJob() {
|
||||||
synchronized(currentTasksLock){
|
synchronized (currentTasksLock) {
|
||||||
// All of the following is redundant but safe to call on a complete job
|
// All of the following is redundant but safe to call on a complete job
|
||||||
isCancelled = true;
|
isCancelled = true;
|
||||||
|
|
||||||
if(isStarted){
|
if (isStarted) {
|
||||||
SleuthkitJNI.cancelFinishImage(imageHandle);
|
SleuthkitJNI.cancelFinishImage(imageHandle);
|
||||||
|
|
||||||
// Stop the progress bar update task.
|
// Stop the progress bar update task.
|
||||||
@ -273,7 +278,7 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
// when that happens.
|
// when that happens.
|
||||||
// Since we've stopped the update task, we'll stop the associated progress
|
// Since we've stopped the update task, we'll stop the associated progress
|
||||||
// bar now, too.
|
// bar now, too.
|
||||||
if(doUI){
|
if (doUI) {
|
||||||
progressUpdateTask.cancel(true);
|
progressUpdateTask.cancel(true);
|
||||||
progressHandle.finish();
|
progressHandle.finish();
|
||||||
}
|
}
|
||||||
@ -282,19 +287,19 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks while all finishImage tasks complete.
|
* Blocks while all finishImage tasks complete. Also makes sure the
|
||||||
* Also makes sure the progressUpdateTask is canceled.
|
* progressUpdateTask is canceled.
|
||||||
*/
|
*/
|
||||||
void waitForJobToFinish(){
|
void waitForJobToFinish() {
|
||||||
synchronized(currentTasksLock){
|
synchronized (currentTasksLock) {
|
||||||
// Wait for the finish task to end
|
// Wait for the finish task to end
|
||||||
if(isStarted){
|
if (isStarted) {
|
||||||
try{
|
try {
|
||||||
finishTask.get();
|
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
|
Logger.getLogger(ImageWriter.class.getName()).log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
if(doUI){
|
if (doUI) {
|
||||||
progressUpdateTask.cancel(true);
|
progressUpdateTask.cancel(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,10 +310,11 @@ class ImageWriter implements PropertyChangeListener{
|
|||||||
* Task to query the Sleuthkit processing to get the percentage done.
|
* Task to query the Sleuthkit processing to get the percentage done.
|
||||||
*/
|
*/
|
||||||
private final class ProgressUpdateTask implements Runnable {
|
private final class ProgressUpdateTask implements Runnable {
|
||||||
|
|
||||||
final long imageHandle;
|
final long imageHandle;
|
||||||
final ProgressHandle progressHandle;
|
final ProgressHandle progressHandle;
|
||||||
|
|
||||||
ProgressUpdateTask(ProgressHandle progressHandle, long imageHandle){
|
ProgressUpdateTask(ProgressHandle progressHandle, long imageHandle) {
|
||||||
this.imageHandle = imageHandle;
|
this.imageHandle = imageHandle;
|
||||||
this.progressHandle = progressHandle;
|
this.progressHandle = progressHandle;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ EditNonFullPathsRulePanel.minSizeCheckbox.text=Minimum size:
|
|||||||
NewRulePanel.chooseLabel.text=Choose the type of rule
|
NewRulePanel.chooseLabel.text=Choose the type of rule
|
||||||
ConfigVisualPanel1.configureDriveRadioButton.text_1=Configure selected external drive:
|
ConfigVisualPanel1.configureDriveRadioButton.text_1=Configure selected external drive:
|
||||||
ConfigVisualPanel1.configureFolderRadioButton.text_1=Configure in a folder:
|
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
|
ConfigVisualPanel1.refreshButton.text=Refresh
|
||||||
ConfigVisualPanel3.saveButton.text=Save
|
ConfigVisualPanel3.saveButton.text=Save
|
||||||
ConfigVisualPanel3.configLabel.text=Logical Imager config file save status:
|
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.
|
EditNonFullPathsRulePanel.extensionsInfoLabel.text=Extensions are case insensitive.
|
||||||
ConfigVisualPanel2.promptBeforeExit.text=Prompt before exiting imager
|
ConfigVisualPanel2.promptBeforeExit.text=Prompt before exiting imager
|
||||||
ConfigVisualPanel2.promptBeforeExit.actionCommand=
|
ConfigVisualPanel2.promptBeforeExit.actionCommand=
|
||||||
|
ConfigVisualPanel2.createVHDCheckBox.text=Create VHD
|
||||||
|
@ -26,10 +26,16 @@ ConfigVisualPanel1.chooseFileTitle=Select a Logical Imager configuration
|
|||||||
# {0} - filename
|
# {0} - filename
|
||||||
ConfigVisualPanel1.configFileIsEmpty=Configuration file {0} is empty
|
ConfigVisualPanel1.configFileIsEmpty=Configuration file {0} is empty
|
||||||
ConfigVisualPanel1.configurationError=Configuration error
|
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.fileNameExtensionFilter=Configuration JSON File
|
||||||
ConfigVisualPanel1.invalidConfigJson=Invalid config JSON:
|
ConfigVisualPanel1.invalidConfigJson=Invalid config JSON:
|
||||||
ConfigVisualPanel1.messageLabel.noExternalDriveFound=No drive found
|
ConfigVisualPanel1.messageLabel.noExternalDriveFound=No drive found
|
||||||
ConfigVisualPanel1.selectConfigurationFile=Select location
|
ConfigVisualPanel1.selectConfigurationFile=Select location
|
||||||
|
ConfigVisualPanel1.unknown=Unknown
|
||||||
ConfigVisualPanel2.cancel=Cancel
|
ConfigVisualPanel2.cancel=Cancel
|
||||||
ConfigVisualPanel2.deleteRuleSet=Delete rule
|
ConfigVisualPanel2.deleteRuleSet=Delete rule
|
||||||
ConfigVisualPanel2.deleteRuleSetConfirmation=Delete rule confirmation
|
ConfigVisualPanel2.deleteRuleSetConfirmation=Delete rule confirmation
|
||||||
@ -174,7 +180,7 @@ LogicalImagerConfigDeserializer.unsupportedKeyException=Unsupported key: {0}
|
|||||||
NewRulePanel.chooseLabel.text=Choose the type of rule
|
NewRulePanel.chooseLabel.text=Choose the type of rule
|
||||||
ConfigVisualPanel1.configureDriveRadioButton.text_1=Configure selected external drive:
|
ConfigVisualPanel1.configureDriveRadioButton.text_1=Configure selected external drive:
|
||||||
ConfigVisualPanel1.configureFolderRadioButton.text_1=Configure in a folder:
|
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
|
ConfigVisualPanel1.refreshButton.text=Refresh
|
||||||
ConfigVisualPanel3.saveButton.text=Save
|
ConfigVisualPanel3.saveButton.text=Save
|
||||||
ConfigVisualPanel3.configLabel.text=Logical Imager config file save status:
|
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.
|
EditNonFullPathsRulePanel.extensionsInfoLabel.text=Extensions are case insensitive.
|
||||||
ConfigVisualPanel2.promptBeforeExit.text=Prompt before exiting imager
|
ConfigVisualPanel2.promptBeforeExit.text=Prompt before exiting imager
|
||||||
ConfigVisualPanel2.promptBeforeExit.actionCommand=
|
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.description=Search for files based on one or more attributes or metadata fields.
|
||||||
NewRuleSetPanel.attributeRule.name=Attribute
|
NewRuleSetPanel.attributeRule.name=Attribute
|
||||||
NewRuleSetPanel.fullPathRule.description=Search for files based on full exact match path.
|
NewRuleSetPanel.fullPathRule.description=Search for files based on full exact match path.
|
||||||
|
@ -29,7 +29,11 @@ import java.io.IOException;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.FileStore;
|
import java.nio.file.FileStore;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.spi.FileSystemProvider;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -241,10 +245,31 @@ final class ConfigVisualPanel1 extends JPanel {
|
|||||||
firePropertyChange(UPDATE_UI_EVENT_NAME, false, true); // NON-NLS
|
firePropertyChange(UPDATE_UI_EVENT_NAME, false, true); // NON-NLS
|
||||||
}//GEN-LAST:event_driveListMouseReleasedSelection
|
}//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
|
* 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() {
|
private void refreshDriveList() {
|
||||||
List<String> listData = new ArrayList<>();
|
List<String> listData = new ArrayList<>();
|
||||||
File[] roots = File.listRoots();
|
File[] roots = File.listRoots();
|
||||||
@ -257,7 +282,8 @@ final class ConfigVisualPanel1 extends JPanel {
|
|||||||
String description = FileSystemView.getFileSystemView().getSystemTypeDescription(root);
|
String description = FileSystemView.getFileSystemView().getSystemTypeDescription(root);
|
||||||
long spaceInBytes = root.getTotalSpace();
|
long spaceInBytes = root.getTotalSpace();
|
||||||
String sizeWithUnit = DriveListUtils.humanReadableByteCount(spaceInBytes, false);
|
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) {
|
if (firstRemovableDrive == -1) {
|
||||||
try {
|
try {
|
||||||
FileStore fileStore = Files.getFileStore(root.toPath());
|
FileStore fileStore = Files.getFileStore(root.toPath());
|
||||||
@ -266,7 +292,7 @@ final class ConfigVisualPanel1 extends JPanel {
|
|||||||
}
|
}
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
//unable to get this removable drive for default selection will try and select next removable drive by default
|
//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++;
|
i++;
|
||||||
@ -431,8 +457,7 @@ final class ConfigVisualPanel1 extends JPanel {
|
|||||||
return UPDATE_UI_EVENT_NAME;
|
return UPDATE_UI_EVENT_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setConfigFilename(String filename
|
void setConfigFilename(String filename) {
|
||||||
) {
|
|
||||||
configFileTextField.setText(filename);
|
configFileTextField.setText(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,9 +467,11 @@ final class ConfigVisualPanel1 extends JPanel {
|
|||||||
* @return true if panel has valid settings selected, false otherwise
|
* @return true if panel has valid settings selected, false otherwise
|
||||||
*/
|
*/
|
||||||
boolean isPanelValid() {
|
boolean isPanelValid() {
|
||||||
return !StringUtils.isBlank(getConfigPath()) && ((configureDriveRadioButton.isSelected() && !StringUtils.isBlank(driveList.getSelectedValue()))
|
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())));
|
|| (configureFolderRadioButton.isSelected() && (!configFileTextField.getText().isEmpty())));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,6 +103,7 @@
|
|||||||
<Component id="flagEncryptionProgramsCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
|
<Component id="flagEncryptionProgramsCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="finalizeImageWriter" 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="promptBeforeExit" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="createVHDCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -193,7 +194,8 @@
|
|||||||
<Component id="finalizeImageWriter" min="-2" max="-2" attributes="0"/>
|
<Component id="finalizeImageWriter" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="promptBeforeExit" 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>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
@ -582,5 +584,15 @@
|
|||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="promptBeforeExitActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="promptBeforeExitActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</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, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="createVHDCheckBoxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -111,6 +111,7 @@ final class ConfigVisualPanel2 extends JPanel {
|
|||||||
maxSizeLabel = new javax.swing.JLabel();
|
maxSizeLabel = new javax.swing.JLabel();
|
||||||
maxSizeTextField = new javax.swing.JFormattedTextField();
|
maxSizeTextField = new javax.swing.JFormattedTextField();
|
||||||
promptBeforeExit = new javax.swing.JCheckBox();
|
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
|
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);
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
@ -338,7 +346,8 @@ final class ConfigVisualPanel2 extends JPanel {
|
|||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(flagEncryptionProgramsCheckBox)
|
.addComponent(flagEncryptionProgramsCheckBox)
|
||||||
.addComponent(finalizeImageWriter)
|
.addComponent(finalizeImageWriter)
|
||||||
.addComponent(promptBeforeExit))
|
.addComponent(promptBeforeExit)
|
||||||
|
.addComponent(createVHDCheckBox))
|
||||||
.addGap(0, 0, Short.MAX_VALUE))
|
.addGap(0, 0, Short.MAX_VALUE))
|
||||||
.addComponent(jSeparator1)))))
|
.addComponent(jSeparator1)))))
|
||||||
);
|
);
|
||||||
@ -412,7 +421,8 @@ final class ConfigVisualPanel2 extends JPanel {
|
|||||||
.addComponent(finalizeImageWriter)
|
.addComponent(finalizeImageWriter)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
.addComponent(promptBeforeExit)
|
.addComponent(promptBeforeExit)
|
||||||
.addGap(21, 21, 21))))
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(createVHDCheckBox))))
|
||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
@ -546,6 +556,10 @@ final class ConfigVisualPanel2 extends JPanel {
|
|||||||
config.setPromptBeforeExit(promptBeforeExit.isSelected());
|
config.setPromptBeforeExit(promptBeforeExit.isSelected());
|
||||||
}//GEN-LAST:event_promptBeforeExitActionPerformed
|
}//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
|
* Set the whether the a rule for detecting encryption programs will be
|
||||||
* added to the rules in this config
|
* added to the rules in this config
|
||||||
@ -588,6 +602,7 @@ final class ConfigVisualPanel2 extends JPanel {
|
|||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JTextField configFileTextField;
|
private javax.swing.JTextField configFileTextField;
|
||||||
|
private javax.swing.JCheckBox createVHDCheckBox;
|
||||||
private javax.swing.JLabel daysIncludedLabel;
|
private javax.swing.JLabel daysIncludedLabel;
|
||||||
private javax.swing.JButton deleteRuleButton;
|
private javax.swing.JButton deleteRuleButton;
|
||||||
private javax.swing.JTextField descriptionEditTextField;
|
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
|
* Update the panel to reflect the rules in the current config
|
||||||
*
|
*
|
||||||
* @param configFilePath path of the config file being modified
|
* @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
|
* @param rowSelectionkey the name of the rule to select by default
|
||||||
*/
|
*/
|
||||||
private void updatePanel(String configFilePath, LogicalImagerConfig config, String rowSelectionkey) {
|
private void updatePanel(String configFilePath, LogicalImagerConfig config, String rowSelectionkey) {
|
||||||
configFileTextField.setText(configFilePath);
|
configFileTextField.setText(configFilePath);
|
||||||
finalizeImageWriter.setSelected(config.isFinalizeImageWriter());
|
finalizeImageWriter.setSelected(config.isFinalizeImageWriter());
|
||||||
promptBeforeExit.setSelected(config.isPromptBeforeExit());
|
promptBeforeExit.setSelected(config.isPromptBeforeExit());
|
||||||
|
createVHDCheckBox.setSelected(config.isCreateVHD());
|
||||||
LogicalImagerRuleSet ruleSet = getRuleSetFromCurrentConfig();
|
LogicalImagerRuleSet ruleSet = getRuleSetFromCurrentConfig();
|
||||||
flagEncryptionProgramsCheckBox.setSelected(ruleSet.find(EncryptionProgramsRule.getName()) != null);
|
flagEncryptionProgramsCheckBox.setSelected(ruleSet.find(EncryptionProgramsRule.getName()) != null);
|
||||||
RulesTableModel rulesTableModel = new RulesTableModel();
|
RulesTableModel rulesTableModel = new RulesTableModel();
|
||||||
|
@ -42,6 +42,10 @@ class LogicalImagerConfig {
|
|||||||
@Expose(serialize = true)
|
@Expose(serialize = true)
|
||||||
private boolean promptBeforeExit;
|
private boolean promptBeforeExit;
|
||||||
|
|
||||||
|
@SerializedName("create-VHD")
|
||||||
|
@Expose(serialize = true)
|
||||||
|
private boolean createVHD;
|
||||||
|
|
||||||
@SerializedName("rule-sets")
|
@SerializedName("rule-sets")
|
||||||
@Expose(serialize = true)
|
@Expose(serialize = true)
|
||||||
private List<LogicalImagerRuleSet> ruleSets;
|
private List<LogicalImagerRuleSet> ruleSets;
|
||||||
@ -50,6 +54,7 @@ class LogicalImagerConfig {
|
|||||||
this.version = CURRENT_VERSION;
|
this.version = CURRENT_VERSION;
|
||||||
this.finalizeImageWriter = false;
|
this.finalizeImageWriter = false;
|
||||||
this.promptBeforeExit = true;
|
this.promptBeforeExit = true;
|
||||||
|
this.createVHD = false;
|
||||||
this.ruleSets = new ArrayList<>();
|
this.ruleSets = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +65,7 @@ class LogicalImagerConfig {
|
|||||||
this.version = CURRENT_VERSION;
|
this.version = CURRENT_VERSION;
|
||||||
this.finalizeImageWriter = finalizeImageWriter;
|
this.finalizeImageWriter = finalizeImageWriter;
|
||||||
this.promptBeforeExit = true;
|
this.promptBeforeExit = true;
|
||||||
|
this.createVHD = false;
|
||||||
this.ruleSets = ruleSets;
|
this.ruleSets = ruleSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +77,7 @@ class LogicalImagerConfig {
|
|||||||
this.version = version;
|
this.version = version;
|
||||||
this.finalizeImageWriter = finalizeImageWriter;
|
this.finalizeImageWriter = finalizeImageWriter;
|
||||||
this.promptBeforeExit = true;
|
this.promptBeforeExit = true;
|
||||||
|
this.createVHD = false;
|
||||||
this.ruleSets = ruleSets;
|
this.ruleSets = ruleSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,11 +85,13 @@ class LogicalImagerConfig {
|
|||||||
String version,
|
String version,
|
||||||
boolean finalizeImageWriter,
|
boolean finalizeImageWriter,
|
||||||
boolean promptBeforeExit,
|
boolean promptBeforeExit,
|
||||||
|
boolean createVHD,
|
||||||
List<LogicalImagerRuleSet> ruleSets
|
List<LogicalImagerRuleSet> ruleSets
|
||||||
) {
|
) {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.finalizeImageWriter = finalizeImageWriter;
|
this.finalizeImageWriter = finalizeImageWriter;
|
||||||
this.promptBeforeExit = promptBeforeExit;
|
this.promptBeforeExit = promptBeforeExit;
|
||||||
|
this.createVHD = createVHD;
|
||||||
this.ruleSets = ruleSets;
|
this.ruleSets = ruleSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +123,14 @@ class LogicalImagerConfig {
|
|||||||
this.promptBeforeExit = promptBeforeExit;
|
this.promptBeforeExit = promptBeforeExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isCreateVHD() {
|
||||||
|
return createVHD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCreateVHD(boolean createVHD) {
|
||||||
|
this.createVHD = createVHD;
|
||||||
|
}
|
||||||
|
|
||||||
List<LogicalImagerRuleSet> getRuleSets() {
|
List<LogicalImagerRuleSet> getRuleSets() {
|
||||||
return ruleSets;
|
return ruleSets;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ class LogicalImagerConfigDeserializer implements JsonDeserializer<LogicalImagerC
|
|||||||
String version = LogicalImagerConfig.getCurrentVersion();
|
String version = LogicalImagerConfig.getCurrentVersion();
|
||||||
boolean finalizeImageWriter = false;
|
boolean finalizeImageWriter = false;
|
||||||
boolean promptBeforeExit = true;
|
boolean promptBeforeExit = true;
|
||||||
|
boolean createVHD = false;
|
||||||
|
|
||||||
final JsonObject jsonObject = je.getAsJsonObject();
|
final JsonObject jsonObject = je.getAsJsonObject();
|
||||||
final JsonElement jsonVersion = jsonObject.get("version"); // NON-NLS
|
final JsonElement jsonVersion = jsonObject.get("version"); // NON-NLS
|
||||||
@ -63,6 +64,11 @@ class LogicalImagerConfigDeserializer implements JsonDeserializer<LogicalImagerC
|
|||||||
promptBeforeExit = jsonPromptBeforeExit.getAsBoolean();
|
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
|
JsonArray asJsonArray = jsonObject.get("rule-sets").getAsJsonArray(); // NON-NLS
|
||||||
if (asJsonArray == null) {
|
if (asJsonArray == null) {
|
||||||
throw new JsonParseException(Bundle.LogicalImagerConfigDeserializer_missingRuleSetException());
|
throw new JsonParseException(Bundle.LogicalImagerConfigDeserializer_missingRuleSetException());
|
||||||
@ -80,7 +86,7 @@ class LogicalImagerConfigDeserializer implements JsonDeserializer<LogicalImagerC
|
|||||||
LogicalImagerRuleSet ruleSet = new LogicalImagerRuleSet(setName, rules);
|
LogicalImagerRuleSet ruleSet = new LogicalImagerRuleSet(setName, rules);
|
||||||
ruleSets.add(ruleSet);
|
ruleSets.add(ruleSet);
|
||||||
}
|
}
|
||||||
return new LogicalImagerConfig(version, finalizeImageWriter, promptBeforeExit, ruleSets);
|
return new LogicalImagerConfig(version, finalizeImageWriter, promptBeforeExit, createVHD, ruleSets);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<LogicalImagerRule> parseRules(JsonArray asJsonArray) {
|
private List<LogicalImagerRule> parseRules(JsonArray asJsonArray) {
|
||||||
|
@ -23,6 +23,7 @@ import java.io.File;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -31,19 +32,22 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
import org.sleuthkit.autopsy.datamodel.utils.LocalFileImporter;
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.Blackboard;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.LocalFilesDataSource;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
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
|
* SearchResults.txt and users.txt files to report - add an image data source to the
|
||||||
* case database.
|
* 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 Logger LOGGER = Logger.getLogger(AddLogicalImageTask.class.getName());
|
||||||
private final static String SEARCH_RESULTS_TXT = "SearchResults.txt"; //NON-NLS
|
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 USERS_TXT = "users.txt"; //NON-NLS
|
||||||
private final static String MODULE_NAME = "Logical Imager"; //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 src;
|
||||||
private final File dest;
|
private final File dest;
|
||||||
private final DataSourceProcessorCallback callback;
|
private final DataSourceProcessorCallback callback;
|
||||||
@ -64,20 +72,30 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
|
|||||||
private final Blackboard blackboard;
|
private final Blackboard blackboard;
|
||||||
private final Case currentCase;
|
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,
|
AddLogicalImageTask(String deviceId,
|
||||||
List<String> imagePaths,
|
|
||||||
String timeZone,
|
String timeZone,
|
||||||
File src, File dest,
|
File src, File dest,
|
||||||
DataSourceProcessorProgressMonitor progressMonitor,
|
DataSourceProcessorProgressMonitor progressMonitor,
|
||||||
DataSourceProcessorCallback callback
|
DataSourceProcessorCallback callback
|
||||||
) throws NoCurrentCaseException {
|
) throws NoCurrentCaseException {
|
||||||
super(deviceId, imagePaths, timeZone, progressMonitor, callback);
|
this.deviceId = deviceId;
|
||||||
|
this.timeZone = timeZone;
|
||||||
this.src = src;
|
this.src = src;
|
||||||
this.dest = dest;
|
this.dest = dest;
|
||||||
this.progressMonitor = progressMonitor;
|
this.progressMonitor = progressMonitor;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.currentCase = Case.getCurrentCase();
|
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} - src", "# {1} - dest", "AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}",
|
||||||
"# {0} - file", "AddLogicalImageTask.addingToReport=Adding {0} to report",
|
"# {0} - file", "AddLogicalImageTask.addingToReport=Adding {0} to report",
|
||||||
"# {0} - file", "AddLogicalImageTask.doneAddingToReport=Done 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.addingInterestingFiles=Adding search results as interesting files",
|
||||||
"AddLogicalImageTask.doneAddingInterestingFiles=Done 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} - 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
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
List<String> errorList = new ArrayList<>();
|
List<String> errorList = new ArrayList<>();
|
||||||
List<Content> emptyDataSources = 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
|
// Add the SearchResults.txt and users.txt to the case report
|
||||||
String resultsFilename;
|
String resultsFilename;
|
||||||
if (Paths.get(dest.toString(), SEARCH_RESULTS_TXT).toFile().exists()) {
|
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);
|
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingToReport(resultsFilename));
|
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingToReport(resultsFilename));
|
||||||
String status = addReport(Paths.get(dest.toString(), resultsFilename), resultsFilename + " " + src.getName());
|
String status = addReport(Paths.get(dest.toString(), resultsFilename), resultsFilename + " " + src.getName());
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
@ -127,17 +173,101 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
|
|||||||
}
|
}
|
||||||
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(USERS_TXT));
|
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(USERS_TXT));
|
||||||
|
|
||||||
super.run();
|
// Get all VHD files in the dest directory
|
||||||
if (super.getResult() == DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS) {
|
List<String> imagePaths = new ArrayList<>();
|
||||||
callback.done(super.getResult(), super.getErrorMessages(), super.getNewDataSources());
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFiles());
|
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFiles());
|
||||||
addInterestingFiles(dest, Paths.get(dest.toString(), resultsFilename));
|
addInterestingFiles(Paths.get(dest.toString(), resultsFilename), createVHD);
|
||||||
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingInterestingFiles());
|
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) {
|
} catch (IOException | TskCoreException ex) {
|
||||||
errorList.add(Bundle.AddLogicalImageTask_failedToAddInterestingFiles(ex.getMessage()));
|
errorList.add(Bundle.AddLogicalImageTask_failedToAddInterestingFiles(ex.getMessage()));
|
||||||
LOGGER.log(Level.SEVERE, "Failed to add interesting files", ex); // NON-NLS
|
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) {
|
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()) {
|
for (Map.Entry<Long, List<String>> entry : imagePaths.entrySet()) {
|
||||||
Long key = entry.getKey();
|
Long key = entry.getKey();
|
||||||
List<String> names = entry.getValue();
|
List<String> names = entry.getValue();
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
imagePathToObjIdMap.put(name, key);
|
imagePathToObjId.put(name, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return imagePathToObjIdMap;
|
return imagePathToObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Messages({
|
@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} - 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 {
|
private void addInterestingFiles(Path resultsPath, boolean createVHD) throws IOException, TskCoreException {
|
||||||
Map<Long, List<String>> imagePaths = currentCase.getSleuthkitCase().getImagePaths();
|
Map<Long, List<String>> objIdToimagePathsMap = currentCase.getSleuthkitCase().getImagePaths();
|
||||||
Map<String, Long> imagePathToObjIdMap = imagePathsToDataSourceObjId(imagePaths);
|
imagePathToObjIdMap = imagePathsToDataSourceObjId(objIdToimagePathsMap);
|
||||||
|
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(
|
||||||
new FileInputStream(resultsPath.toFile()), "UTF8"))) { // NON-NLS
|
new FileInputStream(resultsPath.toFile()), "UTF8"))) { // NON-NLS
|
||||||
|
List<BlackboardArtifact> artifacts = new ArrayList<>();
|
||||||
String line;
|
String line;
|
||||||
br.readLine(); // skip the header line
|
br.readLine(); // skip the header line
|
||||||
int lineNumber = 2;
|
int lineNumber = 2;
|
||||||
while ((line = br.readLine()) != null) {
|
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
|
String[] fields = line.split("\t", -1); // NON-NLS
|
||||||
if (fields.length != 9) {
|
if (fields.length != 14) {
|
||||||
throw new IOException(Bundle.AddLogicalImageTask_notEnoughFields(lineNumber, fields.length, 9));
|
throw new IOException(Bundle.AddLogicalImageTask_notEnoughFields(lineNumber, fields.length, 14));
|
||||||
}
|
}
|
||||||
String vhdFilename = fields[0];
|
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 fileSystemOffsetStr = fields[1];
|
||||||
String fileMetaAddressStr = fields[2];
|
String fileMetaAddressStr = fields[2];
|
||||||
// String extractStatusStr = fields[3];
|
// String extractStatusStr = fields[3];
|
||||||
@ -216,37 +360,151 @@ final class AddLogicalImageTask extends AddMultipleImageTask {
|
|||||||
String ruleName = fields[5];
|
String ruleName = fields[5];
|
||||||
// String description = fields[6];
|
// String description = fields[6];
|
||||||
String filename = fields[7];
|
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
|
if (lineNumber % 100 == 0) {
|
||||||
dataSourceObjId.toString(), fileMetaAddressStr, filename);
|
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);
|
List<AbstractFile> matchedFiles = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(query);
|
||||||
for (AbstractFile file : matchedFiles) {
|
for (AbstractFile file : matchedFiles) {
|
||||||
addInterestingFile(file, ruleSetName, ruleName);
|
addInterestingFileToArtifacts(file, ruleSetName, ruleName, artifacts);
|
||||||
}
|
}
|
||||||
lineNumber++;
|
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<>();
|
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||||
BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, ruleSetName);
|
BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, ruleSetName);
|
||||||
attributes.add(setNameAttribute);
|
attributes.add(setNameAttribute);
|
||||||
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, MODULE_NAME, ruleName);
|
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, MODULE_NAME, ruleName);
|
||||||
attributes.add(ruleNameAttribute);
|
attributes.add(ruleNameAttribute);
|
||||||
org.sleuthkit.datamodel.Blackboard tskBlackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard();
|
if (!blackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
|
||||||
if (!tskBlackboard.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());
|
||||||
BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
|
|
||||||
artifact.addAttributes(attributes);
|
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 {
|
try {
|
||||||
// index the artifact for keyword search
|
trans = skCase.beginTransaction();
|
||||||
blackboard.indexArtifact(artifact);
|
LocalFilesDataSource localFilesDataSource = skCase.addLocalFilesDataSource(deviceId, this.src.getName(), timeZone, trans);
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
LocalFileImporter fileImporter = new LocalFileImporter(skCase, trans);
|
||||||
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
|
|
||||||
|
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 {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,10 @@ package org.sleuthkit.autopsy.logicalimager.dsp;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -42,27 +42,34 @@ import org.sleuthkit.datamodel.TskFileRange;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@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());
|
private static final Logger LOGGER = Logger.getLogger(AddMultipleImagesTask.class.getName());
|
||||||
public static final String TSK_FS_TYPE_UNKNOWN_ERR_MSG = Bundle.AddMultipleImageTask_fsTypeUnknownErr();
|
public static final String TSK_FS_TYPE_UNKNOWN_ERR_MSG = Bundle.AddMultipleImagesTask_fsTypeUnknownErr();
|
||||||
private static final long TWO_GB = 2000000000L;
|
private static final long TWO_GB = 2000000000L;
|
||||||
private final String deviceId;
|
private final String deviceId;
|
||||||
private final List<String> imageFilePaths;
|
private final List<String> imageFilePaths;
|
||||||
private final String timeZone;
|
private final String timeZone;
|
||||||
private final long chunkSize = TWO_GB;
|
private final long chunkSize = TWO_GB;
|
||||||
private final DataSourceProcessorProgressMonitor progressMonitor;
|
private final DataSourceProcessorProgressMonitor progressMonitor;
|
||||||
private final DataSourceProcessorCallback callback;
|
|
||||||
private final Case currentCase;
|
private final Case currentCase;
|
||||||
|
|
||||||
private boolean criticalErrorOccurred;
|
private boolean criticalErrorOccurred;
|
||||||
private volatile boolean cancelled;
|
private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess = null;
|
||||||
|
private List<String> errorMessages = new ArrayList<>();
|
||||||
private List<Content> newDataSources;
|
|
||||||
private List<String> errorMessages;
|
|
||||||
private DataSourceProcessorResult result;
|
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.
|
* Constructs a runnable that adds multiple image files to a case database.
|
||||||
@ -78,41 +85,57 @@ class AddMultipleImageTask implements Runnable {
|
|||||||
* java.util.TimeZone.getID.
|
* java.util.TimeZone.getID.
|
||||||
* @param progressMonitor Progress monitor for reporting progress during
|
* @param progressMonitor Progress monitor for reporting progress during
|
||||||
* processing.
|
* processing.
|
||||||
* @param callback Callback to call when processing is done.
|
|
||||||
*
|
*
|
||||||
* @throws NoCurrentCaseException The exception if there is no open case.
|
* @throws NoCurrentCaseException The exception if there is no open case.
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@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",
|
"# {0} - deviceId", "# {1} - exceptionMessage",
|
||||||
"AddMultipleImageTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device %s: %s",})
|
"AddMultipleImagesTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device {0}: {1}",})
|
||||||
AddMultipleImageTask(String deviceId, List<String> imageFilePaths, String timeZone,
|
AddMultipleImagesTask(String deviceId, List<String> imageFilePaths, String timeZone,
|
||||||
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) throws NoCurrentCaseException {
|
DataSourceProcessorProgressMonitor progressMonitor) throws NoCurrentCaseException {
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
this.imageFilePaths = imageFilePaths;
|
this.imageFilePaths = imageFilePaths;
|
||||||
this.timeZone = timeZone;
|
this.timeZone = timeZone;
|
||||||
this.callback = callback;
|
|
||||||
this.progressMonitor = progressMonitor;
|
this.progressMonitor = progressMonitor;
|
||||||
currentCase = Case.getCurrentCaseThrows();
|
currentCase = Case.getCurrentCaseThrows();
|
||||||
this.criticalErrorOccurred = false;
|
this.criticalErrorOccurred = false;
|
||||||
this.result = DataSourceProcessorResult.NO_ERRORS;
|
tskAddImageProcessLock = new Object();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Messages({
|
||||||
|
"AddMultipleImagesTask.cancelled=Cancellation: Add image process reverted",
|
||||||
|
})
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
newDataSources = new ArrayList<>();
|
|
||||||
errorMessages = new ArrayList<>();
|
errorMessages = new ArrayList<>();
|
||||||
|
newDataSources = new ArrayList<>();
|
||||||
|
List<Content> emptyDataSources = new ArrayList<>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to add the input image files as images.
|
* Try to add the input image files as images.
|
||||||
*/
|
*/
|
||||||
List<String> corruptedImageFilePaths = new ArrayList<>();
|
List<String> corruptedImageFilePaths = new ArrayList<>();
|
||||||
currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
|
|
||||||
try {
|
try {
|
||||||
|
currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
|
||||||
progressMonitor.setIndeterminate(true);
|
progressMonitor.setIndeterminate(true);
|
||||||
for (String imageFilePath : imageFilePaths) {
|
for (String imageFilePath : imageFilePaths) {
|
||||||
if (!cancelled) {
|
synchronized (tskAddImageProcessLock) {
|
||||||
addImageToCase(imageFilePath, newDataSources, corruptedImageFilePaths, errorMessages);
|
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 {
|
} finally {
|
||||||
@ -124,11 +147,11 @@ class AddMultipleImageTask implements Runnable {
|
|||||||
* single an unallocated space file with the device id as the root virtual
|
* single an unallocated space file with the device id as the root virtual
|
||||||
* directory name.
|
* directory name.
|
||||||
*/
|
*/
|
||||||
if (!cancelled && !corruptedImageFilePaths.isEmpty()) {
|
if (!tskAddImageProcessStopped && !corruptedImageFilePaths.isEmpty()) {
|
||||||
SleuthkitCase caseDatabase;
|
SleuthkitCase caseDatabase;
|
||||||
caseDatabase = currentCase.getSleuthkitCase();
|
caseDatabase = currentCase.getSleuthkitCase();
|
||||||
try {
|
try {
|
||||||
progressMonitor.setProgressText(Bundle.AddMultipleImageTask_addingFileAsLogicalFile(corruptedImageFilePaths.toString()));
|
progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_addingFileAsLogicalFile(corruptedImageFilePaths.toString()));
|
||||||
|
|
||||||
caseDatabase.acquireSingleUserCaseWriteLock();
|
caseDatabase.acquireSingleUserCaseWriteLock();
|
||||||
|
|
||||||
@ -146,14 +169,13 @@ class AddMultipleImageTask implements Runnable {
|
|||||||
start += TWO_GB;
|
start += TWO_GB;
|
||||||
sequence++;
|
sequence++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
double leftoverSize = imageSize - sequence * TWO_GB;
|
double leftoverSize = imageSize - sequence * TWO_GB;
|
||||||
fileRanges.add(new TskFileRange(start, (long)leftoverSize, sequence));
|
fileRanges.add(new TskFileRange(start, (long)leftoverSize, sequence));
|
||||||
|
|
||||||
caseDatabase.addLayoutFiles(dataSource, fileRanges);
|
caseDatabase.addLayoutFiles(dataSource, fileRanges);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
errorMessages.add(Bundle.AddMultipleImageTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
|
errorMessages.add(Bundle.AddMultipleImagesTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
|
||||||
criticalErrorOccurred = true;
|
criticalErrorOccurred = true;
|
||||||
} finally {
|
} finally {
|
||||||
caseDatabase.releaseSingleUserCaseWriteLock();
|
caseDatabase.releaseSingleUserCaseWriteLock();
|
||||||
@ -167,9 +189,6 @@ class AddMultipleImageTask implements Runnable {
|
|||||||
progressMonitor.setProgress(0);
|
progressMonitor.setProgress(0);
|
||||||
progressMonitor.setProgress(100);
|
progressMonitor.setProgress(100);
|
||||||
|
|
||||||
/*
|
|
||||||
* Pass the results back via the callback.
|
|
||||||
*/
|
|
||||||
if (criticalErrorOccurred) {
|
if (criticalErrorOccurred) {
|
||||||
result = DataSourceProcessorResult.CRITICAL_ERRORS;
|
result = DataSourceProcessorResult.CRITICAL_ERRORS;
|
||||||
} else if (!errorMessages.isEmpty()) {
|
} else if (!errorMessages.isEmpty()) {
|
||||||
@ -184,38 +203,50 @@ class AddMultipleImageTask implements Runnable {
|
|||||||
* partial processing of the input.
|
* partial processing of the input.
|
||||||
*/
|
*/
|
||||||
void cancelTask() {
|
void cancelTask() {
|
||||||
LOGGER.log(Level.WARNING, "AddMultipleImageTask cancelled, processing may be incomplete"); // NON-NLS
|
LOGGER.log(Level.WARNING, "AddMultipleImagesTask cancelled, processing may be incomplete"); // NON-NLS
|
||||||
cancelled = true;
|
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.
|
* Attempts to add an input image to the case.
|
||||||
*
|
*
|
||||||
* @param imageFilePath The image file path.
|
* @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
|
* @param corruptedImageFilePaths If the image cannot be added because
|
||||||
* Sleuth Kit cannot detect a filesystem,
|
* Sleuth Kit cannot detect a filesystem,
|
||||||
* the image file path is added to this list
|
* the image file path is added to this list
|
||||||
* for later addition as an unallocated space file.
|
* for later addition as an unallocated space file.
|
||||||
* @param errorMessages If there are any error messages, the
|
* @param errorMessages If there are any error messages, the
|
||||||
* error messages are added to this list for
|
* error messages are added to this list for
|
||||||
* eventual return to the caller via the
|
* eventual return to the caller via the getter
|
||||||
* callback.
|
* method.
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
"# {0} - imageFilePath", "AddMultipleImageTask.adding=Adding: {0}",
|
"# {0} - imageFilePath", "AddMultipleImagesTask.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", "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}",
|
"# {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", "AddMultipleImageTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}",})
|
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImagesTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}",})
|
||||||
private void addImageToCase(String imageFilePath, List<Content> newDataSources, List<String> corruptedImageFilePaths, List<String> errorMessages) {
|
private void run(String imageFilePath, List<String> corruptedImageFilePaths, List<String> errorMessages) {
|
||||||
/*
|
/*
|
||||||
* Try to add the image to the case database as a data source.
|
* Try to add the image to the case database as a data source.
|
||||||
*/
|
*/
|
||||||
progressMonitor.setProgressText(Bundle.AddMultipleImageTask_adding(imageFilePath));
|
progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_adding(imageFilePath));
|
||||||
SleuthkitCase caseDatabase = currentCase.getSleuthkitCase();
|
|
||||||
SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess = caseDatabase.makeAddImageProcess(timeZone, false, false, "");
|
|
||||||
try {
|
try {
|
||||||
addImageProcess.run(deviceId, new String[]{imageFilePath});
|
addImageProcess.run(deviceId, new String[]{imageFilePath});
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
@ -228,31 +259,46 @@ class AddMultipleImageTask implements Runnable {
|
|||||||
*/
|
*/
|
||||||
corruptedImageFilePaths.add(imageFilePath);
|
corruptedImageFilePaths.add(imageFilePath);
|
||||||
} else {
|
} else {
|
||||||
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
|
errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
|
||||||
criticalErrorOccurred = true;
|
criticalErrorOccurred = true;
|
||||||
}
|
}
|
||||||
/*
|
} catch (TskDataException ex) {
|
||||||
* Either way, the add image process needs to be reverted.
|
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 {
|
try {
|
||||||
addImageProcess.revert();
|
addImageProcess.revert();
|
||||||
} catch (TskCoreException e) {
|
} catch (TskCoreException ex) {
|
||||||
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorReverting(imageFilePath, deviceId, e.getLocalizedMessage()));
|
errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorReverting(imageFilePath, deviceId, ex.getLocalizedMessage()));
|
||||||
criticalErrorOccurred = true;
|
criticalErrorOccurred = true;
|
||||||
}
|
}
|
||||||
return;
|
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
|
* 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
|
* image from the case database, and add it to the list of new data
|
||||||
* sources to be returned via the callback.
|
* sources to be returned via the getter method.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
long imageId = addImageProcess.commit();
|
long imageId = addImageProcess.commit();
|
||||||
Image dataSource = caseDatabase.getImageById(imageId);
|
Image dataSource = currentCase.getSleuthkitCase().getImageById(imageId);
|
||||||
newDataSources.add(dataSource);
|
newDataSources.add(dataSource);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -261,7 +307,7 @@ class AddMultipleImageTask implements Runnable {
|
|||||||
*/
|
*/
|
||||||
String verificationError = dataSource.verifyImageSize();
|
String verificationError = dataSource.verifyImageSize();
|
||||||
if (!verificationError.isEmpty()) {
|
if (!verificationError.isEmpty()) {
|
||||||
errorMessages.add(Bundle.AddMultipleImageTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
|
errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
/*
|
/*
|
||||||
@ -269,21 +315,33 @@ class AddMultipleImageTask implements Runnable {
|
|||||||
* for the newly added image failed. Either way, this is a critical
|
* for the newly added image failed. Either way, this is a critical
|
||||||
* error.
|
* error.
|
||||||
*/
|
*/
|
||||||
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
|
errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
|
||||||
criticalErrorOccurred = true;
|
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() {
|
public List<String> getErrorMessages() {
|
||||||
return errorMessages;
|
return errorMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the result the AddMultipleImagesTask run
|
||||||
|
* @return The result of the run
|
||||||
|
*/
|
||||||
public DataSourceProcessorResult getResult() {
|
public DataSourceProcessorResult getResult() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the new data sources the AddMultipleImagesTask run
|
||||||
|
* @return The new data sources of the run
|
||||||
|
*/
|
||||||
|
public List<Content> getNewDataSources() {
|
||||||
|
return newDataSources;
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,15 +2,28 @@
|
|||||||
# To change this template file, choose Tools | Templates
|
# To change this template file, choose Tools | Templates
|
||||||
# and open the template in the editor.
|
# 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
|
AddLogicalImageTask.addingInterestingFiles=Adding search results as interesting files
|
||||||
# {0} - file
|
# {0} - file
|
||||||
AddLogicalImageTask.addingToReport=Adding {0} to report
|
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
|
# {0} - SearchResults.txt
|
||||||
# {1} - directory
|
# {1} - directory
|
||||||
AddLogicalImageTask.cannotFindFiles=Cannot find {0} in {1}
|
AddLogicalImageTask.cannotFindFiles=Cannot find {0} in {1}
|
||||||
# {0} - src
|
# {0} - src
|
||||||
# {1} - dest
|
# {1} - dest
|
||||||
AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1}
|
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
|
AddLogicalImageTask.doneAddingInterestingFiles=Done adding search results as interesting files
|
||||||
# {0} - file
|
# {0} - file
|
||||||
AddLogicalImageTask.doneAddingToReport=Done adding {0} to report
|
AddLogicalImageTask.doneAddingToReport=Done adding {0} to report
|
||||||
@ -23,37 +36,45 @@ AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1}
|
|||||||
# {0} - src
|
# {0} - src
|
||||||
# {1} - dest
|
# {1} - dest
|
||||||
AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}
|
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
|
# {0} - line number
|
||||||
# {1} - fields length
|
# {1} - fields length
|
||||||
# {2} - expected length
|
# {2} - expected length
|
||||||
AddLogicalImageTask.notEnoughFields=File does not contain enough fields at line {0}, got {1}, expecting {2}
|
AddLogicalImageTask.notEnoughFields=File does not contain enough fields at line {0}, got {1}, expecting {2}
|
||||||
# {0} - imageFilePath
|
# {0} - imageFilePath
|
||||||
AddMultipleImageTask.adding=Adding: {0}
|
AddMultipleImagesTask.adding=Adding: {0}
|
||||||
# {0} - file
|
# {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
|
# {0} - imageFilePath
|
||||||
# {1} - deviceId
|
# {1} - deviceId
|
||||||
# {2} - exceptionMessage
|
# {2} - exceptionMessage
|
||||||
AddMultipleImageTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}
|
AddMultipleImagesTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}
|
||||||
# {0} - imageFilePath
|
# {0} - imageFilePath
|
||||||
# {1} - deviceId
|
# {1} - deviceId
|
||||||
# {2} - exceptionMessage
|
# {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
|
# {0} - deviceId
|
||||||
# {1} - exceptionMessage
|
# {1} - exceptionMessage
|
||||||
AddMultipleImageTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device %s: %s
|
AddMultipleImagesTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device {0}: {1}
|
||||||
AddMultipleImageTask.fsTypeUnknownErr=Cannot determine file system type
|
AddMultipleImagesTask.fsTypeUnknownErr=Cannot determine file system type
|
||||||
# {0} - imageFilePath
|
# {0} - imageFilePath
|
||||||
# {1} - deviceId
|
# {1} - deviceId
|
||||||
# {2} - exceptionMessage
|
# {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.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
|
# {0} - directory
|
||||||
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
|
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
|
||||||
# {0} - directory
|
# {0} - directory
|
||||||
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
|
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
|
||||||
# {0} - file
|
|
||||||
LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}
|
|
||||||
# {0} - imageDirPath
|
# {0} - imageDirPath
|
||||||
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
|
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
|
||||||
LogicalImagerDSProcessor.noCurrentCase=No current case
|
LogicalImagerDSProcessor.noCurrentCase=No current case
|
||||||
|
@ -19,15 +19,15 @@
|
|||||||
package org.sleuthkit.autopsy.logicalimager.dsp;
|
package org.sleuthkit.autopsy.logicalimager.dsp;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import static javax.swing.JOptionPane.YES_OPTION;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import org.openide.util.lookup.ServiceProviders;
|
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.DataSourceProcessor;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
|
||||||
import org.sleuthkit.datamodel.Content;
|
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} - imageDirPath", "LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.",
|
||||||
"# {0} - directory", "LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}",
|
"# {0} - directory", "LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}",
|
||||||
"# {0} - directory", "LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists",
|
"# {0} - directory", "LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists",
|
||||||
"# {0} - file", "LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}",
|
"LogicalImagerDSProcessor.destinationDirectoryConfirmation=Destination directory confirmation",
|
||||||
"LogicalImagerDSProcessor.noCurrentCase=No current case",})
|
"# {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
|
@Override
|
||||||
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||||
configPanel.storeSettings();
|
configPanel.storeSettings();
|
||||||
@ -164,44 +167,27 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor {
|
|||||||
File dest = Paths.get(logicalImagerDir.toString(), imageDirPath.getFileName().toString()).toFile();
|
File dest = Paths.get(logicalImagerDir.toString(), imageDirPath.getFileName().toString()).toFile();
|
||||||
if (dest.exists()) {
|
if (dest.exists()) {
|
||||||
// Destination directory already exists
|
// Destination directory already exists
|
||||||
|
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());
|
String msg = Bundle.LogicalImagerDSProcessor_directoryAlreadyExists(dest.toString());
|
||||||
errorList.add(msg);
|
errorList.add(msg);
|
||||||
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
|
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
File src = imageDirPath.toFile();
|
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 {
|
try {
|
||||||
String deviceId = UUID.randomUUID().toString();
|
String deviceId = UUID.randomUUID().toString();
|
||||||
String timeZone = Calendar.getInstance().getTimeZone().getID();
|
String timeZone = Calendar.getInstance().getTimeZone().getID();
|
||||||
run(deviceId, imagePaths,
|
run(deviceId, timeZone, src, dest,
|
||||||
timeZone, src, dest,
|
|
||||||
progressMonitor, callback);
|
progressMonitor, callback);
|
||||||
} catch (NoCurrentCaseException ex) {
|
} catch (NoCurrentCaseException ex) {
|
||||||
String msg = Bundle.LogicalImagerDSProcessor_noCurrentCase();
|
String msg = Bundle.LogicalImagerDSProcessor_noCurrentCase();
|
||||||
@ -220,7 +206,6 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor {
|
|||||||
* @param deviceId An ASCII-printable identifier for the device
|
* @param deviceId An ASCII-printable identifier for the device
|
||||||
* associated with the data source that is intended
|
* associated with the data source that is intended
|
||||||
* to be unique across multiple cases (e.g., a UUID).
|
* 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
|
* @param timeZone The time zone to use when processing dates and
|
||||||
* times for the image, obtained from
|
* times for the image, obtained from
|
||||||
* java.util.TimeZone.getID.
|
* java.util.TimeZone.getID.
|
||||||
@ -230,13 +215,14 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor {
|
|||||||
* processing.
|
* processing.
|
||||||
* @param callback Callback to call when processing is done.
|
* @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,
|
File src, File dest,
|
||||||
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback
|
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback
|
||||||
) throws NoCurrentCaseException {
|
) throws NoCurrentCaseException {
|
||||||
addLogicalImageTask = new AddLogicalImageTask(deviceId, imagePaths, timeZone, src, dest,
|
addLogicalImageTask = new AddLogicalImageTask(deviceId, timeZone, src, dest,
|
||||||
progressMonitor, callback);
|
progressMonitor, callback);
|
||||||
new Thread(addLogicalImageTask).start();
|
Thread thread = new Thread(addLogicalImageTask);
|
||||||
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -333,10 +333,20 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (vhdFiles.length == 0) {
|
if (vhdFiles.length == 0) {
|
||||||
|
// 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));
|
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path));
|
||||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
|
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
manualImageDirPath = Paths.get(path);
|
manualImageDirPath = Paths.get(path);
|
||||||
setNormalMessage(path);
|
setNormalMessage(path);
|
||||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||||
@ -360,11 +370,11 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean dirHasVhdFiles(File dir) {
|
private boolean dirHasImagerResult(File dir) {
|
||||||
File[] fList = dir.listFiles(new FilenameFilter() {
|
String[] fList = dir.list(new FilenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File dir, String name) {
|
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);
|
return (fList != null && fList.length != 0);
|
||||||
@ -382,9 +392,9 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
if (fList != null) {
|
if (fList != null) {
|
||||||
imageTableModel = new ImageTableModel();
|
imageTableModel = new ImageTableModel();
|
||||||
// Find all directories with name like Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
|
// 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) {
|
for (File file : fList) {
|
||||||
if (file.isDirectory() && dirHasVhdFiles(file)) {
|
if (file.isDirectory() && dirHasImagerResult(file)) {
|
||||||
String dir = file.getName();
|
String dir = file.getName();
|
||||||
Matcher m = regex.matcher(dir);
|
Matcher m = regex.matcher(dir);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
@ -508,7 +518,7 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
}
|
}
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
//unable to get this removable drive for default selection will try and select next removable drive by default
|
//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++;
|
i++;
|
||||||
|
@ -31,6 +31,9 @@ PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged f
|
|||||||
PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files
|
PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files
|
||||||
PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results
|
PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results
|
||||||
PortableCaseReportModule.generateReport.errorCopyingTags=Error copying tags
|
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
|
# {0} - attribute type name
|
||||||
PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}
|
PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}
|
||||||
PortableCaseReportModule.generateReport.interestingItemError=Error loading intersting items
|
PortableCaseReportModule.generateReport.interestingItemError=Error loading intersting items
|
||||||
|
@ -206,7 +206,7 @@ class PortableCaseInterestingItemsListPanel extends javax.swing.JPanel {
|
|||||||
*/
|
*/
|
||||||
private static class GetInterestingItemSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
|
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<>();
|
private final Map<String, Long> setCounts = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -36,6 +36,7 @@ import org.openide.modules.InstalledFileLocator;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
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.FileUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
@ -179,9 +180,12 @@ class PortableCaseReportModule implements ReportModule {
|
|||||||
"PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
|
"PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
|
||||||
"PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
|
"PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
|
||||||
"PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
|
"PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
|
||||||
|
"PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table",
|
||||||
"# {0} - attribute type name",
|
"# {0} - attribute type name",
|
||||||
"PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
|
"PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
|
||||||
"PortableCaseReportModule.generateReport.compressingCase=Compressing case...",
|
"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) {
|
void generateReport(String reportPath, PortableCaseOptions options, ReportProgressPanel progressPanel) {
|
||||||
@ -240,6 +244,14 @@ class PortableCaseReportModule implements ReportModule {
|
|||||||
return;
|
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
|
// Copy the selected tags
|
||||||
progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
|
progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
|
||||||
try {
|
try {
|
||||||
@ -358,7 +370,7 @@ class PortableCaseReportModule implements ReportModule {
|
|||||||
|
|
||||||
File reportsFolder = Paths.get(caseFolder.toString(), "Reports").toFile();
|
File reportsFolder = Paths.get(caseFolder.toString(), "Reports").toFile();
|
||||||
if(!reportsFolder.mkdir()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +378,7 @@ class PortableCaseReportModule implements ReportModule {
|
|||||||
CaseUcoFormatExporter.export(tagNames, setNames, reportsFolder, progressPanel);
|
CaseUcoFormatExporter.export(tagNames, setNames, reportsFolder, progressPanel);
|
||||||
} catch (IOException | SQLException | NoCurrentCaseException | TskCoreException ex) {
|
} catch (IOException | SQLException | NoCurrentCaseException | TskCoreException ex) {
|
||||||
handleError("Problem while generating CASE-UCO report",
|
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)
|
// 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
|
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.
|
* Add all files with a given tag to the portable case.
|
||||||
*
|
*
|
||||||
@ -507,16 +535,88 @@ class PortableCaseReportModule implements ReportModule {
|
|||||||
|
|
||||||
Content content = tag.getContent();
|
Content content = tag.getContent();
|
||||||
if (content instanceof AbstractFile) {
|
if (content instanceof AbstractFile) {
|
||||||
|
|
||||||
long newFileId = copyContentToPortableCase(content, progressPanel);
|
long newFileId = copyContentToPortableCase(content, progressPanel);
|
||||||
|
|
||||||
// Tag the file
|
// Tag the file
|
||||||
if (! oldTagNameToNewTagName.containsKey(tag.getName())) {
|
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
|
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.
|
* Add all artifacts with a given tag to the portable case.
|
||||||
|
@ -205,7 +205,7 @@ class PortableCaseTagsListPanel extends javax.swing.JPanel {
|
|||||||
*/
|
*/
|
||||||
static class GetTagCountsCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
|
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<>();
|
private final Map<Long, Long> tagCounts = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -136,6 +136,7 @@ final class TikaTextExtractor implements TextExtractor {
|
|||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS
|
||||||
"application/pdf"); //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 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());
|
private static final Logger AUTOPSY_LOGGER = Logger.getLogger(TikaTextExtractor.class.getName());
|
||||||
|
|
||||||
|
@ -356,12 +356,8 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
scene.addEventFilter(KeyEvent.KEY_PRESSED, keyEvent -> {
|
scene.addEventFilter(KeyEvent.KEY_PRESSED, keyEvent -> {
|
||||||
if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
|
if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
|
||||||
new Back(controller).handle(null);
|
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)) {
|
} else if (new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
|
||||||
new Forward(controller).handle(null);
|
new Forward(controller).handle(null);
|
||||||
} else if (new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCodeCombination.SHIFT_DOWN).match(keyEvent)) {
|
|
||||||
new Forward(controller).handle(null);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2018 Basis Technology Corp.
|
* Copyright 2018-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -22,7 +22,9 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
|
import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
|
||||||
@ -35,6 +37,8 @@ import org.sleuthkit.datamodel.Content;
|
|||||||
*/
|
*/
|
||||||
public final class IngestJobRunner {
|
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.
|
* Runs an ingest job, blocking until the job is completed.
|
||||||
*
|
*
|
||||||
@ -51,7 +55,7 @@ public final class IngestJobRunner {
|
|||||||
Object ingestMonitor = new Object();
|
Object ingestMonitor = new Object();
|
||||||
IngestJobCompletiontListener completiontListener = new IngestJobCompletiontListener(ingestMonitor);
|
IngestJobCompletiontListener completiontListener = new IngestJobCompletiontListener(ingestMonitor);
|
||||||
IngestManager ingestManager = IngestManager.getInstance();
|
IngestManager ingestManager = IngestManager.getInstance();
|
||||||
ingestManager.addIngestJobEventListener(completiontListener);
|
ingestManager.addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, completiontListener);
|
||||||
try {
|
try {
|
||||||
synchronized (ingestMonitor) {
|
synchronized (ingestMonitor) {
|
||||||
IngestJobStartResult jobStartResult = ingestManager.beginIngestJob(dataSources, settings);
|
IngestJobStartResult jobStartResult = ingestManager.beginIngestJob(dataSources, settings);
|
||||||
|
@ -28,6 +28,7 @@ import org.opencv.core.Core;
|
|||||||
*/
|
*/
|
||||||
public final class OpenCvLoader {
|
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 final Logger logger = Logger.getLogger(OpenCvLoader.class.getName());
|
||||||
private static boolean openCvLoaded;
|
private static boolean openCvLoaded;
|
||||||
private static UnsatisfiedLinkError exception = null; // Deprecated
|
private static UnsatisfiedLinkError exception = null; // Deprecated
|
||||||
|
@ -142,6 +142,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
ControlEventType.SHUTDOWN.toString(),
|
ControlEventType.SHUTDOWN.toString(),
|
||||||
Event.CANCEL_JOB.toString(),
|
Event.CANCEL_JOB.toString(),
|
||||||
Event.REPROCESS_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 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 String JOB_STATUS_PUBLISHING_THREAD_NAME = "AIM-job-status-event-publisher-%d";
|
||||||
private static final long MAX_MISSED_JOB_STATUS_UPDATES = 10;
|
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();
|
Path caseDirectoryPath = currentJob.getCaseDirectoryPath();
|
||||||
AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath);
|
AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath);
|
||||||
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
|
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
|
||||||
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
|
||||||
try {
|
try {
|
||||||
synchronized (ingestLock) {
|
synchronized (ingestLock) {
|
||||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(AutoIngestUserPreferences.getAutoModeIngestModuleContextString());
|
IngestJobSettings ingestJobSettings = new IngestJobSettings(AutoIngestUserPreferences.getAutoModeIngestModuleContextString());
|
||||||
|
@ -26,7 +26,9 @@ import java.nio.charset.Charset;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.apache.commons.io.FileUtils;
|
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 Logger LOGGER = Logger.getLogger(MultiUserTestTool.class.getName());
|
||||||
private static final String TEST_FILE_NAME = "AutopsyTempFile";
|
private static final String TEST_FILE_NAME = "AutopsyTempFile";
|
||||||
private static final Object INGEST_LOCK = new Object();
|
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");
|
static final String MULTI_USER_TEST_SUCCESSFUL = NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.Success");
|
||||||
|
|
||||||
private MultiUserTestTool() {
|
private MultiUserTestTool() {
|
||||||
@ -228,7 +231,9 @@ class MultiUserTestTool {
|
|||||||
* @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
|
* @param rootOutputDirectory Full path to directory in which the case will
|
||||||
* be created
|
* be created
|
||||||
|
*
|
||||||
* @return Case object
|
* @return Case object
|
||||||
|
*
|
||||||
* @throws CaseActionException
|
* @throws CaseActionException
|
||||||
*/
|
*/
|
||||||
private static Case createCase(String baseCaseName, String rootOutputDirectory) throws CaseActionException {
|
private static Case createCase(String baseCaseName, String rootOutputDirectory) throws CaseActionException {
|
||||||
@ -254,7 +259,8 @@ class MultiUserTestTool {
|
|||||||
* source was added successfully
|
* source was added successfully
|
||||||
*
|
*
|
||||||
* @throws InterruptedException if the thread running the job processing
|
* @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({
|
@NbBundle.Messages({
|
||||||
"MultiUserTestTool.noContent=Test data source failed to produce content",
|
"MultiUserTestTool.noContent=Test data source failed to produce content",
|
||||||
@ -301,7 +307,8 @@ class MultiUserTestTool {
|
|||||||
* source was analyzed successfully
|
* source was analyzed successfully
|
||||||
*
|
*
|
||||||
* @throws InterruptedException if the thread running the job processing
|
* @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({
|
@NbBundle.Messages({
|
||||||
"# {0} - cancellationReason",
|
"# {0} - cancellationReason",
|
||||||
@ -314,7 +321,7 @@ class MultiUserTestTool {
|
|||||||
|
|
||||||
LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", dataSource.getPath());
|
LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", dataSource.getPath());
|
||||||
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
|
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
|
||||||
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
|
||||||
try {
|
try {
|
||||||
synchronized (INGEST_LOCK) {
|
synchronized (INGEST_LOCK) {
|
||||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(AutoIngestUserPreferences.getAutoModeIngestModuleContextString());
|
IngestJobSettings ingestJobSettings = new IngestJobSettings(AutoIngestUserPreferences.getAutoModeIngestModuleContextString());
|
||||||
@ -324,9 +331,9 @@ class MultiUserTestTool {
|
|||||||
IngestJob ingestJob = ingestJobStartResult.getJob();
|
IngestJob ingestJob = ingestJobStartResult.getJob();
|
||||||
if (null != ingestJob) {
|
if (null != ingestJob) {
|
||||||
/*
|
/*
|
||||||
* Block until notified by the ingest job event
|
* Block until notified by the ingest job event listener
|
||||||
* listener or until interrupted because auto ingest
|
* or until interrupted because auto ingest is shutting
|
||||||
* is shutting down.
|
* down.
|
||||||
*/
|
*/
|
||||||
INGEST_LOCK.wait();
|
INGEST_LOCK.wait();
|
||||||
LOGGER.log(Level.INFO, "Finished ingest modules analysis for {0} ", dataSource.getPath());
|
LOGGER.log(Level.INFO, "Finished ingest modules analysis for {0} ", dataSource.getPath());
|
||||||
|
@ -89,7 +89,8 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
public final class ImageGalleryController {
|
public final class ImageGalleryController {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ImageGalleryController.class.getName());
|
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
|
* 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
|
* 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());
|
dbTaskQueueSize.addListener(obs -> this.updateRegroupDisabled());
|
||||||
|
|
||||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, caseEventListener);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, caseEventListener);
|
||||||
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestJobEventListener);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(ingestModuleEventListener);
|
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, ingestModuleEventListener);
|
||||||
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
topComponent = ImageGalleryTopComponent.getTopComponent();
|
topComponent = ImageGalleryTopComponent.getTopComponent();
|
||||||
|
@ -35,6 +35,8 @@ OpenAction.multiUserDialog.Header=Multi-user Image Gallery
|
|||||||
OpenAction.noControllerDialog.header=Cannot open Image Gallery
|
OpenAction.noControllerDialog.header=Cannot open Image Gallery
|
||||||
OpenAction.noControllerDialog.text=An initialization error ocurred.\nPlease see the log for details.
|
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.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.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
|
OpenAction.stale.confDlg.title=Image Gallery
|
||||||
OpenExternalViewerAction.displayName=External Viewer
|
OpenExternalViewerAction.displayName=External Viewer
|
||||||
|
@ -34,6 +34,7 @@ import javafx.stage.Modality;
|
|||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import org.openide.awt.ActionID;
|
import org.openide.awt.ActionID;
|
||||||
import org.openide.awt.ActionReference;
|
import org.openide.awt.ActionReference;
|
||||||
@ -43,6 +44,7 @@ import org.openide.util.HelpCtx;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.openide.util.actions.CallableSystemAction;
|
import org.openide.util.actions.CallableSystemAction;
|
||||||
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.core.Installer;
|
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() {
|
private void openTopComponent() {
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
try {
|
try {
|
||||||
ImageGalleryTopComponent.openTopComponent();
|
ImageGalleryTopComponent.openTopComponent();
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to open Image Gallery top component", ex); //NON-NLS}
|
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -572,12 +572,12 @@ public final class DrawableDB {
|
|||||||
String sql = "CREATE TABLE if not exists drawable_files " //NON-NLS
|
String sql = "CREATE TABLE if not exists drawable_files " //NON-NLS
|
||||||
+ "( obj_id BIGINT PRIMARY KEY, " //NON-NLS
|
+ "( obj_id BIGINT PRIMARY KEY, " //NON-NLS
|
||||||
+ " data_source_obj_id BIGINT NOT NULL, "
|
+ " data_source_obj_id BIGINT NOT NULL, "
|
||||||
+ " path VARCHAR(255), " //NON-NLS
|
+ " path TEXT, " //NON-NLS
|
||||||
+ " name VARCHAR(255), " //NON-NLS
|
+ " name TEXT, " //NON-NLS
|
||||||
+ " created_time integer, " //NON-NLS
|
+ " created_time integer, " //NON-NLS
|
||||||
+ " modified_time integer, " //NON-NLS
|
+ " modified_time integer, " //NON-NLS
|
||||||
+ " make VARCHAR(255) DEFAULT NULL, " //NON-NLS
|
+ " make TEXT DEFAULT NULL, " //NON-NLS
|
||||||
+ " model VARCHAR(255) DEFAULT NULL, " //NON-NLS
|
+ " model TEXT DEFAULT NULL, " //NON-NLS
|
||||||
+ " analyzed integer DEFAULT 0)"; //NON-NLS
|
+ " analyzed integer DEFAULT 0)"; //NON-NLS
|
||||||
stmt.execute(sql);
|
stmt.execute(sql);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
@ -588,7 +588,7 @@ public final class DrawableDB {
|
|||||||
try {
|
try {
|
||||||
String sql = "CREATE TABLE if not exists hash_sets " //NON-NLS
|
String sql = "CREATE TABLE if not exists hash_sets " //NON-NLS
|
||||||
+ "( hash_set_id INTEGER primary key," //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);
|
stmt.execute(sql);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to create hash_sets table", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Failed to create hash_sets table", ex); //NON-NLS
|
||||||
@ -692,8 +692,8 @@ public final class DrawableDB {
|
|||||||
String tableSchema
|
String tableSchema
|
||||||
= "( group_id " + autogenKeyType + " PRIMARY KEY, " //NON-NLS
|
= "( group_id " + autogenKeyType + " PRIMARY KEY, " //NON-NLS
|
||||||
+ " data_source_obj_id BIGINT DEFAULT 0, "
|
+ " data_source_obj_id BIGINT DEFAULT 0, "
|
||||||
+ " value VARCHAR(255) not null, " //NON-NLS
|
+ " value TEXT not null, " //NON-NLS
|
||||||
+ " attribute VARCHAR(255) not null, " //NON-NLS
|
+ " attribute TEXT not null, " //NON-NLS
|
||||||
+ " is_analyzed integer DEFAULT 0, "
|
+ " is_analyzed integer DEFAULT 0, "
|
||||||
+ " UNIQUE(data_source_obj_id, value, attribute) )"; //NON-NLS
|
+ " UNIQUE(data_source_obj_id, value, attribute) )"; //NON-NLS
|
||||||
|
|
||||||
|
143
InternalPythonModules/android/imo.py
Normal file
143
InternalPythonModules/android/imo.py
Normal 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()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -46,6 +46,7 @@ import googlemaplocation
|
|||||||
import tangomessage
|
import tangomessage
|
||||||
import textmessage
|
import textmessage
|
||||||
import wwfmessage
|
import wwfmessage
|
||||||
|
import imo
|
||||||
|
|
||||||
class AndroidModuleFactory(IngestModuleFactoryAdapter):
|
class AndroidModuleFactory(IngestModuleFactoryAdapter):
|
||||||
|
|
||||||
@ -87,7 +88,10 @@ class AndroidIngestModule(DataSourceIngestModule):
|
|||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
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")
|
self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers")
|
||||||
progressBar.switchToDeterminate(len(analyzers))
|
progressBar.switchToDeterminate(len(analyzers))
|
||||||
|
|
||||||
|
@ -483,6 +483,7 @@ final class IngestSearchRunner {
|
|||||||
if (progressGroup != null) {
|
if (progressGroup != null) {
|
||||||
progressGroup.setDisplayName(displayName + " " + NbBundle.getMessage(this.getClass(), "SearchRunner.doInBackGround.cancelMsg"));
|
progressGroup.setDisplayName(displayName + " " + NbBundle.getMessage(this.getClass(), "SearchRunner.doInBackGround.cancelMsg"));
|
||||||
}
|
}
|
||||||
|
progressGroup.finish();
|
||||||
return IngestSearchRunner.Searcher.this.cancel(true);
|
return IngestSearchRunner.Searcher.this.cancel(true);
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
|
45
NEWS.txt
45
NEWS.txt
@ -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 Ballentin’s “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 --------------
|
---------------- VERSION 4.11.0 --------------
|
||||||
New Features:
|
New Features:
|
||||||
|
|
||||||
|
@ -236,6 +236,10 @@ abstract class Extract {
|
|||||||
return moduleName;
|
return moduleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getRAModuleName() {
|
||||||
|
return RecentActivityExtracterModuleFactory.getModuleName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the state of foundData
|
* Returns the state of foundData
|
||||||
* @return
|
* @return
|
||||||
|
@ -54,6 +54,7 @@ import org.w3c.dom.NodeList;
|
|||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.AbstractMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -66,8 +67,6 @@ import static java.util.TimeZone.getTimeZone;
|
|||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
|
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
|
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.autopsy.keywordsearchservice.KeywordSearchService;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
@ -90,6 +89,36 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
})
|
})
|
||||||
class ExtractRegistry extends Extract {
|
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 UsbDeviceIdMapper USB_MAPPER = new UsbDeviceIdMapper();
|
||||||
final private static String RIP_EXE = "rip.exe";
|
final private static String RIP_EXE = "rip.exe";
|
||||||
final private static String RIP_PL = "rip.pl";
|
final private static String RIP_PL = "rip.pl";
|
||||||
@ -840,27 +869,29 @@ class ExtractRegistry extends Extract {
|
|||||||
*/
|
*/
|
||||||
private boolean parseSamPluginOutput(String regFilePath, AbstractFile regAbstractFile) {
|
private boolean parseSamPluginOutput(String regFilePath, AbstractFile regAbstractFile) {
|
||||||
File regfile = new File(regFilePath);
|
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))) {
|
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(regfile))) {
|
||||||
// Read the file in and create a Document and elements
|
// Read the file in and create a Document and elements
|
||||||
String userInfoSection = "User Information";
|
String userInfoSection = "User Information";
|
||||||
String previousLine = null;
|
String previousLine = null;
|
||||||
String line = bufferedReader.readLine();
|
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) {
|
while (line != null) {
|
||||||
if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains(userInfoSection)) {
|
if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains(userInfoSection)) {
|
||||||
readUsers(bufferedReader, userSet);
|
readUsers(bufferedReader, userSet);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains("Group Membership Information")) {
|
||||||
|
groupMap = readGroups(bufferedReader);
|
||||||
|
}
|
||||||
|
|
||||||
previousLine = line;
|
previousLine = line;
|
||||||
line = bufferedReader.readLine();
|
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
|
//load all the user info which was read into a map
|
||||||
for (UserInfo userInfo : userSet) {
|
for (Map<String, String> userInfo : userSet) {
|
||||||
userInfoMap.put(userInfo.getUserSid(), userInfo);
|
userInfoMap.put(userInfo.get(SID_KEY), userInfo);
|
||||||
}
|
}
|
||||||
//get all existing OS account artifacts
|
//get all existing OS account artifacts
|
||||||
List<BlackboardArtifact> existingOsAccounts = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
|
List<BlackboardArtifact> existingOsAccounts = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
|
||||||
@ -869,45 +900,19 @@ class ExtractRegistry extends Extract {
|
|||||||
if (osAccount.getDataSource().getId() == regAbstractFile.getDataSourceObjectId()) {
|
if (osAccount.getDataSource().getId() == regAbstractFile.getDataSourceObjectId()) {
|
||||||
BlackboardAttribute existingUserId = osAccount.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID));
|
BlackboardAttribute existingUserId = osAccount.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID));
|
||||||
if (existingUserId != null) {
|
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 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) {
|
if (userInfo != null) {
|
||||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
osAccount.addAttributes(getAttributesForAccount(userInfo, groupMap.get(userID), true));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//add remaining userinfos as accounts;
|
//add remaining userinfos as accounts;
|
||||||
for (String userId : userInfoMap.keySet()) {
|
for (Map<String, String> userInfo : userInfoMap.values()) {
|
||||||
UserInfo userInfo = userInfoMap.get(userId);
|
|
||||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
|
||||||
BlackboardArtifact bbart = regAbstractFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
|
BlackboardArtifact bbart = regAbstractFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
|
bbart.addAttributes(getAttributesForAccount(userInfo, groupMap.get(userInfo.get(SID_KEY)), false));
|
||||||
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);
|
|
||||||
// index the artifact for keyword search
|
// index the artifact for keyword search
|
||||||
postArtifact(bbart);
|
postArtifact(bbart);
|
||||||
}
|
}
|
||||||
@ -925,6 +930,149 @@ class ExtractRegistry extends Extract {
|
|||||||
return false;
|
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
|
* Read the User Information section of the SAM regripper plugin's output
|
||||||
* and collect user account information from the file.
|
* and collect user account information from the file.
|
||||||
@ -936,42 +1084,125 @@ class ExtractRegistry extends Extract {
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void readUsers(BufferedReader bufferedReader, Set<UserInfo> users) throws IOException {
|
private void readUsers(BufferedReader bufferedReader, Set<Map<String, String>> users) throws IOException {
|
||||||
String userNameLabel = "Username :";
|
|
||||||
String sidLabel = "SID :";
|
|
||||||
String accountCreatedLabel = "Account Created :";
|
|
||||||
String loginCountLabel = "Login Count :";
|
|
||||||
String lastLoginLabel = "Last Login Date :";
|
|
||||||
String line = bufferedReader.readLine();
|
String line = bufferedReader.readLine();
|
||||||
//read until end of file or next section divider
|
//read until end of file or next section divider
|
||||||
String userName = "";
|
String userName = "";
|
||||||
|
String user_rid = "";
|
||||||
while (line != null && !line.contains(SECTION_DIVIDER)) {
|
while (line != null && !line.contains(SECTION_DIVIDER)) {
|
||||||
//when a user name field exists read the name and id number
|
//when a user name field exists read the name and id number
|
||||||
if (line.contains(userNameLabel)) {
|
if (line.contains(USERNAME_KEY)) {
|
||||||
String userNameAndIdString = line.replace(userNameLabel, "");
|
String regx = USERNAME_KEY + "\\s*?:";
|
||||||
|
String userNameAndIdString = line.replaceAll(regx, "");
|
||||||
userName = userNameAndIdString.substring(0, userNameAndIdString.lastIndexOf('[')).trim();
|
userName = userNameAndIdString.substring(0, userNameAndIdString.lastIndexOf('[')).trim();
|
||||||
} else if (line.contains(sidLabel) && !userName.isEmpty()) {
|
user_rid = userNameAndIdString.substring(userNameAndIdString.lastIndexOf('['), userNameAndIdString.lastIndexOf(']'));
|
||||||
String sid = line.replace(sidLabel, "").trim();
|
} else if (line.contains(SID_KEY) && !userName.isEmpty()) {
|
||||||
UserInfo userInfo = new UserInfo(userName, sid);
|
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
|
//continue reading this users information until end of file or a blank line between users
|
||||||
line = bufferedReader.readLine();
|
line = bufferedReader.readLine();
|
||||||
while (line != null && !line.isEmpty()) {
|
while (line != null && !line.isEmpty()) {
|
||||||
if (line.contains(accountCreatedLabel)) {
|
entry = getSAMKeyValue(line);
|
||||||
userInfo.setAccountCreatedDate(line.replace(accountCreatedLabel, "").trim());
|
userInfo.put(entry.getKey(), entry.getValue());
|
||||||
} else if (line.contains(loginCountLabel)) {
|
|
||||||
userInfo.setLoginCount(Integer.parseInt(line.replace(loginCountLabel, "").trim()));
|
|
||||||
} else if (line.contains(lastLoginLabel)) {
|
|
||||||
userInfo.setLastLoginDate(line.replace(lastLoginLabel, "").trim());
|
|
||||||
}
|
|
||||||
line = bufferedReader.readLine();
|
line = bufferedReader.readLine();
|
||||||
}
|
}
|
||||||
users.add(userInfo);
|
users.add(userInfo);
|
||||||
|
|
||||||
userName = "";
|
userName = "";
|
||||||
}
|
}
|
||||||
line = bufferedReader.readLine();
|
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
|
@Override
|
||||||
public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
|
public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
@ -990,101 +1221,4 @@ class ExtractRegistry extends Extract {
|
|||||||
public String autopsyPlugins = "";
|
public String autopsyPlugins = "";
|
||||||
public String fullPlugins = "";
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
import java.util.logging.Level;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
@ -66,7 +66,7 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
|
|
||||||
public class AutopsyTestCases {
|
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;
|
private long start;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +40,7 @@ import org.netbeans.junit.NbModuleSuite;
|
|||||||
*/
|
*/
|
||||||
public class RegressionTest extends TestCase {
|
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")));
|
private static final AutopsyTestCases autopsyTests = new AutopsyTestCases(Boolean.parseBoolean(System.getProperty("isMultiUser")));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<delete includeemptydirs="true" failonerror="false">
|
<delete includeemptydirs="true" failonerror="false">
|
||||||
<fileset dir="${basedir}/docs/doxygen-dev/dev-docs" includes="**/*"/>
|
<fileset dir="${basedir}/docs/doxygen-dev/build-docs" includes="**/*"/>
|
||||||
</delete>
|
</delete>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
@ -265,7 +265,7 @@
|
|||||||
<fileset dir="${basedir}/docs/doxygen-user/user-docs" includes="**/*"/>
|
<fileset dir="${basedir}/docs/doxygen-user/user-docs" includes="**/*"/>
|
||||||
</delete>
|
</delete>
|
||||||
<delete includeemptydirs="true" failonerror="false">
|
<delete includeemptydirs="true" failonerror="false">
|
||||||
<fileset dir="${basedir}/docs/doxygen-dev/dev-docs" includes="**/*"/>
|
<fileset dir="${basedir}/docs/doxygen-dev/build-docs" includes="**/*"/>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<!-- Generate new -->
|
<!-- Generate new -->
|
||||||
|
@ -58,7 +58,7 @@ PROJECT_LOGO =
|
|||||||
# entered, it will be relative to the location where doxygen was started. If
|
# entered, it will be relative to the location where doxygen was started. If
|
||||||
# left blank the current directory will be used.
|
# 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-
|
# 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
|
# directories (in 2 levels) under the output directory of each output format and
|
||||||
|
@ -322,6 +322,7 @@ class TskDbDiff(object):
|
|||||||
id_fs_info_table = build_id_fs_info_table(conn.cursor(), isMultiUser)
|
id_fs_info_table = build_id_fs_info_table(conn.cursor(), isMultiUser)
|
||||||
id_objects_table = build_id_objects_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_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_reports_table = build_id_reports_table(conn.cursor(), isMultiUser)
|
||||||
id_images_table = build_id_image_names_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)
|
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:
|
if 'INSERT INTO image_gallery_groups_seen' in dump_line:
|
||||||
dump_line = ''
|
dump_line = ''
|
||||||
continue;
|
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)
|
db_log.write('%s\n' % dump_line)
|
||||||
dump_line = ''
|
dump_line = ''
|
||||||
postgreSQL_db.close()
|
postgreSQL_db.close()
|
||||||
@ -361,7 +362,7 @@ class TskDbDiff(object):
|
|||||||
for line in conn.iterdump():
|
for line in conn.iterdump():
|
||||||
if 'INSERT INTO "image_gallery_groups_seen"' in line:
|
if 'INSERT INTO "image_gallery_groups_seen"' in line:
|
||||||
continue
|
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)
|
db_log.write('%s\n' % line)
|
||||||
# Now sort the file
|
# Now sort the file
|
||||||
srtcmdlst = ["sort", dump_file, "-o", dump_file]
|
srtcmdlst = ["sort", dump_file, "-o", dump_file]
|
||||||
@ -414,7 +415,7 @@ class PGSettings(object):
|
|||||||
return self.password
|
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.
|
""" Make testing more consistent and reasonable by doctoring certain db entries.
|
||||||
|
|
||||||
Args:
|
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
|
# replace object ids with information that is deterministic
|
||||||
file_obj_id = int(fields_list[5])
|
file_obj_id = int(fields_list[5])
|
||||||
object_id = int(fields_list[4])
|
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():
|
if file_obj_id != 'NULL' and file_obj_id in files_table.keys():
|
||||||
fields_list[5] = files_table[file_obj_id]
|
fields_list[5] = files_table[file_obj_id]
|
||||||
if object_id != 'NULL' and object_id in files_table.keys():
|
if object_id != 'NULL' and object_id in files_table.keys():
|
||||||
fields_list[4] = files_table[object_id]
|
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
|
newLine = ('INSERT INTO "tsk_event_descriptions" VALUES(' + ','.join(fields_list[1:]) + ');') # remove report_id
|
||||||
return newLine
|
return newLine
|
||||||
else:
|
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 ")])
|
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
|
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):
|
def build_id_reports_table(db_cursor, isPostgreSQL):
|
||||||
"""Build the map of report object ids to report path.
|
"""Build the map of report object ids to report path.
|
||||||
|
|
||||||
|
@ -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-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-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
|
OpenIDE-Module-Name=Email Parser
|
||||||
|
72
thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EMLParser.java
Executable file
72
thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EMLParser.java
Executable 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
Loading…
x
Reference in New Issue
Block a user