diff --git a/CentralRepository/build.xml b/CentralRepository/build.xml deleted file mode 100644 index 4e8c2ff783ae403993f2b6f9e6c9cf6e62737be0..0000000000000000000000000000000000000000 --- a/CentralRepository/build.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- You may freely edit this file. See harness/README in the NetBeans platform --> -<!-- for some information on what you could do (e.g. targets to override). --> -<!-- If you delete this file and reopen the project it will be recreated. --> -<project name="org.sleuthkit.autopsy.centralrepository" default="netbeans" basedir="." xmlns:ivy="antlib:org.apache.ivy.ant"> - <description>Builds, tests, and runs the project org.sleuthkit.autopsy.centralrepository.</description> - <import file="nbproject/build-impl.xml"/> - <import file="../BootstrapIvy.xml"/> - - <property name="thirdparty.dir" value="${basedir}/../thirdparty" /> - <property name="modules.dir" value="${basedir}/release/modules/" /> - <property name="ext.dir" value="${modules.dir}/ext" /> - - <target name="resolve"> - <ivy:settings file="ivysettings.xml" /> - <ivy:resolve file="ivy.xml" conf="central-repository"/> - </target> - - <target name="retrieve" depends="resolve"> - <ivy:retrieve conf="central-repository" pattern="${basedir}/release/modules/ext/[artifact]-[revision](-[classifier]).[ext]" /> - </target> - - <target name="init" depends="retrieve, harness.init" /> - - <target name="clean" depends="projectized-common.clean"> - <!--Override clean to delete jars, etc downloaded with Ivy - or copied in from thirdparty folder. This way we don't end up with - out-of-date/unneeded stuff in the installer--> - <delete dir="${basedir}/release"/> - </target> -</project> diff --git a/CentralRepository/manifest.mf b/CentralRepository/manifest.mf deleted file mode 100644 index b798470437a66784c49570e9ffd64ff5210db734..0000000000000000000000000000000000000000 --- a/CentralRepository/manifest.mf +++ /dev/null @@ -1,6 +0,0 @@ -Manifest-Version: 1.0 -AutoUpdate-Show-In-Client: true -OpenIDE-Module: org.sleuthkit.autopsy.centralrepository -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/centralrepository/Bundle.properties -OpenIDE-Module-Specification-Version: 1.0 -OpenIDE-Module-Install: org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.class diff --git a/CentralRepository/nbproject/build-impl.xml b/CentralRepository/nbproject/build-impl.xml deleted file mode 100644 index 60467ca5c3a0f0f767c67c9319d5be9e276d6407..0000000000000000000000000000000000000000 --- a/CentralRepository/nbproject/build-impl.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -*** GENERATED FROM project.xml - DO NOT EDIT *** -*** EDIT ../build.xml INSTEAD *** ---> -<project name="org.sleuthkit.autopsy.centralrepository-impl" basedir=".."> - <fail message="Please build using Ant 1.7.1 or higher."> - <condition> - <not> - <antversion atleast="1.7.1"/> - </not> - </condition> - </fail> - <property file="nbproject/private/suite-private.properties"/> - <property file="nbproject/suite.properties"/> - <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail> - <property file="${suite.dir}/nbproject/private/platform-private.properties"/> - <property file="${suite.dir}/nbproject/platform.properties"/> - <macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-project/2"> - <attribute name="name"/> - <attribute name="value"/> - <sequential> - <property name="@{name}" value="${@{value}}"/> - </sequential> - </macrodef> - <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2"> - <attribute name="property"/> - <attribute name="value"/> - <sequential> - <property name="@{property}" value="@{value}"/> - </sequential> - </macrodef> - <property file="${user.properties.file}"/> - <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/> - <nbmproject2:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/> - <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/> - <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness)."> - <condition> - <not> - <contains string="${cluster.path.evaluated}" substring="platform"/> - </not> - </condition> - </fail> - <import file="${harness.dir}/build.xml"/> -</project> diff --git a/CentralRepository/nbproject/project.properties b/CentralRepository/nbproject/project.properties deleted file mode 100644 index efcb9ba609d0e144deea9645c26b7088dd6f60b2..0000000000000000000000000000000000000000 --- a/CentralRepository/nbproject/project.properties +++ /dev/null @@ -1,9 +0,0 @@ -file.reference.commons-dbcp2-2.1.1.jar=release/modules/ext/commons-dbcp2-2.1.1.jar -file.reference.commons-logging-1.2.jar=release/modules/ext/commons-logging-1.2.jar -file.reference.commons-pool2-2.4.2.jar=release/modules/ext/commons-pool2-2.4.2.jar -file.reference.postgresql-42.1.1.jar=release/modules/ext/postgresql-42.1.1.jar -file.reference.sqlite-jdbc-3.16.1.jar=release/modules/ext/sqlite-jdbc-3.16.1.jar -javac.source=1.8 -javac.compilerargs=-Xlint -Xlint:-serial -license.file=../LICENSE-2.0.txt -nbm.homepage=http://www.sleuthkit.org/autopsy/ diff --git a/CentralRepository/nbproject/project.xml b/CentralRepository/nbproject/project.xml deleted file mode 100644 index 1c66ca32ff484902bc129a6035d12137daa1f435..0000000000000000000000000000000000000000 --- a/CentralRepository/nbproject/project.xml +++ /dev/null @@ -1,116 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://www.netbeans.org/ns/project/1"> - <type>org.netbeans.modules.apisupport.project</type> - <configuration> - <data xmlns="http://www.netbeans.org/ns/nb-module-project/3"> - <code-name-base>org.sleuthkit.autopsy.centralrepository</code-name-base> - <suite-component/> - <module-dependencies> - <dependency> - <code-name-base>org.netbeans.api.progress</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <release-version>1</release-version> - <specification-version>1.47.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.netbeans.modules.options.api</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <release-version>1</release-version> - <specification-version>1.45.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.openide.awt</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <specification-version>7.67.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.openide.modules</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <specification-version>7.48.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.openide.nodes</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <specification-version>7.45.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.openide.util</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <specification-version>9.7.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.openide.util.lookup</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <specification-version>8.33.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.openide.util.ui</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <specification-version>9.6.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.openide.windows</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <specification-version>6.75.1</specification-version> - </run-dependency> - </dependency> - <dependency> - <code-name-base>org.sleuthkit.autopsy.core</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <release-version>10</release-version> - <specification-version>10.8</specification-version> - </run-dependency> - </dependency> - </module-dependencies> - <public-packages/> - <class-path-extension> - <runtime-relative-path>ext/sqlite-jdbc-3.16.1.jar</runtime-relative-path> - <binary-origin>release\modules\ext\sqlite-jdbc-3.16.1.jar</binary-origin> - </class-path-extension> - <class-path-extension> - <runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path> - <binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin> - </class-path-extension> - <class-path-extension> - <runtime-relative-path>ext/postgresql-42.1.1.jar</runtime-relative-path> - <binary-origin>release\modules\ext\postgresql-42.1.1.jar</binary-origin> - </class-path-extension> - <class-path-extension> - <runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path> - <binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin> - </class-path-extension> - <class-path-extension> - <runtime-relative-path>ext/commons-logging-1.2.jar</runtime-relative-path> - <binary-origin>release\modules\ext\commons-logging-1.2.jar</binary-origin> - </class-path-extension> - </data> - </configuration> -</project> diff --git a/CentralRepository/nbproject/suite.properties b/CentralRepository/nbproject/suite.properties deleted file mode 100644 index 29d7cc9bd6fdd81453543cdf1bcf1dab301e3a92..0000000000000000000000000000000000000000 --- a/CentralRepository/nbproject/suite.properties +++ /dev/null @@ -1 +0,0 @@ -suite.dir=${basedir}/.. diff --git a/Core/ivy.xml b/Core/ivy.xml index d40831b7736fce028d20fed2b8984837ec091b4e..b6cfe4a5682459b700e0e41ebb136350747f49e0 100644 --- a/Core/ivy.xml +++ b/Core/ivy.xml @@ -19,5 +19,7 @@ <dependency conf="core->default" org="com.adobe.xmp" name="xmpcore" rev="5.1.2"/> <dependency conf="core->default" org="org.apache.zookeeper" name="zookeeper" rev="3.4.6"/> + <dependency conf="core->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/> + <dependency conf="core->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/> </dependencies> </ivy-module> diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index eb4739d209bc1c76858bb4596b132513956f4255..0fa567cf007141947e940ec0b34b9e1ba8a56930 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -362,6 +362,14 @@ <runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path> <binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin> </class-path-extension> + <class-path-extension> + <runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path> + <binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin> + </class-path-extension> +<class-path-extension> + <runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path> + <binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin> + </class-path-extension> </data> </configuration> </project> diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index eb810e708c1307d2d918b9aa21a2dad90a4c17f5..f12c2f7e5d207111217e0f966ce9a4ea2fefac28 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -36,8 +36,10 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.LayoutFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction; +import org.sleuthkit.datamodel.SpecialDirectory; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskFileRange; import org.sleuthkit.datamodel.VirtualDirectory; @@ -45,6 +47,7 @@ import org.sleuthkit.datamodel.TskDataException; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractContent; import org.sleuthkit.datamodel.CarvingResult; import org.sleuthkit.datamodel.TskData; @@ -295,7 +298,7 @@ public synchronized List<AbstractFile> openFiles(Content dataSource, String file * @param atime The accessed time of the file. * @param mtime The modified time of the file. * @param isFile True if a file, false if a directory. - * @param parentFile The parent file from which the file was derived. + * @param parentObj The parent object from which the file was derived. * @param rederiveDetails The details needed to re-derive file (will be * specific to the derivation method), currently * unused. @@ -317,7 +320,7 @@ public synchronized DerivedFile addDerivedFile(String fileName, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, - AbstractFile parentFile, + Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType) throws TskCoreException { if (null == caseDb) { @@ -325,7 +328,7 @@ public synchronized DerivedFile addDerivedFile(String fileName, } return caseDb.addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime, - isFile, parentFile, rederiveDetails, toolName, toolVersion, otherDetails, encodingType); + isFile, parentObj, rederiveDetails, toolName, toolVersion, otherDetails, encodingType); } /** @@ -496,12 +499,9 @@ private List<java.io.File> getFilesAndDirectories(List<String> localFilePaths) t * database, recursively adding the contents of directories. * * @param trans A case database transaction. - * @param parentDirectory The root virtual direcotry of the data source. + * @param parentDirectory The root virtual directory of the data source or the parent local directory. * @param localFile The local/logical file or directory. * @param encodingType Type of encoding used when storing the file - * - * @returns File object of file added or new virtualdirectory for the - * directory. * @param progressUpdater Called after each file/directory is added to * the case database. * @@ -510,14 +510,14 @@ private List<java.io.File> getFilesAndDirectories(List<String> localFilePaths) t * @throws TskCoreException If there is a problem completing a database * operation. */ - private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, + private AbstractFile addLocalFile(CaseDbTransaction trans, SpecialDirectory parentDirectory, java.io.File localFile, TskData.EncodingType encodingType, FileAddProgressUpdater progressUpdater) throws TskCoreException { if (localFile.isDirectory()) { /* - * Add the directory as a virtual directory. + * Add the directory as a local directory. */ - VirtualDirectory virtualDirectory = caseDb.addVirtualDirectory(parentDirectory.getId(), localFile.getName(), trans); - progressUpdater.fileAdded(virtualDirectory); + LocalDirectory localDirectory = caseDb.addLocalDirectory(parentDirectory.getId(), localFile.getName(), trans); + progressUpdater.fileAdded(localDirectory); /* * Add its children, if any. @@ -525,11 +525,11 @@ private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory pare final java.io.File[] childFiles = localFile.listFiles(); if (childFiles != null && childFiles.length > 0) { for (java.io.File childFile : childFiles) { - addLocalFile(trans, virtualDirectory, childFile, progressUpdater); + addLocalFile(trans, localDirectory, childFile, progressUpdater); } } - return virtualDirectory; + return localDirectory; } else { return caseDb.addLocalFile(localFile.getName(), localFile.getAbsolutePath(), localFile.length(), 0, 0, 0, 0, @@ -677,13 +677,10 @@ public synchronized DerivedFile addDerivedFile(String fileName, * database, recursively adding the contents of directories. * * @param trans A case database transaction. - * @param parentDirectory The root virtual direcotry of the data source. + * @param parentDirectory The root virtual directory of the data source or the parent local directory. * @param localFile The local/logical file or directory. * @param progressUpdater notifier to receive progress notifications on * folders added, or null if not used - * - * @returns File object of file added or new virtualdirectory for the - * directory. * @param progressUpdater Called after each file/directory is added to * the case database. * @@ -695,7 +692,7 @@ public synchronized DerivedFile addDerivedFile(String fileName, * @deprecated Use the version with explicit EncodingType instead */ @Deprecated - private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, FileAddProgressUpdater progressUpdater) throws TskCoreException { + private AbstractFile addLocalFile(CaseDbTransaction trans, SpecialDirectory parentDirectory, java.io.File localFile, FileAddProgressUpdater progressUpdater) throws TskCoreException { return addLocalFile(trans, parentDirectory, localFile, TskData.EncodingType.NONE, progressUpdater); } diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties rename to Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/README-POSTGRES-TESTING.md b/Core/src/org/sleuthkit/autopsy/centralrepository/README-POSTGRES-TESTING.md similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/README-POSTGRES-TESTING.md rename to Core/src/org/sleuthkit/autopsy/centralrepository/README-POSTGRES-TESTING.md diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/README_MONGODB_TESTING.md b/Core/src/org/sleuthkit/autopsy/centralrepository/README_MONGODB_TESTING.md similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/README_MONGODB_TESTING.md rename to Core/src/org/sleuthkit/autopsy/centralrepository/README_MONGODB_TESTING.md diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/Bundle.properties similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/actions/Bundle.properties rename to Core/src/org/sleuthkit/autopsy/centralrepository/actions/Bundle.properties diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.form similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.form rename to Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.form diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties rename to Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form rename to Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableCellRenderer.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableCellRenderer.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java similarity index 98% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index 2fa17e42d87449485efa836775e8e05fb421747e..e6fa8730a704004e5478845e080ac71b37084612 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -1095,6 +1095,20 @@ public void setArtifactInstanceKnownBad(EamArtifact eamArtifact) throws EamDbExc preparedUpdate.executeUpdate(); } else { + // In this case, the user is tagging something that isn't in the database, + // which means the case and/or datasource may also not be in the database. + // We could improve effiency by keeping a list of all datasources and cases + // in the database, but we don't expect the user to be tagging large numbers + // of items (that didn't have the CE ingest module run on them) at once. + + if(null == getCaseDetails(eamInstance.getEamCase().getCaseUUID())){ + newCase(eamInstance.getEamCase()); + } + + if (null == getDataSourceDetails(eamInstance.getEamDataSource().getDeviceID())) { + newDataSource(eamInstance.getEamDataSource()); + } + eamArtifact.getInstances().get(0).setKnownStatus(TskData.FileKnown.BAD); addArtifact(eamArtifact); } diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifact.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifact.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifact.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifact.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactInstance.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactInstance.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactInstance.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactInstance.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamCase.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamCase.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamCase.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamCase.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDataSource.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDataSource.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDataSource.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDataSource.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbException.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbException.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbException.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbException.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbPlatformEnum.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbPlatformEnum.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbPlatformEnum.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbPlatformEnum.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalFileInstance.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalFileInstance.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalFileInstance.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalFileInstance.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamOrganization.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamOrganization.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamOrganization.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamOrganization.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/BadFileTagRunner.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/BadFileTagRunner.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/BadFileTagRunner.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/BadFileTagRunner.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java similarity index 88% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java index a0a78786053b0f70c121ec3092878f5463fbfa70..d2b1beebbb230f17d4844bf1a99c262046882330 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java @@ -35,6 +35,20 @@ public class Installer extends ModuleInstall { private final PropertyChangeListener pcl = new CaseEventListener(); private final IngestEventsListener ieListener = new IngestEventsListener(); + private static Installer instance; + + public synchronized static Installer getDefault() { + if (instance == null) { + instance = new Installer(); + } + return instance; + } + + private Installer() { + super(); + } + + @Override public void restored() { Case.addPropertyChangeListener(pcl); diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/NewArtifactsRunner.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/NewArtifactsRunner.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/NewArtifactsRunner.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/NewArtifactsRunner.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/images/bad.png b/Core/src/org/sleuthkit/autopsy/centralrepository/images/bad.png similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/images/bad.png rename to Core/src/org/sleuthkit/autopsy/centralrepository/images/bad.png diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/images/good.png b/Core/src/org/sleuthkit/autopsy/centralrepository/images/good.png similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/images/good.png rename to Core/src/org/sleuthkit/autopsy/centralrepository/images/good.png diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/images/import16.png b/Core/src/org/sleuthkit/autopsy/centralrepository/images/import16.png similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/images/import16.png rename to Core/src/org/sleuthkit/autopsy/centralrepository/images/import16.png diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/images/options-icon.png b/Core/src/org/sleuthkit/autopsy/centralrepository/images/options-icon.png similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/images/options-icon.png rename to Core/src/org/sleuthkit/autopsy/centralrepository/images/options-icon.png diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/license-centralrepository.txt b/Core/src/org/sleuthkit/autopsy/centralrepository/license-centralrepository.txt similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/license-centralrepository.txt rename to Core/src/org/sleuthkit/autopsy/centralrepository/license-centralrepository.txt diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.form similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.form rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.form diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.form similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.form rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.form diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamOptionsPanelController.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamOptionsPanelController.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamOptionsPanelController.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.form similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.form rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.form diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCorrelationPropertiesDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCorrelationPropertiesDialog.form similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCorrelationPropertiesDialog.form rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCorrelationPropertiesDialog.form diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCorrelationPropertiesDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCorrelationPropertiesDialog.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCorrelationPropertiesDialog.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCorrelationPropertiesDialog.java diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.form similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.form rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.form diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.java similarity index 100% rename from CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.java diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 748870d7832de6ba8228eb89ac7fb89d442ead44..0b660acd2a3d535fd790ca399692671fed57420e 100644 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -212,6 +212,7 @@ public Installer() { packageInstallers.add(org.sleuthkit.autopsy.corecomponents.Installer.getDefault()); packageInstallers.add(org.sleuthkit.autopsy.datamodel.Installer.getDefault()); packageInstallers.add(org.sleuthkit.autopsy.ingest.Installer.getDefault()); + packageInstallers.add(org.sleuthkit.autopsy.centralrepository.eventlisteners.Installer.getDefault()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index f80866ac9bf5051e8d6e3ba57cafcd9c80a3e0f1..c4f35e9b8a11867ce0fc9a9b35c9fc0fdc2c4c9c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -26,6 +26,7 @@ import java.awt.datatransfer.StringSelection; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.concurrent.ExecutionException; @@ -456,12 +457,13 @@ public boolean isSupported(Node node) { return false; } - Content content = node.getLookup().lookup(Content.class); - if (content != null) { - try { - return content.getAllArtifactsCount() > 0; - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS + for (Content content : node.getLookup().lookupAll(Content.class)) { + if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){ + try { + return content.getAllArtifactsCount() > 0; + } catch (TskException ex) { + logger.log(Level.SEVERE, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS + } } } return false; @@ -693,22 +695,28 @@ protected ViewUpdate doInBackground() { // blackboard artifact, if any. Lookup lookup = selectedNode.getLookup(); - // Get the content. - Content content = lookup.lookup(Content.class); - if (content == null) { + // Get the content. We may get BlackboardArtifacts, ignore those here. + ArrayList<BlackboardArtifact> artifacts = new ArrayList<>(); + Collection<? extends Content> contents = lookup.lookupAll(Content.class); + if (contents.isEmpty()) { return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); } - - // Get all of the blackboard artifacts associated with the content. These are what this - // viewer displays. - ArrayList<BlackboardArtifact> artifacts; - try { - artifacts = content.getAllArtifacts(); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't get artifacts", ex); //NON-NLS - return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); + Content underlyingContent = null; + for (Content content : contents) { + if ( (content != null) && (!(content instanceof BlackboardArtifact)) ) { + // Get all of the blackboard artifacts associated with the content. These are what this + // viewer displays. + try { + artifacts = content.getAllArtifacts(); + underlyingContent = content; + break; + } catch (TskException ex) { + logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS + return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); + } + } } - + if (isCancelled()) { return null; } @@ -716,7 +724,7 @@ protected ViewUpdate doInBackground() { // Build the new artifact contents cache. ArrayList<ResultsTableArtifact> artifactContents = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { - artifactContents.add(new ResultsTableArtifact(artifact, content)); + artifactContents.add(new ResultsTableArtifact(artifact, underlyingContent)); } // If the node has an underlying blackboard artifact, show it. If not, diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 4b522d0f415e2c0c6689b48752088543cd6f522a..25cd62e7199400cec7448cbb09673b1b4f7dd4c0 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -37,7 +37,6 @@ import java.util.TreeSet; import java.util.logging.Level; import java.util.prefs.Preferences; -import java.util.stream.Stream; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; @@ -59,8 +58,6 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Node.Property; -import org.openide.nodes.NodeAdapter; -import org.openide.nodes.NodeMemberEvent; import org.openide.util.NbBundle; import org.openide.util.NbPreferences; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; @@ -82,8 +79,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { private static final Logger logger = Logger.getLogger(DataResultViewerTable.class.getName()); @NbBundle.Messages("DataResultViewerTable.firstColLbl=Name") static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl(); - @NbBundle.Messages("DataResultViewerTable.pleasewaitNodeDisplayName=Please Wait...") - private static final String PLEASEWAIT_NODE_DISPLAY_NAME = Bundle.DataResultViewerTable_pleasewaitNodeDisplayName(); private static final Color TAGGED_COLOR = new Color(200, 210, 220); /** * The properties map: @@ -103,8 +98,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { */ private final Map<String, ETableColumn> columnMap = new HashMap<>(); - private final PleasewaitNodeListener pleasewaitNodeListener = new PleasewaitNodeListener(); - private Node currentRoot; /* @@ -218,15 +211,8 @@ public void setNode(Node selectedNode) { hasChildren = selectedNode.getChildren().getNodesCount() > 0; } - Node oldNode = this.em.getRootContext(); - if (oldNode != null) { - oldNode.removeNodeListener(pleasewaitNodeListener); - } - if (hasChildren) { currentRoot = selectedNode; - pleasewaitNodeListener.reset(); - currentRoot.addNodeListener(pleasewaitNodeListener); em.setRootContext(currentRoot); setupTable(); } else { @@ -764,35 +750,6 @@ private void listenToVisibilityChanges(boolean b) { } } - private class PleasewaitNodeListener extends NodeAdapter { - - private volatile boolean load = true; - - public void reset() { - load = true; - } - - @Override - public void childrenAdded(final NodeMemberEvent nme) { - Node[] delta = nme.getDelta(); - if (load && containsReal(delta)) { - load = false; - //JMTODO: this looks suspicious - if (SwingUtilities.isEventDispatchThread()) { - setupTable(); - } else { - SwingUtilities.invokeLater(() -> setupTable()); - } - } - } - - private boolean containsReal(Node[] delta) { - return Stream.of(delta) - .map(Node::getDisplayName) - .noneMatch(PLEASEWAIT_NODE_DISPLAY_NAME::equals); - } - } - /** * This custom renderer extends the renderer that was already being used by * the outline table. This renderer colors a row if the tags property of the diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index e3c750826d2dff1b2ebec83a66576c61b73f40f2..a1d85d50df0bbb7220cb157728c1356f02bacf34 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,17 +22,19 @@ import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; -import org.openide.nodes.Children; import java.util.Map; import java.util.logging.Level; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.coreutils.Logger; +import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType.*; +import static org.sleuthkit.autopsy.datamodel.Bundle.*; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; @@ -47,25 +49,22 @@ */ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends AbstractContentNode<T> { - private static final Logger LOGGER = Logger.getLogger(AbstractAbstractFileNode.class.getName()); + private static final Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName()); + @NbBundle.Messages("AbstractAbstractFileNode.addFileProperty.desc=no description") + private static final String NO_DESCR = AbstractAbstractFileNode_addFileProperty_desc(); /** - * @param <T> type of the AbstractFile data to encapsulate - * @param abstractFile file to encapsulate + * @param abstractFile file to wrap */ AbstractAbstractFileNode(T abstractFile) { super(abstractFile); - String name = abstractFile.getName(); - int dotIndex = name.lastIndexOf("."); - if (dotIndex > 0) { - String ext = name.substring(dotIndex).toLowerCase(); - + String ext = abstractFile.getNameExtension(); + if (StringUtils.isNotBlank(ext)) { + ext = "." + ext; // If this is an archive file we will listen for ingest events // that will notify us when new content has been identified. - for (String s : FileTypeExtensions.getArchiveExtensions()) { - if (ext.equals(s)) { - IngestManager.getInstance().addIngestModuleEventListener(pcl); - } + if (FileTypeExtensions.getArchiveExtensions().contains(ext)) { + IngestManager.getInstance().addIngestModuleEventListener(pcl); } } // Listen for case events so that we can detect when case is closed @@ -103,7 +102,6 @@ private void removeListeners() { } catch (NullPointerException ex) { // Skip } - } } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { if (evt.getNewValue() == null) { @@ -127,194 +125,125 @@ private void updateSheet() { this.setSheet(createSheet()); } - // Note: this order matters for the search result, changed it if the order of property headers on the "KeywordSearchNode"changed - public static enum AbstractFilePropertyType { + @NbBundle.Messages({"AbstractAbstractFileNode.nameColLbl=Name", + "AbstractAbstractFileNode.locationColLbl=Location", + "AbstractAbstractFileNode.modifiedTimeColLbl=Modified Time", + "AbstractAbstractFileNode.changeTimeColLbl=Change Time", + "AbstractAbstractFileNode.accessTimeColLbl=Access Time", + "AbstractAbstractFileNode.createdTimeColLbl=Created Time", + "AbstractAbstractFileNode.sizeColLbl=Size", + "AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)", + "AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta)", + "AbstractAbstractFileNode.modeColLbl=Mode", + "AbstractAbstractFileNode.useridColLbl=UserID", + "AbstractAbstractFileNode.groupidColLbl=GroupID", + "AbstractAbstractFileNode.metaAddrColLbl=Meta Addr.", + "AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.", + "AbstractAbstractFileNode.typeDirColLbl=Type(Dir)", + "AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)", + "AbstractAbstractFileNode.knownColLbl=Known", + "AbstractAbstractFileNode.inHashsetsColLbl=In Hashsets", + "AbstractAbstractFileNode.md5HashColLbl=MD5 Hash", + "AbstractAbstractFileNode.objectId=Object ID", + "AbstractAbstractFileNode.mimeType=MIME Type", + "AbstractAbstractFileNode.extensionColLbl=Extension"}) + public enum AbstractFilePropertyType { - NAME { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.nameColLbl"); - } - }, - LOCATION { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.locationColLbl"); - } - }, - MOD_TIME { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.modifiedTimeColLbl"); - } - }, - CHANGED_TIME { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.changeTimeColLbl"); - } - }, - ACCESS_TIME { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.accessTimeColLbl"); - } - }, - CREATED_TIME { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.createdTimeColLbl"); - } - }, - SIZE { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.sizeColLbl"); - } - }, - FLAGS_DIR { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.flagsDirColLbl"); - } - }, - FLAGS_META { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.flagsMetaColLbl"); - } - }, - MODE { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.modeColLbl"); - } - }, - USER_ID { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.useridColLbl"); - } - }, - GROUP_ID { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.groupidColLbl"); - } - }, - META_ADDR { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.metaAddrColLbl"); - } - }, - ATTR_ADDR { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.attrAddrColLbl"); - } - }, - TYPE_DIR { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.typeDirColLbl"); - } - }, - TYPE_META { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.typeMetaColLbl"); - } - }, - KNOWN { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.knownColLbl"); - } - }, - HASHSETS { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.inHashsetsColLbl"); - } - }, - MD5HASH { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.md5HashColLbl"); - } - }, - ObjectID { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.objectId"); + NAME(AbstractAbstractFileNode_nameColLbl()), + LOCATION(AbstractAbstractFileNode_locationColLbl()), + MOD_TIME(AbstractAbstractFileNode_modifiedTimeColLbl()), + CHANGED_TIME(AbstractAbstractFileNode_changeTimeColLbl()), + ACCESS_TIME(AbstractAbstractFileNode_accessTimeColLbl()), + CREATED_TIME(AbstractAbstractFileNode_createdTimeColLbl()), + SIZE(AbstractAbstractFileNode_sizeColLbl()), + FLAGS_DIR(AbstractAbstractFileNode_flagsDirColLbl()), + FLAGS_META(AbstractAbstractFileNode_flagsMetaColLbl()), + MODE(AbstractAbstractFileNode_modeColLbl()), + USER_ID(AbstractAbstractFileNode_useridColLbl()), + GROUP_ID(AbstractAbstractFileNode_groupidColLbl()), + META_ADDR(AbstractAbstractFileNode_metaAddrColLbl()), + ATTR_ADDR(AbstractAbstractFileNode_attrAddrColLbl()), + TYPE_DIR(AbstractAbstractFileNode_typeDirColLbl()), + TYPE_META(AbstractAbstractFileNode_typeMetaColLbl()), + KNOWN(AbstractAbstractFileNode_knownColLbl()), + HASHSETS(AbstractAbstractFileNode_inHashsetsColLbl()), + MD5HASH(AbstractAbstractFileNode_md5HashColLbl()), + ObjectID(AbstractAbstractFileNode_objectId()), + MIMETYPE(AbstractAbstractFileNode_mimeType()), + EXTENSION(AbstractAbstractFileNode_extensionColLbl()); - } - }, - MIMETYPE { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.mimeType"); + final private String displayString; - } - }, + private AbstractFilePropertyType(String displayString) { + this.displayString = displayString; + } + + @Override + public String toString() { + return displayString; + } } /** * Fill map with AbstractFile properties * - * @param map map with preserved ordering, where property names/values are - * put - * @param content to extract properties from + * @param map map with preserved ordering, where property names/values + * are put + * @param content The content to get properties for. */ - public static void fillPropertyMap(Map<String, Object> map, AbstractFile content) { - - String path = ""; - try { - path = content.getUniquePath(); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Except while calling Content.getUniquePath() on {0}", content); //NON-NLS - } - - map.put(AbstractFilePropertyType.NAME.toString(), AbstractAbstractFileNode.getContentDisplayName(content)); - map.put(AbstractFilePropertyType.LOCATION.toString(), path); - map.put(AbstractFilePropertyType.MOD_TIME.toString(), ContentUtils.getStringTime(content.getMtime(), content)); - map.put(AbstractFilePropertyType.CHANGED_TIME.toString(), ContentUtils.getStringTime(content.getCtime(), content)); - map.put(AbstractFilePropertyType.ACCESS_TIME.toString(), ContentUtils.getStringTime(content.getAtime(), content)); - map.put(AbstractFilePropertyType.CREATED_TIME.toString(), ContentUtils.getStringTime(content.getCrtime(), content)); - map.put(AbstractFilePropertyType.SIZE.toString(), content.getSize()); - map.put(AbstractFilePropertyType.FLAGS_DIR.toString(), content.getDirFlagAsString()); - map.put(AbstractFilePropertyType.FLAGS_META.toString(), content.getMetaFlagsAsString()); - map.put(AbstractFilePropertyType.MODE.toString(), content.getModesAsString()); - map.put(AbstractFilePropertyType.USER_ID.toString(), content.getUid()); - map.put(AbstractFilePropertyType.GROUP_ID.toString(), content.getGid()); - map.put(AbstractFilePropertyType.META_ADDR.toString(), content.getMetaAddr()); - map.put(AbstractFilePropertyType.ATTR_ADDR.toString(), Long.toString(content.getAttrType().getValue()) + "-" + content.getAttributeId()); - map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel()); - map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString()); - map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName()); - map.put(AbstractFilePropertyType.HASHSETS.toString(), getHashSetHitsForFile(content)); - map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash()); - map.put(AbstractFilePropertyType.ObjectID.toString(), content.getId()); - map.put(AbstractFilePropertyType.MIMETYPE.toString(), content.getMIMEType() == null ? "" : content.getMIMEType()); + static public void fillPropertyMap(Map<String, Object> map, AbstractFile content) { + map.put(NAME.toString(), getContentDisplayName(content)); + map.put(LOCATION.toString(), getContentPath(content)); + map.put(MOD_TIME.toString(), ContentUtils.getStringTime(content.getMtime(), content)); + map.put(CHANGED_TIME.toString(), ContentUtils.getStringTime(content.getCtime(), content)); + map.put(ACCESS_TIME.toString(), ContentUtils.getStringTime(content.getAtime(), content)); + map.put(CREATED_TIME.toString(), ContentUtils.getStringTime(content.getCrtime(), content)); + map.put(SIZE.toString(), content.getSize()); + map.put(FLAGS_DIR.toString(), content.getDirFlagAsString()); + map.put(FLAGS_META.toString(), content.getMetaFlagsAsString()); + map.put(MODE.toString(), content.getModesAsString()); + map.put(USER_ID.toString(), content.getUid()); + map.put(GROUP_ID.toString(), content.getGid()); + map.put(META_ADDR.toString(), content.getMetaAddr()); + map.put(ATTR_ADDR.toString(), content.getAttrType().getValue() + "-" + content.getAttributeId()); + map.put(TYPE_DIR.toString(), content.getDirType().getLabel()); + map.put(TYPE_META.toString(), content.getMetaType().toString()); + map.put(KNOWN.toString(), content.getKnown().getName()); + map.put(HASHSETS.toString(), getHashSetHitsForFile(content)); + map.put(MD5HASH.toString(), StringUtils.defaultString(content.getMd5Hash())); + map.put(ObjectID.toString(), content.getId()); + map.put(MIMETYPE.toString(), StringUtils.defaultString(content.getMIMEType())); + map.put(EXTENSION.toString(), content.getNameExtension()); } /** * Used by subclasses of AbstractAbstractFileNode to add the tags property * to their sheets. - * @param ss the modifiable Sheet.Set returned by Sheet.get(Sheet.PROPERTIES) + * + * @param ss the modifiable Sheet.Set returned by + * Sheet.get(Sheet.PROPERTIES) */ + @NbBundle.Messages("AbstractAbstractFileNode.tagsProperty.displayName=Tags") protected void addTagProperty(Sheet.Set ss) { - final String NO_DESCR = NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.addFileProperty.desc"); - List<ContentTag> tags; + List<ContentTag> tags = new ArrayList<>(); + try { + tags.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content)); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex); + } + ss.put(new NodeProperty<>("Tags", AbstractAbstractFileNode_tagsProperty_displayName(), + NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()) + .distinct() + .collect(Collectors.joining(", ")))); + } + + private static String getContentPath(AbstractFile file) { try { - tags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content); + return file.getUniquePath(); } catch (TskCoreException ex) { - tags = new ArrayList<>(); - LOGGER.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex); + logger.log(Level.SEVERE, "Except while calling Content.getUniquePath() on " + file, ex); //NON-NLS + return ""; //NON-NLS } - ss.put(new NodeProperty<>("Tags", NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.addFileProperty.tags.displayName"), - NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", ")))); } static String getContentDisplayName(AbstractFile file) { @@ -330,12 +259,11 @@ static String getContentDisplayName(AbstractFile file) { } } - @SuppressWarnings("deprecation") - private static String getHashSetHitsForFile(AbstractFile content) { + private static String getHashSetHitsForFile(AbstractFile file) { try { - return StringUtils.join(content.getHashSetNames(), ", "); + return StringUtils.join(file.getHashSetNames(), ", "); } catch (TskCoreException tskCoreException) { - LOGGER.log(Level.WARNING, "Error getting hashset hits: ", tskCoreException); //NON-NLS + logger.log(Level.WARNING, "Error getting hashset hits: ", tskCoreException); //NON-NLS return ""; } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 03066faa550f84c74e099b7ed7854a530a947c0c..bf139f9a476ba703a9e440b0568cd3f0d3ae3b4a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -25,6 +25,7 @@ import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.accounts.Accounts.AccountsRootNode; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.Directory; @@ -32,6 +33,7 @@ import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.SleuthkitItemVisitor; import org.sleuthkit.datamodel.SleuthkitVisitableItem; @@ -112,11 +114,21 @@ public AbstractContentNode<? extends Content> visit(VirtualDirectory ld) { return new VirtualDirectoryNode(ld); } + @Override + public AbstractContentNode<? extends Content> visit(LocalDirectory ld) { + return new LocalDirectoryNode(ld); + } + @Override public AbstractContentNode<? extends Content> visit(SlackFile sf) { return new SlackFileNode(sf); } + @Override + public AbstractContentNode<? extends Content> visit(BlackboardArtifact art) { + return new BlackboardArtifactNode(art); + } + @Override protected AbstractContentNode<? extends Content> defaultVisit(SleuthkitVisitableItem di) { throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 0a88cfd5dc59824f6e5d1a881c242a750669b6d7..82a8130c23ac17ce40e8481392524631d84f514f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -21,8 +21,8 @@ import java.util.List; import java.util.logging.Level; -import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.openide.util.Lookup; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; @@ -48,13 +48,23 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode * @param content Underlying Content instances */ AbstractContentNode(T content) { - //TODO consider child factory for the content children - super(new ContentChildren(content), Lookups.singleton(content)); + this(content, Lookups.singleton(content) ); + } + + /** + * Handles aspects that depend on the Content object + * + * @param content Underlying Content instances + * @param lookup The Lookup object for the node. + */ + AbstractContentNode(T content, Lookup lookup) { + //TODO consider child factory for the content children + super(new ContentChildren(content), lookup); this.content = content; //super.setName(ContentUtils.getSystemName(content)); super.setName("content_" + Long.toString(content.getId())); //NON-NLS } - + /** * Return the content data associated with this node * @@ -66,8 +76,7 @@ public T getContent() { @Override public void setName(String name) { - throw new UnsupportedOperationException( - NbBundle.getMessage(this.getClass(), "AbstractContentNode.exception.cannotChangeSysName.msg")); + super.setName(name); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java index a6db3c1df1cbca62aa2264693caf1185962089ba..b8a6807c2409d0aa3300f51642ad36262f38e17a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java @@ -69,14 +69,11 @@ protected Sheet createSheet() { s.put(ss); } - Map<String, Object> map = new LinkedHashMap<String, Object>(); - AbstractAbstractFileNode.fillPropertyMap(map, content); + Map<String, Object> map = new LinkedHashMap<>(); + fillPropertyMap(map, getContent()); - AbstractFilePropertyType[] fsTypes = AbstractFilePropertyType.values(); - final int FS_PROPS_LEN = fsTypes.length; final String NO_DESCR = NbBundle.getMessage(this.getClass(), "AbstractFsContentNode.noDesc.text"); - for (int i = 0; i < FS_PROPS_LEN; ++i) { - final AbstractFilePropertyType propType = AbstractFilePropertyType.values()[i]; + for (AbstractFilePropertyType propType : AbstractFilePropertyType.values()) { final String propString = propType.toString(); ss.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString))); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 7317b5781f2476f721456a2fba7b51ffd9f77095..0e1c7cb8aa6afb5dfe9f9042fa0a639b6bcad388 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -25,6 +25,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -34,6 +35,7 @@ import java.util.stream.Collectors; import javax.swing.Action; import org.openide.nodes.Children; +import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -43,9 +45,11 @@ import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; +import static org.sleuthkit.autopsy.datamodel.DataModelActionsFactory.VIEW_IN_NEW_WINDOW; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; @@ -61,7 +65,7 @@ * Node wrapping a blackboard artifact object. This is generated from several * places in the tree. */ -public class BlackboardArtifactNode extends DisplayableItemNode { +public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> { private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName()); @@ -70,8 +74,9 @@ public class BlackboardArtifactNode extends DisplayableItemNode { build(); private final BlackboardArtifact artifact; - private final Content associated; + private Content associated = null; private List<NodeProperty<? extends Object>> customProperties; + /* * Artifact types which should have the full unique path of the associated * content as a property. @@ -130,11 +135,18 @@ public void propertyChange(PropertyChangeEvent evt) { * @param iconPath icon to use for the artifact */ public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) { - super(Children.LEAF, createLookup(artifact)); + super(artifact, createLookup(artifact)); this.artifact = artifact; - //this.associated = getAssociatedContent(artifact); - this.associated = this.getLookup().lookup(Content.class); + + // Look for associated Content i.e. the source file for the artifact + for (Content content : this.getLookup().lookupAll(Content.class)) { + if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){ + this.associated = content; + break; + } + } + this.setName(Long.toString(artifact.getArtifactID())); this.setDisplayName(); this.setIconBaseWithExtension(iconPath); @@ -148,20 +160,18 @@ public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) { * @param artifact artifact to encapsulate */ public BlackboardArtifactNode(BlackboardArtifact artifact) { - super(Children.LEAF, createLookup(artifact)); - - this.artifact = artifact; - this.associated = this.getLookup().lookup(Content.class); - this.setName(Long.toString(artifact.getArtifactID())); - this.setDisplayName(); - this.setIconBaseWithExtension(ExtractedContent.getIconFilePath(artifact.getArtifactTypeID())); //NON-NLS - Case.addPropertyChangeListener(pcl); + + this(artifact, ExtractedContent.getIconFilePath(artifact.getArtifactTypeID())); } private void removeListeners() { Case.removePropertyChangeListener(pcl); } + public BlackboardArtifact getArtifact() { + return this.artifact; + } + @Override @NbBundle.Messages({ "BlackboardArtifactNode.getAction.errorTitle=Error getting actions", @@ -211,10 +221,7 @@ public Action[] getActions(boolean context) { */ private void setDisplayName() { String displayName = ""; //NON-NLS - if (associated != null) { - displayName = associated.getName(); - } - + // If this is a node for a keyword hit on an artifact, we set the // display name to be the artifact type name followed by " Artifact" // e.g. "Messages Artifact". @@ -238,9 +245,30 @@ private void setDisplayName() { // Do nothing since the display name will be set to the file name. } } + + if (displayName.isEmpty() && artifact != null) { + displayName = artifact.getName(); + } + this.setDisplayName(displayName); + } + /** + * Return the name of the associated source file/content + * + * @return source file/content name + */ + public String getSrcName() { + + String srcName = ""; + if (associated != null) { + srcName = associated.getName(); + } + return srcName; + } + + @NbBundle.Messages({ "BlackboardArtifactNode.createSheet.artifactType.displayName=Artifact Type", "BlackboardArtifactNode.createSheet.artifactType.name=Artifact Type", @@ -264,7 +292,7 @@ protected Sheet createSheet() { ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"), NO_DESCR, - this.getDisplayName())); + this.getSrcName())); if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { try { BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); @@ -555,4 +583,9 @@ public boolean isLeafTypeNode() { public String getItemType() { return getClass().getName(); } + + @Override + public <T> T accept(ContentNodeVisitor<T> v) { + return v.visit(this); + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index a712c1bdb74c41660d045c174a69e0dc851b83ed..dd8a8cb5ff58d8f4a831e51678168fe1e4a7c7f2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -1,24 +1,4 @@ OpenIDE-Module-Name=DataModel -AbstractAbstractFileNode.nameColLbl=Name -AbstractAbstractFileNode.locationColLbl=Location -AbstractAbstractFileNode.modifiedTimeColLbl=Modified Time -AbstractAbstractFileNode.changeTimeColLbl=Change Time -AbstractAbstractFileNode.accessTimeColLbl=Access Time -AbstractAbstractFileNode.createdTimeColLbl=Created Time -AbstractAbstractFileNode.sizeColLbl=Size -AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir) -AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta) -AbstractAbstractFileNode.modeColLbl=Mode -AbstractAbstractFileNode.useridColLbl=UserID -AbstractAbstractFileNode.groupidColLbl=GroupID -AbstractAbstractFileNode.metaAddrColLbl=Meta Addr. -AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr. -AbstractAbstractFileNode.typeDirColLbl=Type(Dir) -AbstractAbstractFileNode.typeMetaColLbl=Type(Meta) -AbstractAbstractFileNode.knownColLbl=Known -AbstractAbstractFileNode.inHashsetsColLbl=In Hashsets -AbstractAbstractFileNode.md5HashColLbl=MD5 Hash -AbstractAbstractFileNode.mimeType = MIME Type AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg=No Node defined for the given SleuthkitItem AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg=No Node defined for the given DisplayableItem AbstractContentNode.exception.cannotChangeSysName.msg=Cannot change the system name. @@ -80,17 +60,6 @@ DataSourcesNode.name=Data Sources DataSourcesNode.createSheet.name.name=Name DataSourcesNode.createSheet.name.displayName=Name DataSourcesNode.createSheet.name.desc=no description -DeletedContent.fsDelFilter.text=File System -DeletedContent.allDelFilter.text=All -DeletedContent.deletedContentsNode.name=Deleted Files -DeletedContent.createSheet.name.name=Name -DeletedContent.createSheet.name.displayName=Name -DeletedContent.createSheet.name.desc=no description -DeletedContent.createSheet.filterType.name=Type -DeletedContent.createSheet.filterType.displayName=Type -DeletedContent.createSheet.filterType.desc=no description -DeletedContent.createKeys.maxObjects.msg=There are more Deleted Files than can be displayed. Only the first {0} Deleted Files will be shown. -DeletedContent.createNodeForKey.typeNotSupported.msg=Not supported for this type of Displayable Item\: {0} DirectoryNode.parFolder.text=[parent folder] DirectoryNode.curFolder.text=[current folder] DirectoryNode.getActions.viewFileInDir.text=View File in Directory @@ -233,16 +202,12 @@ VolumeNode.createSheet.description.desc=no description VolumeNode.createSheet.flags.name=Flags VolumeNode.createSheet.flags.displayName=Flags VolumeNode.createSheet.flags.desc=no description -AbstractAbstractFileNode.objectId=Object ID ArtifactStringContent.getStr.artifactId.text=Artifact ID DeleteReportAction.actionDisplayName.singleReport=Delete Report DeleteReportAction.actionDisplayName.multipleReports=Delete Reports DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion DeleteReportAction.actionPerformed.showConfirmDialog.single.msg=Do you want to delete 1 report from the case? DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg=Do you want to delete {0} reports from the case? -AbstractAbstractFileNode.addFileProperty.desc=no description -AbstractAbstractFileNode.addFileProperty.tags.name=Tags -AbstractAbstractFileNode.addFileProperty.tags.displayName=Tags BlackboardArtifactNode.createSheet.tags.name=Tags BlackboardArtifactNode.createSheet.tags.displayName=Tags FileTypeExtensionFilters.tskImgFilter.text=Images @@ -255,4 +220,4 @@ FileTypeExtensionFilters.autDocHtmlFilter.text=HTML FileTypeExtensionFilters.autDocOfficeFilter.text=Office FileTypeExtensionFilters.autoDocPdfFilter.text=PDF FileTypeExtensionFilters.autDocTxtFilter.text=Plain Text -FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text \ No newline at end of file +FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java index 6dbd8002eefc4eb16981620f5d93cb9dd420b161..2277cb4b5608e49459127b9a3b651391246ec656 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java @@ -31,6 +31,8 @@ interface ContentNodeVisitor<T> { T visit(ImageNode in); T visit(VirtualDirectoryNode lcn); + + T visit(LocalDirectoryNode ldn); T visit(VolumeNode vn); @@ -43,6 +45,9 @@ interface ContentNodeVisitor<T> { T visit(LocalFileNode dfn); T visit(SlackFileNode sfn); + + T visit(BlackboardArtifactNode bban); + /** * Visitor with an implementable default behavior for all types. Override @@ -96,9 +101,19 @@ public T visit(VirtualDirectoryNode ldn) { return defaultVisit(ldn); } + @Override + public T visit(LocalDirectoryNode ldn) { + return defaultVisit(ldn); + } + @Override public T visit(SlackFileNode sfn) { return defaultVisit(sfn); } + + @Override + public T visit(BlackboardArtifactNode bban) { + return defaultVisit(bban); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java index 1b457966fe184d19dd5a2d4dbb02bc2f7e3a6bfe..8034a4f9fb4285c4f6f13a91fdb73380a0a0bcf6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java @@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.TskException; @@ -378,6 +379,11 @@ public Void visit(Directory dir) { public Void visit(VirtualDirectory dir) { return visitDir(dir); } + + @Override + public Void visit(LocalDirectory dir) { + return visitDir(dir); + } private java.io.File getFsContentDest(Content fsc) { String path = dest.getAbsolutePath() + java.io.File.separator diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index dc1aa9a8bf0b410605589652132e59b66ce8bec0..db9967b743cdacb36cbddca0753af13faeddaa0e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -44,6 +44,7 @@ import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.VirtualDirectory; @@ -229,6 +230,38 @@ public static List<Action> getActions(VirtualDirectory directory, boolean isArti actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } + + public static List<Action> getActions(LocalDirectory directory, boolean isArtifactSource) { + List<Action> actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory)); + LocalDirectoryNode directoryNode = new LocalDirectoryNode(directory); + actionsList.add(null); // creates a menu separator + actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode)); + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); + if (isArtifactSource) { + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); + } + + final Collection<AbstractFile> selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if(selectedFilesList.size() == 1) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } + if(isArtifactSource) { + final Collection<BlackboardArtifact> selectedArtifactsList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if(selectedArtifactsList.size() == 1) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; + } public static List<Action> getActions(LocalFile file, boolean isArtifactSource) { List<Action> actionsList = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 589dfc4c86d2c52b33383fb1fb4cee10e212c6c2..0b6ced4f169a645bc47fa04c58f14512243d48a9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2013-2017 Basis Technology Corp. + * + * Copyright 2011-2017 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. @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; +import static org.sleuthkit.autopsy.datamodel.Bundle.*; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; @@ -58,14 +59,15 @@ public class DeletedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; + @NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System", + "DeletedContent.allDelFilter.text=All"}) public enum DeletedContentFilter implements AutopsyVisitableItem { - FS_DELETED_FILTER(0, - "FS_DELETED_FILTER", //NON-NLS - NbBundle.getMessage(DeletedContent.class, "DeletedContent.fsDelFilter.text")), - ALL_DELETED_FILTER(1, - "ALL_DELETED_FILTER", //NON-NLS - NbBundle.getMessage(DeletedContent.class, "DeletedContent.allDelFilter.text")); + FS_DELETED_FILTER(0, "FS_DELETED_FILTER", //NON-NLS + Bundle.DeletedContent_fsDelFilter_text()), + ALL_DELETED_FILTER(1, "ALL_DELETED_FILTER", //NON-NLS + Bundle.DeletedContent_allDelFilter_text()); + private int id; private String name; private String displayName; @@ -110,15 +112,13 @@ public SleuthkitCase getSleuthkitCase() { public static class DeletedContentsNode extends DisplayableItemNode { - private static final String NAME = NbBundle.getMessage(DeletedContent.class, - "DeletedContent.deletedContentsNode.name"); - private SleuthkitCase skCase; + @NbBundle.Messages("DeletedContent.deletedContentsNode.name=Deleted Files") + private static final String NAME = Bundle.DeletedContent_deletedContentsNode_name(); DeletedContentsNode(SleuthkitCase skCase) { super(Children.create(new DeletedContentsChildren(skCase), true), Lookups.singleton(NAME)); super.setName(NAME); super.setDisplayName(NAME); - this.skCase = skCase; this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS } @@ -133,6 +133,9 @@ public <T> T accept(DisplayableItemNodeVisitor<T> v) { } @Override + @NbBundle.Messages({ + "DeletedContent.createSheet.name.displayName=Name", + "DeletedContent.createSheet.name.desc=no description"}) protected Sheet createSheet() { Sheet s = super.createSheet(); Sheet.Set ss = s.get(Sheet.PROPERTIES); @@ -141,9 +144,9 @@ protected Sheet createSheet() { s.put(ss); } - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.name.displayName"), - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.name.desc"), + ss.put(new NodeProperty<>("Name", //NON-NLS + Bundle.DeletedContent_createSheet_name_displayName(), + Bundle.DeletedContent_createSheet_name_desc(), NAME)); return s; } @@ -303,6 +306,9 @@ public <T> T accept(DisplayableItemNodeVisitor<T> v) { } @Override + @NbBundle.Messages({ + "DeletedContent.createSheet.filterType.displayName=Type", + "DeletedContent.createSheet.filterType.desc=no description"}) protected Sheet createSheet() { Sheet s = super.createSheet(); Sheet.Set ss = s.get(Sheet.PROPERTIES); @@ -311,10 +317,9 @@ protected Sheet createSheet() { s.put(ss); } - ss.put(new NodeProperty<>( - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.filterType.name"), - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.filterType.displayName"), - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.filterType.desc"), + ss.put(new NodeProperty<>("Type", //NON_NLS + Bundle.DeletedContent_createSheet_filterType_displayName(), + Bundle.DeletedContent_createSheet_filterType_desc(), filter.getDisplayName())); return s; @@ -334,7 +339,7 @@ public String getItemType() { return DisplayableItemNode.FILE_PARENT_NODE_KEY; } } - + static class DeletedContentChildren extends ChildFactory.Detachable<AbstractFile> { private final SleuthkitCase skCase; @@ -375,6 +380,10 @@ protected void removeNotify() { } @Override + @NbBundle.Messages({"# {0} - The deleted files threshold", + "DeletedContent.createKeys.maxObjects.msg=" + + "There are more Deleted Files than can be displayed." + + " Only the first {0} Deleted Files will be shown."}) protected boolean createKeys(List<AbstractFile> list) { List<AbstractFile> queryList = runFsQuery(); if (queryList.size() == MAX_OBJECTS) { @@ -382,14 +391,10 @@ protected boolean createKeys(List<AbstractFile> list) { // only show the dialog once - not each time we refresh if (maxFilesDialogShown == false) { maxFilesDialogShown = true; - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(this.getClass(), - "DeletedContent.createKeys.maxObjects.msg", - MAX_OBJECTS - 1)); - } - }); + SwingUtilities.invokeLater(() + -> JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + DeletedContent_createKeys_maxObjects_msg(MAX_OBJECTS - 1)) + ); } } list.addAll(queryList); @@ -428,14 +433,13 @@ static private String makeQuery(DeletedContent.DeletedContentFilter filter) { logger.log(Level.SEVERE, "Unsupported filter type to get deleted content: {0}", filter); //NON-NLS } - - if(UserPreferences.hideKnownFilesInViewsTree()) { + + if (UserPreferences.hideKnownFilesInViewsTree()) { query += " AND (known != " + TskData.FileKnown.KNOWN.getFileKnownValue() //NON-NLS + " OR known IS NULL)"; //NON-NLS } query += " LIMIT " + MAX_OBJECTS; //NON-NLS - return query; } @@ -456,6 +460,9 @@ private List<AbstractFile> runFsQuery() { /** * Get children count without actually loading all nodes * + * @param sleuthkitCase + * @param filter + * * @return */ static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter) { @@ -495,9 +502,7 @@ public FileNode visit(Directory f) { @Override protected AbstractNode defaultVisit(Content di) { - throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(), - "DeletedContent.createNodeForKey.typeNotSupported.msg", - di.toString())); + throw new UnsupportedOperationException("Not supported for this type of Displayable Item: " + di.toString()); } }); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 5cc152e4653dc6a856a5f4b935e533ff92a97466..e6e8afed52723bf96b0bb9be8553be3076077f12 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -41,6 +41,8 @@ public interface DisplayableItemNodeVisitor<T> { T visit(LocalFileNode dfn); T visit(VirtualDirectoryNode ldn); + + T visit(LocalDirectoryNode ldn); T visit(DirectoryNode dn); @@ -370,6 +372,11 @@ public T visit(VirtualDirectoryNode ldn) { return defaultVisit(ldn); } + @Override + public T visit(LocalDirectoryNode ldn) { + return defaultVisit(ldn); + } + @Override public T visit(Tags.RootNode node) { return defaultVisit(node); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index ca4602e30a94f7952379658eb33aca6287955066..ad740a501196eebf046a65f80fd601056d3149ab 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -428,7 +428,7 @@ private void updateDisplayName() { @Override public boolean isLeafTypeNode() { - return true; + return false; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 2e1fba50ccccf30e74f8c525c9aa10842dfd9548..d8ef2a2f5ea026d95f24b3eaeb8f25677b8f92fc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -353,29 +353,14 @@ private String createQuery(FileTypesByExtension.SearchFilterInterface filter) { throw new IllegalArgumentException("Empty filter list passed to createQuery()"); // NON-NLS } - String query = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" - + (UserPreferences.hideKnownFilesInViewsTree() ? " AND (known IS NULL OR known != " - + TskData.FileKnown.KNOWN.getFileKnownValue() + ")" : " ") - + " AND (NULL "; //NON-NLS - - if (skCase.getDatabaseType().equals(TskData.DbType.POSTGRESQL)) { - // For PostgreSQL we get a more efficient query by using builtin - // regular expression support and or'ing all extensions. We also - // escape the dot at the beginning of the extension. - // We will end up with a query that looks something like this: - // OR LOWER(name) ~ '(\.zip|\.rar|\.7zip|\.cab|\.jar|\.cpio|\.ar|\.gz|\.tgz|\.bz2)$') - query += "OR LOWER(name) ~ '(\\"; - query += StringUtils.join(filter.getFilter().stream() - .map(String::toLowerCase).collect(Collectors.toList()), "|\\"); - query += ")$'"; - } else { - for (String s : filter.getFilter()) { - query += "OR LOWER(name) LIKE '%" + s.toLowerCase() + "'"; // NON-NLS - } - } - - query += ')'; - return query; + return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" + + (UserPreferences.hideKnownFilesInViewsTree() + ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")" + : " ") + + " AND (extension IN (" + filter.getFilter().stream() + .map(String::toLowerCase) + .map(s -> "'"+StringUtils.substringAfter(s, ".")+"'") + .collect(Collectors.joining(", ")) + "))"; } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index c759b425d7a964135c294e14ab2517a82592785c..0d541d7e1a4ae741cf3a7a9b30c450d3df0c8223 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -79,7 +79,7 @@ protected Sheet createSheet() { } Map<String, Object> map = new LinkedHashMap<>(); - fillPropertyMap(map, content); + fillPropertyMap(map); ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "LayoutFileNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "LayoutFileNode.createSheet.name.displayName"), @@ -134,11 +134,12 @@ public Action[] getActions(boolean context) { } actionsList.addAll(ContextMenuExtensionPoint.getActions()); - return actionsList.toArray(new Action[0]); + return actionsList.toArray(new Action[actionsList.size()]); } - private static void fillPropertyMap(Map<String, Object> map, LayoutFile content) { - AbstractAbstractFileNode.fillPropertyMap(map, content); + + void fillPropertyMap(Map<String, Object> map) { + AbstractAbstractFileNode.fillPropertyMap(map, getContent()); map.put(LayoutContentPropertyType.PARTS.toString(), content.getNumParts()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java new file mode 100644 index 0000000000000000000000000000000000000000..f9bab8d5b2e1f3dad30a5f82c86b9d811d08bc3a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java @@ -0,0 +1,86 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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; + +import java.util.LinkedHashMap; +import java.util.Map; +import org.openide.nodes.Sheet; +import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.LocalDirectory; + +/** + * Node for a local directory + */ +public class LocalDirectoryNode extends SpecialDirectoryNode { + + public static String nameForLocalDir(LocalDirectory ld) { + return ld.getName(); + } + + public LocalDirectoryNode(LocalDirectory ld) { + super(ld); + + this.setDisplayName(nameForLocalDir(ld)); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png"); //NON-NLS + + } + + @Override + @NbBundle.Messages({ + "LocalDirectoryNode.createSheet.name.name=Name", + "LocalDirectoryNode.createSheet.name.displayName=Name", + "LocalDirectoryNode.createSheet.name.desc=no description", + "LocalDirectoryNode.createSheet.noDesc=no description"}) + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + + ss.put(new NodeProperty<>(Bundle.LocalDirectoryNode_createSheet_name_name(), + Bundle.LocalDirectoryNode_createSheet_name_displayName(), + Bundle.LocalDirectoryNode_createSheet_name_desc(), + getName())); + + // At present, a LocalDirectory will never be a datasource - the top level of a logical + // file set is a VirtualDirectory + Map<String, Object> map = new LinkedHashMap<>(); + fillPropertyMap(map, getContent()); + + final String NO_DESCR = Bundle.LocalDirectoryNode_createSheet_noDesc(); + for (Map.Entry<String, Object> entry : map.entrySet()) { + ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue())); + } + addTagProperty(ss); + + return s; + } + + @Override + public <T> T accept(ContentNodeVisitor<T> v) { + return v.visit(this); + } + + @Override + public <T> T accept(DisplayableItemNodeVisitor<T> v) { + return v.visit(this); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index 5738356c46a874d2a7007e805d545527f3ce3233..e14e41416e4bebd3b3ec40f0704e0926c3852951 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -71,7 +71,7 @@ protected Sheet createSheet() { } Map<String, Object> map = new LinkedHashMap<>(); - fillPropertyMap(map, content); + fillPropertyMap(map, getContent()); ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "LocalFileNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "LocalFileNode.createSheet.name.displayName"), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java new file mode 100644 index 0000000000000000000000000000000000000000..a25034481af2fec29f592c4b0be6a33119d2cbc6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -0,0 +1,82 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.swing.Action; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.FileSearchAction; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.SpecialDirectory; + +/** + * Parent class for special directory types (Local and Virtual) + */ +public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode<SpecialDirectory> { + + public SpecialDirectoryNode(SpecialDirectory sd) { + super(sd); + } + + /** + * Right click action for this node + * + * @param popup + * + * @return + */ + @Override + @NbBundle.Messages({"SpecialDirectoryNode.action.runIngestMods.text=Run Ingest Modules", + "SpecialDirectoryNode.getActions.viewInNewWin.text=View in New Window" + }) + public Action[] getActions(boolean popup) { + List<Action> actions = new ArrayList<>(); + for (Action a : super.getActions(true)) { + actions.add(a); + } + + actions.add(new NewWindowViewAction( + Bundle.SpecialDirectoryNode_action_runIngestMods_text(), this)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(null); // creates a menu separator + actions.add(new FileSearchAction( + Bundle.ImageNode_getActions_openFileSearchByAttr_text())); + actions.add(new RunIngestModulesAction(Collections.<Content>singletonList(content))); + actions.addAll(ContextMenuExtensionPoint.getActions()); + return actions.toArray(new Action[0]); + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + @Override + public String getItemType() { + // use content.isDataSource if different column settings are desired + return DisplayableItemNode.FILE_PARENT_NODE_KEY; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index ac861c88475f6eff7d111508ab881e6f8e4cdec4..3d78d3f13d48fe7e7f5bbbbce5f30458ca4da973 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -20,91 +20,47 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.logging.Level; -import javax.swing.Action; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.directorytree.FileSearchAction; -import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.VirtualDirectory; /** - * Node for layout dir + * Node for a virtual directory */ -public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirectory> { +public class VirtualDirectoryNode extends SpecialDirectoryNode { private static final Logger logger = Logger.getLogger(VirtualDirectoryNode.class.getName()); //prefix for special VirtualDirectory root nodes grouping local files public final static String LOGICAL_FILE_SET_PREFIX = "LogicalFileSet"; //NON-NLS - public static String nameForLayoutFile(VirtualDirectory ld) { + public static String nameForVirtualDirectory(VirtualDirectory ld) { return ld.getName(); } public VirtualDirectoryNode(VirtualDirectory ld) { super(ld); - this.setDisplayName(nameForLayoutFile(ld)); + this.setDisplayName(nameForVirtualDirectory(ld)); String name = ld.getName(); - //set icon for name, special case for some built-ins - if (name.equals(VirtualDirectory.NAME_UNALLOC)) { - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-deleted.png"); //NON-NLS - } else if (ld.isDataSource()) { + //set icon for name, special case for logical file set + if (ld.isDataSource()) { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS - } else if (name.equals(VirtualDirectory.NAME_CARVED)) { - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png"); //TODO NON-NLS } else { - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png"); //NON-NLS + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-virtual.png"); //TODO NON-NLS } - } - - /** - * Right click action for this node - * - * @param popup - * - * @return - */ + @Override - @NbBundle.Messages({"VirtualDirectoryNode.action.runIngestMods.text=Run Ingest Modules"}) - public Action[] getActions(boolean popup) { - List<Action> actions = new ArrayList<>(); - for (Action a : super.getActions(true)) { - actions.add(a); - } - - actions.add(new NewWindowViewAction( - NbBundle.getMessage(this.getClass(), "VirtualDirectoryNode.getActions.viewInNewWin.text"), this)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(null); // creates a menu separator - actions.add(new FileSearchAction( - Bundle.ImageNode_getActions_openFileSearchByAttr_text())); - actions.add(new RunIngestModulesAction(Collections.<Content>singletonList(content))); - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions.toArray(new Action[0]); - } - - @Override - @Messages({"VirtualDirectoryNode.createSheet.size.name=Size (Bytes)", + @NbBundle.Messages({"VirtualDirectoryNode.createSheet.size.name=Size (Bytes)", "VirtualDirectoryNode.createSheet.size.displayName=Size (Bytes)", "VirtualDirectoryNode.createSheet.size.desc=Size of the data source in bytes.", "VirtualDirectoryNode.createSheet.type.name=Type", @@ -133,7 +89,7 @@ protected Sheet createSheet() { if (!this.content.isDataSource()) { Map<String, Object> map = new LinkedHashMap<>(); - fillPropertyMap(map, content); + fillPropertyMap(map, getContent()); final String NO_DESCR = NbBundle.getMessage(this.getClass(), "VirtualDirectoryNode.createSheet.noDesc"); for (Map.Entry<String, Object> entry : map.entrySet()) { @@ -186,39 +142,4 @@ public <T> T accept(ContentNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) { return v.visit(this); } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - /** - * Convert meta flag long to user-readable string / label - * - * @param metaFlag to convert - * - * @return string formatted meta flag representation - */ - public static String metaFlagToString(short metaFlag) { - - String result = ""; - - short allocFlag = TskData.TSK_FS_META_FLAG_ENUM.ALLOC.getValue(); - short unallocFlag = TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(); - - if ((metaFlag & allocFlag) == allocFlag) { - result = TskData.TSK_FS_META_FLAG_ENUM.ALLOC.toString(); - } - if ((metaFlag & unallocFlag) == unallocFlag) { - result = TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.toString(); - } - - return result; - } - - @Override - public String getItemType() { - // use content.isDataSource if different column settings are desired - return DisplayableItemNode.FILE_PARENT_NODE_KEY; - } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 21146610da1535ff944120921e0ada331656b81e..c13b2442bc051299c9c365d82a6c3e9bbccd5fed 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -20,6 +20,7 @@ import java.awt.event.ActionEvent; import java.beans.PropertyVetoException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -43,6 +44,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; @@ -53,10 +55,12 @@ import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; +import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode; import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.Reports; import org.sleuthkit.autopsy.datamodel.SlackFileNode; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; +import static org.sleuthkit.autopsy.directorytree.Bundle.*; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -66,11 +70,13 @@ import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.VirtualDirectory; -import static org.sleuthkit.autopsy.directorytree.Bundle.*; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.TskCoreException; /** * A node used to wrap another node before passing it to the result viewers. The @@ -210,6 +216,26 @@ public Node.PropertySet[] getPropertySets() { return propertySets; } + /** + * Gets the display name for the wrapped node. + * + * OutlineView used in the DataResult table uses getDisplayName() to populate + * the first column, which is Source File. + * + * Hence this override to return the 'correct' displayName for the wrapped node. + * + * @return The display name for the node. + */ + @Override + public String getDisplayName() { + final Node orig = getOriginal(); + String name = orig.getDisplayName(); + if ((orig instanceof BlackboardArtifactNode)) { + name = ((BlackboardArtifactNode) orig).getSrcName(); + } + return name; + } + /** * Adds information about which child node of this node, if any, should be * selected. Can be null. @@ -248,16 +274,20 @@ private static class DataResultFilterChildren extends FilterNode.Children { private boolean filterKnown; private boolean filterSlack; + private boolean filterArtifacts; // display message artifacts in the DataSource subtree /** * the constructor */ private DataResultFilterChildren(Node arg, ExplorerManager sourceEm) { super(arg); + + this.filterArtifacts = false; switch (SelectionContext.getSelectionContext(arg)) { case DATA_SOURCES: filterSlack = filterSlackFromDataSources; filterKnown = filterKnownFromDataSources; + filterArtifacts = true; break; case VIEWS: filterSlack = filterSlackFromViews; @@ -291,6 +321,16 @@ protected Node[] createNodes(Node key) { return new Node[]{}; } } + + // filter out all non-message artifacts, if displaying the results from the Data Source tree + BlackboardArtifact art = key.getLookup().lookup(BlackboardArtifact.class); + if (art != null && filterArtifacts) { + if ( (art.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) && + (art.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) ) { + return new Node[]{}; + } + } + return new Node[]{new DataResultFilterNode(key, sourceEm, filterKnown, filterSlack)}; } } @@ -350,6 +390,8 @@ public List<Action> visit(BlackboardArtifactNode ban) { n = new DirectoryNode((Directory) c); } else if ((c = ban.getLookup().lookup(VirtualDirectory.class)) != null) { n = new VirtualDirectoryNode((VirtualDirectory) c); + } else if ((c = ban.getLookup().lookup(LocalDirectory.class)) != null) { + n = new LocalDirectoryNode((LocalDirectory) c); } else if ((c = ban.getLookup().lookup(LayoutFile.class)) != null) { n = new LayoutFileNode((LayoutFile) c); } else if ((c = ban.getLookup().lookup(LocalFile.class)) != null @@ -459,8 +501,20 @@ private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableI @Override public AbstractAction visit(BlackboardArtifactNode ban) { - return new ViewContextAction( - NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInDir.text"), ban); + BlackboardArtifact artifact = ban.getArtifact(); + try { + if ( (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) || + (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) ) { + if (artifact.hasChildren()) { + return openChild(ban); + } + } + } + catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting children from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS + } + return new ViewContextAction( + NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInDir.text"), ban); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java index 2b10d57f0937008f093d4bef556d6fb2b80c487a..9fbd6425dc93d60220b01c12d5ee6042781c812e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java @@ -26,16 +26,19 @@ import org.openide.nodes.FilterNode; import org.openide.nodes.Node; import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode; +import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; +import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode; import org.sleuthkit.autopsy.datamodel.SlackFileNode; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; import org.sleuthkit.autopsy.datamodel.VolumeNode; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.LayoutFile; @@ -198,7 +201,7 @@ private Boolean visitDeep(AbstractAbstractFileNode<? extends AbstractFile> node) List<Content> derivedChildren = node.getContentChildren(); //child of a file, must be a (derived) file too for (Content childContent : derivedChildren) { - if (((AbstractFile) childContent).isDir()) { + if ((childContent instanceof AbstractFile) && ((AbstractFile) childContent).isDir()) { return false; } else { try { @@ -244,11 +247,26 @@ public Boolean visit(VirtualDirectoryNode vdn) { //return ! vdn.hasContentChildren(); } + @Override + public Boolean visit(LocalDirectoryNode ldn) { + return visitDeep(ldn); + } + @Override public Boolean visit(FileTypesNode ft) { return defaultVisit(ft); } + @Override + public Boolean visit(BlackboardArtifactNode bbafn) { + // Only show Message arttifacts with children + if ( (bbafn.getArtifact().getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) || + (bbafn.getArtifact().getArtifactTypeID() == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) ) { + return bbafn.hasContentChildren(); + } + + return false; + } } private static class ShowItemVisitor extends DisplayableItemNodeVisitor.Default<Boolean> { @@ -292,10 +310,28 @@ public Boolean visit(VirtualDirectoryNode vdn) { //return vdn.hasContentChildren(); } + + @Override + public Boolean visit(LocalDirectoryNode ldn) { + return true; + } + @Override public Boolean visit(FileTypesNode fileTypes) { return defaultVisit(fileTypes); } + + @Override + public Boolean visit(BlackboardArtifactNode bbafn) { + + // Only show Message arttifacts with children + if ( (bbafn.getArtifact().getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) || + (bbafn.getArtifact().getArtifactTypeID() == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) ) { + return bbafn.hasContentChildren(); + } + + return false; + } } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java index ed2a2fd3877354d929ff63c9245a932ba2997817..81a704c57a99ad7d65b038edc3af3fe61fd79d34 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -25,14 +25,17 @@ import javax.swing.Action; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AbstractContentNode; +import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.Image; @@ -77,7 +80,7 @@ public String getDisplayName() { String name = orig.getDisplayName(); if (orig instanceof AbstractContentNode) { AbstractFile file = getLookup().lookup(AbstractFile.class); - if (file != null) { + if ((file != null) && (false == (orig instanceof BlackboardArtifactNode)) ){ try { int numVisibleChildren = getVisibleChildCount(file); @@ -92,6 +95,15 @@ public String getDisplayName() { logger.log(Level.SEVERE, "Error getting children count to display for file: " + file, ex); //NON-NLS } } + else if (orig instanceof BlackboardArtifactNode) { + BlackboardArtifact artifact = ((BlackboardArtifactNode) orig).getArtifact(); + try { + int numAttachments = artifact.getChildrenCount(); + name = name + " \u200E(\u200E" + numAttachments + ")\u200E"; //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting chidlren count for atifact: " + artifact, ex); //NON-NLS + } + } } return name; } @@ -115,13 +127,17 @@ private int getVisibleChildCount(AbstractFile file) throws TskCoreException { if (purgeKnownFiles || purgeSlackFiles) { // Purge known and/or slack files from the file count for (int i = 0; i < childList.size(); i++) { - AbstractFile childFile = (AbstractFile) childList.get(i); - if ((purgeKnownFiles && childFile.getKnown() == TskData.FileKnown.KNOWN) - || (purgeSlackFiles && childFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) { - numVisibleChildren--; + Content child = childList.get(i); + if (child instanceof AbstractFile) { + AbstractFile childFile = (AbstractFile) child; + if ((purgeKnownFiles && childFile.getKnown() == TskData.FileKnown.KNOWN) + || (purgeSlackFiles && childFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) { + numVisibleChildren--; + } } } } + return numVisibleChildren; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index 86c3df1fe3b92fda3b7536fdc24a60c53475bae5..583c2aa1576f78cb2f4c5b570e47abb216eeaec8 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -38,6 +38,7 @@ import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.Volume; @@ -119,6 +120,23 @@ public List<? extends Action> visit(final VirtualDirectory d) { actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } + + @Override + public List<? extends Action> visit(final LocalDirectory d) { + List<Action> actionsList = new ArrayList<>(); + if (!d.isDataSource()) { + actionsList.add(AddContentTagAction.getInstance()); + + final Collection<AbstractFile> selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if(selectedFilesList.size() == 1) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } + } + actionsList.add(ExtractAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; + } @Override public List<? extends Action> visit(final DerivedFile d) { diff --git a/Core/src/org/sleuthkit/autopsy/images/folder-icon-virtual.png b/Core/src/org/sleuthkit/autopsy/images/folder-icon-virtual.png new file mode 100644 index 0000000000000000000000000000000000000000..88f6dd63b276f96f87333eed0d237fe934f8315c Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/folder-icon-virtual.png differ diff --git a/Core/src/org/sleuthkit/autopsy/ingest/GetFilesContentVisitor.java b/Core/src/org/sleuthkit/autopsy/ingest/GetFilesContentVisitor.java index b45b7b307bbb17b00c8a68cc70eaaca4c465a606..e6b5ee02fa600db3024d7e54dd85ecba4ac18dd6 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/GetFilesContentVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/GetFilesContentVisitor.java @@ -28,6 +28,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.VirtualDirectory; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.VolumeSystem; @@ -43,6 +44,11 @@ abstract class GetFilesContentVisitor implements ContentVisitor<Collection<Abstr public Collection<AbstractFile> visit(VirtualDirectory ld) { return getAllFromChildren(ld); } + + @Override + public Collection<AbstractFile> visit(LocalDirectory ld) { + return getAllFromChildren(ld); + } @Override public Collection<AbstractFile> visit(Directory drctr) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java b/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java index 28085cee96ce6f56ca6d9e576ed7b0dbc2c04989..8523fa699f83ce4040ae20065ea69d8c5172bc39 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java @@ -21,12 +21,14 @@ import java.util.ArrayList; import java.util.Collection; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.VirtualDirectory; @@ -38,12 +40,20 @@ final class GetRootDirectoryVisitor extends GetFilesContentVisitor { @Override public Collection<AbstractFile> visit(VirtualDirectory ld) { - //case when we hit a layout directoryor local file container, not under a real FS + //case when we hit a layout directory or local file container, not under a real FS //or when root virt dir is scheduled Collection<AbstractFile> ret = new ArrayList<>(); ret.add(ld); return ret; } + + @Override + public Collection<AbstractFile> visit(LocalDirectory ld) { + //case when we hit a local directory + Collection<AbstractFile> ret = new ArrayList<>(); + ret.add(ld); + return ret; + } @Override public Collection<AbstractFile> visit(LayoutFile lf) { @@ -93,4 +103,8 @@ public Collection<AbstractFile> visit(SlackFile slackFile) { return getAllFromChildren(slackFile); } + @Override + public Collection<AbstractFile> visit(BlackboardArtifact art) { + return getAllFromChildren(art); + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java index 6d37ca2a26a479e0e03f34ad7e83c71be0e630c6..ff474230307a8b288d62fd909ebe7573d22e1e63 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,7 +39,7 @@ class AutoIngestCase implements Comparable<AutoIngestCase> { private final String caseName; private final Path metadataFilePath; private final Date createDate; - private Date lastModfiedDate; + private final Date lastAccessedDate; /** * Constructs a representation of case created by automated ingest. @@ -58,10 +58,10 @@ class AutoIngestCase implements Comparable<AutoIngestCase> { } if (null != fileAttrs) { createDate = new Date(fileAttrs.creationTime().toMillis()); - lastModfiedDate = new Date(fileAttrs.lastModifiedTime().toMillis()); + lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); } else { createDate = new Date(); - lastModfiedDate = new Date(); + lastAccessedDate = new Date(); } } @@ -94,19 +94,13 @@ Date getCreationDate() { } /** - * Gets the last accessed date for the case, defined as the last modified + * Gets the last accessed date for the case, defined as the last accessed * time of the case metadata file. * * @return The last accessed date. */ Date getLastAccessedDate() { - try { - BasicFileAttributes fileAttrs = Files.readAttributes(metadataFilePath, BasicFileAttributes.class); - lastModfiedDate = new Date(fileAttrs.lastModifiedTime().toMillis()); - } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, lastModfiedDate time not updated", caseDirectoryPath), ex); - } - return lastModfiedDate; + return this.lastAccessedDate; } /** @@ -162,7 +156,7 @@ public int hashCode() { */ @Override public int compareTo(AutoIngestCase other) { - return -this.lastModfiedDate.compareTo(other.getLastAccessedDate()); + return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form index 0c22854c9a257fcdb7260c5e90e2a975616c5b07..cb0f27580926db1724b41c06792d4fdb73ffa683 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form @@ -27,44 +27,53 @@ <EmptySpace max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" attributes="0"> - <EmptySpace min="-2" pref="13" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> <Component id="bnOpen" min="-2" pref="80" max="-2" attributes="0"/> - <EmptySpace type="separate" max="-2" attributes="0"/> - <Component id="bnRefresh" min="-2" max="-2" attributes="0"/> - <EmptySpace type="separate" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> <Component id="bnShowLog" min="-2" max="-2" attributes="0"/> <EmptySpace max="32767" attributes="0"/> - <Component id="panelFilter" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="20" max="-2" attributes="0"/> - </Group> - <Group type="102" attributes="0"> - <Component id="scrollPaneTable" pref="1007" max="32767" attributes="0"/> + <Component id="rbGroupLabel" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> + <Component id="rbDays" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="rbWeeks" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="rbMonths" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelFilter" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="bnRefresh" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> </Group> + <Component id="scrollPaneTable" pref="1007" max="32767" attributes="0"/> </Group> + <EmptySpace max="-2" attributes="0"/> </Group> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" attributes="0"> - <EmptySpace min="-2" pref="43" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="6" max="-2" attributes="0"/> <Component id="scrollPaneTable" min="-2" pref="450" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="32767" attributes="0"/> - <Group type="103" groupAlignment="1" attributes="0"> - <Group type="102" alignment="1" attributes="0"> - <Component id="panelFilter" min="-2" pref="130" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="bnOpen" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="bnShowLog" alignment="3" min="-2" max="-2" attributes="0"/> </Group> - <Group type="102" alignment="1" attributes="0"> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="bnOpen" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="bnRefresh" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="bnShowLog" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="bnRefresh" min="-2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="1" attributes="0"> + <Group type="103" alignment="1" groupAlignment="3" attributes="0"> + <Component id="rbDays" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="rbWeeks" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="rbMonths" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="rbGroupLabel" alignment="3" min="-2" max="-2" attributes="0"/> </Group> - <EmptySpace min="-2" pref="36" max="-2" attributes="0"/> + <Component id="panelFilter" min="-2" max="-2" attributes="0"/> </Group> </Group> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> </Group> </Group> </DimensionLayout> @@ -122,32 +131,16 @@ <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="rbGroupLabel" min="-2" max="-2" attributes="0"/> - <Component id="rbAllCases" alignment="0" min="-2" max="-2" attributes="0"/> - <Component id="rbMonths" alignment="0" min="-2" max="-2" attributes="0"/> - <Component id="rbWeeks" alignment="0" min="-2" max="-2" attributes="0"/> - <Component id="rbDays" alignment="0" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace pref="34" max="32767" attributes="0"/> + <Component id="rbAllCases" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="1" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="rbGroupLabel" min="-2" max="-2" attributes="0"/> - <EmptySpace max="32767" attributes="0"/> - <Component id="rbDays" min="-2" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="rbWeeks" min="-2" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="rbMonths" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> <Component id="rbAllCases" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> </Group> </Group> </DimensionLayout> @@ -167,56 +160,6 @@ <EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbAllCasesItemStateChanged"/> </Events> </Component> - <Component class="javax.swing.JRadioButton" name="rbMonths"> - <Properties> - <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> - <ComponentRef name="rbGroupHistoryLength"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestCasePanel.rbMonths.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - </Properties> - <Events> - <EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbMonthsItemStateChanged"/> - </Events> - </Component> - <Component class="javax.swing.JRadioButton" name="rbWeeks"> - <Properties> - <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> - <ComponentRef name="rbGroupHistoryLength"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestCasePanel.rbWeeks.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - </Properties> - <Events> - <EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbWeeksItemStateChanged"/> - </Events> - </Component> - <Component class="javax.swing.JRadioButton" name="rbDays"> - <Properties> - <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> - <ComponentRef name="rbGroupHistoryLength"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestCasePanel.rbDays.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="name" type="java.lang.String" value="" noResource="true"/> - </Properties> - <Events> - <EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbDaysItemStateChanged"/> - </Events> - </Component> - <Component class="javax.swing.JLabel" name="rbGroupLabel"> - <Properties> - <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> - <Font name="Tahoma" size="12" style="0"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestCasePanel.rbGroupLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - </Properties> - </Component> </SubComponents> </Container> <Component class="javax.swing.JButton" name="bnShowLog"> @@ -233,5 +176,55 @@ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnShowLogActionPerformed"/> </Events> </Component> + <Component class="javax.swing.JRadioButton" name="rbDays"> + <Properties> + <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> + <ComponentRef name="rbGroupHistoryLength"/> + </Property> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestCasePanel.rbDays.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + <Property name="name" type="java.lang.String" value="" noResource="true"/> + </Properties> + <Events> + <EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbDaysItemStateChanged"/> + </Events> + </Component> + <Component class="javax.swing.JRadioButton" name="rbWeeks"> + <Properties> + <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> + <ComponentRef name="rbGroupHistoryLength"/> + </Property> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestCasePanel.rbWeeks.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + <Events> + <EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbWeeksItemStateChanged"/> + </Events> + </Component> + <Component class="javax.swing.JRadioButton" name="rbMonths"> + <Properties> + <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> + <ComponentRef name="rbGroupHistoryLength"/> + </Property> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestCasePanel.rbMonths.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + <Events> + <EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbMonthsItemStateChanged"/> + </Events> + </Component> + <Component class="javax.swing.JLabel" name="rbGroupLabel"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="Tahoma" size="12" style="0"/> + </Property> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestCasePanel.rbGroupLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + </Component> </SubComponents> </Form> diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java index ea98faea18522168bf006641da32c09d7b007392..9b6b3ddefaad64f4d95a36efe152cfba7950073b 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java @@ -63,7 +63,7 @@ public final class AutoIngestCasePanel extends JPanel { private static final int STATUS_COL_MAX_WIDTH = 250; private static final int STATUS_COL_PREFERRED_WIDTH = 60; private static final int MILLIS_TO_WAIT_BEFORE_STARTING = 500; - private static final int MILLIS_TO_WAIT_BETWEEN_UPDATES = 30000; + private static final int MILLIS_TO_WAIT_BETWEEN_UPDATES = 300000; private ScheduledThreadPoolExecutor casesTableRefreshExecutor; /* @@ -105,6 +105,14 @@ public AutoIngestCasePanel(JDialog parent) { public boolean isCellEditable(int row, int column) { return false; } + @Override + public Class<?> getColumnClass(int col) { + if (this.getColumnName(col).equals(CREATEDTIME_HEADER) || this.getColumnName(col).equals(COMPLETEDTIME_HEADER)) { + return Date.class; + } else { + return super.getColumnClass(col); + } + } }; initComponents(); @@ -384,11 +392,11 @@ private void initComponents() { bnRefresh = new javax.swing.JButton(); panelFilter = new javax.swing.JPanel(); rbAllCases = new javax.swing.JRadioButton(); - rbMonths = new javax.swing.JRadioButton(); - rbWeeks = new javax.swing.JRadioButton(); + bnShowLog = new javax.swing.JButton(); rbDays = new javax.swing.JRadioButton(); + rbWeeks = new javax.swing.JRadioButton(); + rbMonths = new javax.swing.JRadioButton(); rbGroupLabel = new javax.swing.JLabel(); - bnShowLog = new javax.swing.JButton(); setName("Completed Cases"); // NOI18N @@ -428,62 +436,19 @@ public void itemStateChanged(java.awt.event.ItemEvent evt) { } }); - rbGroupHistoryLength.add(rbMonths); - org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbMonths.text")); // NOI18N - rbMonths.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbMonthsItemStateChanged(evt); - } - }); - - rbGroupHistoryLength.add(rbWeeks); - org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbWeeks.text")); // NOI18N - rbWeeks.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbWeeksItemStateChanged(evt); - } - }); - - rbGroupHistoryLength.add(rbDays); - org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbDays.text")); // NOI18N - rbDays.setName(""); // NOI18N - rbDays.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbDaysItemStateChanged(evt); - } - }); - - rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbGroupLabel.text")); // NOI18N - javax.swing.GroupLayout panelFilterLayout = new javax.swing.GroupLayout(panelFilter); panelFilter.setLayout(panelFilterLayout); panelFilterLayout.setHorizontalGroup( panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(panelFilterLayout.createSequentialGroup() - .addContainerGap() - .addGroup(panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(rbGroupLabel) - .addComponent(rbAllCases) - .addComponent(rbMonths) - .addComponent(rbWeeks) - .addComponent(rbDays)) - .addContainerGap(34, Short.MAX_VALUE)) + .addComponent(rbAllCases) + .addGap(0, 0, Short.MAX_VALUE)) ); panelFilterLayout.setVerticalGroup( panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelFilterLayout.createSequentialGroup() - .addContainerGap() - .addComponent(rbGroupLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(rbDays) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(rbWeeks) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(rbMonths) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rbAllCases) - .addContainerGap()) + .addGap(0, 0, 0) + .addComponent(rbAllCases)) ); org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.text")); // NOI18N @@ -495,6 +460,34 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { } }); + rbGroupHistoryLength.add(rbDays); + org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbDays.text")); // NOI18N + rbDays.setName(""); // NOI18N + rbDays.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + rbDaysItemStateChanged(evt); + } + }); + + rbGroupHistoryLength.add(rbWeeks); + org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbWeeks.text")); // NOI18N + rbWeeks.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + rbWeeksItemStateChanged(evt); + } + }); + + rbGroupHistoryLength.add(rbMonths); + org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbMonths.text")); // NOI18N + rbMonths.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + rbMonthsItemStateChanged(evt); + } + }); + + rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbGroupLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -503,35 +496,45 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(13, 13, 13) + .addGap(4, 4, 4) .addComponent(bnOpen, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(bnRefresh) - .addGap(18, 18, 18) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(bnShowLog) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(rbGroupLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rbDays) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rbWeeks) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rbMonths) + .addGap(0, 0, 0) .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(20, 20, 20)) - .addGroup(layout.createSequentialGroup() - .addComponent(scrollPaneTable, javax.swing.GroupLayout.DEFAULT_SIZE, 1007, Short.MAX_VALUE) - .addContainerGap()))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnRefresh) + .addGap(4, 4, 4)) + .addComponent(scrollPaneTable, javax.swing.GroupLayout.DEFAULT_SIZE, 1007, Short.MAX_VALUE)) + .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(43, 43, 43) + .addGap(6, 6, 6) .addComponent(scrollPaneTable, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) - .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnOpen) + .addComponent(bnShowLog)) + .addComponent(bnRefresh) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnOpen) - .addComponent(bnRefresh) - .addComponent(bnShowLog)) - .addGap(36, 36, 36)))) + .addComponent(rbDays) + .addComponent(rbWeeks) + .addComponent(rbMonths) + .addComponent(rbGroupLabel)) + .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, 0)) ); }// </editor-fold>//GEN-END:initComponents diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index 5b755dfb011ebb1d4fe55dc8107020ca07c0b7d6..7e04d4c8e4192646a71df92299c94cc42e8b4d5e 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -1,4 +1,11 @@ CTL_OpenAction=Open Case... +AutoIngestDashboard.bnRefresh.text=&Refresh +AutoIngestDashboard.lbCompleted.text=Completed Jobs +AutoIngestDashboard.lbRunning.text=Running Jobs +AutoIngestDashboard.lbPending.text=Pending Jobs +AutoIngestDashboard.bnCancelModule.text=Cancel &Module +AutoIngestDashboard.bnExit.text=&Exit +AutoIngestDashboard.bnOptions.text=&Options AutoIngestDashboard.JobsTableModel.ColumnHeader.Case=Case AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder=Data Source AutoIngestDashboard.JobsTableModel.ColumnHeader.HostName=Host Name @@ -8,12 +15,23 @@ AutoIngestDashboard.JobsTableModel.ColumnHeader.CompletedTime=Job Completed AutoIngestDashboard.JobsTableModel.ColumnHeader.Stage=Stage AutoIngestDashboard.JobsTableModel.ColumnHeader.Status=Status AutoIngestDashboard.JobsTableModel.ColumnHeader.ManifestFilePath= Manifest File Path +AutoIngestDashboard.bnShowProgress.text=Ingest Progress AutoIngestDashboard.bnResume.text=Resume +AutoIngestDashboard.bnPause.text=Pause AutoIngestDashboard.bnPause.confirmHeader=Are you sure you want to pause? AutoIngestDashboard.bnPause.warningText=Pause will occur after the current job completes processing. This could take a long time. Continue? +AutoIngestDashboard.bnPause.toolTipText=Suspend processing of Pending Jobs AutoIngestDashboard.bnPause.toolTipTextResume=Resume processing of Pending Jobs AutoIngestDashboard.bnPause.pausing=Pausing after current job completes... +AutoIngestDashboard.bnRefresh.toolTipText=Refresh displayed tables +AutoIngestDashboard.bnShowProgress.toolTipText=Show the progress of the currently running Job. This functionality is only available for jobs running on current AIM node. +AutoIngestDashboard.bnCancelModule.toolTipText=Cancel processing of the current module within the Job and move on to the next module within the Job. This functionality is only available for jobs running on current AIM node. +AutoIngestDashboard.bnExit.toolTipText=Exit Application AutoIngestDashboard.Cancelling=Cancelling... +AutoIngestDashboard.bnOptions.toolTipText=Display options panel. All processing must be paused to open the options panel. +AutoIngestDashboard.pendingTable.toolTipText=The Pending table displays the order upcoming Jobs will be processed with the top of the list first +AutoIngestDashboard.runningTable.toolTipText=The Running table displays the currently running Job and information about it +AutoIngestDashboard.completedTable.toolTipText=The Completed table shows all Jobs that have been processed already AutoIngestDashboard.JobsTableModel.ColumnHeader.StageTime=Time in Stage AutoIngestDashboard.JobsTableModel.ColumnHeader.CaseFolder=Case Folder AutoIngestDashboard.JobsTableModel.ColumnHeader.LocalJob= Local Job? @@ -145,12 +163,20 @@ CopyFilesPanel.ConfirmCopyAdd=exists. Do you really want to copy more files to t CopyFilesPanel.ConfirmCopyYes=Copy CopyFilesPanel.ConfirmCopyNo=Do not copy ConfirmationDialog.ConfirmUnlockHeader=Confirm Case Unlock +AutoIngestDashboard.bnPrioritizeCase.toolTipText=Move all images associated with a case to top of Pending queue. +AutoIngestDashboard.bnPrioritizeCase.text=Prioriti&ze Case +AutoIngestDashboard.bnShowCaseLog.toolTipText=Display case log file for selected case +AutoIngestDashboard.bnShowCaseLog.text=Show Case &Log CopyFilesPanel.bnCancelPendingJob.text=Ca&ncel CopyFilesPanel.tbDestinationCase.text= CopyFilesPanel.cbThrottleNetwork.text=&Throttle Network CopyFilesPanel.cbThrottleNetwork.toolTipText=<html>Select this box if a low-bandwidth network connection is involved in this copy job.<br>\nSelecting this box will artificially limit the transfer speed by inserting strategic delays.<br>\nThis helps copy files across low-bandwidth networks where the transfer would<br>\notherwise fail. Only select this if you are having problems copying across the network.</html> CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.bnShowCurrentLog.text=Show &Log +AutoIngestDashboard.bnCancelJob.toolTipText=Cancel processing of the current Job and move on to the next Job. This functionality is only available for jobs running on current AIM node. +AutoIngestDashboard.bnCancelJob.text=&Cancel Job +AutoIngestDashboard.bnDeleteCase.toolTipText=Delete the selected Case in its entirety +AutoIngestDashboard.bnDeleteCase.text=&Delete Case CopyFilesPanel.lbCaseName.text=Case Name CaseStatusIconCellRenderer.tooltiptext.ok=Images processed successfully CaseStatusIconCellRenderer.tooltiptext.warning=An error occurred or processing was canceled for at least one image - please check the log @@ -173,6 +199,7 @@ CaseImportPanel.Error=Error CaseImportPanel.Complete=Complete CaseImportPanel.Blank= CaseImportPanel.DeleteWarning=Make sure no important files are in the case source directory +AutoIngestDashboard.lbStatus.text=Status: SingleUserCaseImporter.NonUniqueOutputFolder=Output folder not unique. Skipping SingleUserCaseImporter.WillImport=Will import: SingleUserCaseImporter.None=None @@ -195,6 +222,9 @@ ReviewModeCasePanel.StatusIconHeaderText=Status ReviewModeCasePanel.OutputFolderHeaderText=Output Folder ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time CopyFilesPanel.bnOptions.text=&Options +AutoIngestDashboard.lbServicesStatus.text=Services Status: +AutoIngestDashboard.tbServicesStatusMessage.text= +AutoIngestDashboard.tbStatusMessage.text= FileExporterSettingsPanel.ChooseRootDirectory=Choose a root directory for file output FileExporterSettingsPanel.ChooseReportDirectory=Choose a report directory FileExporterSettingsPanel.RuleName=Rule Name @@ -253,7 +283,12 @@ FileExporterSettingsPanel.BrowseReportTooltip_1=Browse for the Reports Folder FileExporterSettingsPanel.NewRuleTooltip_1=Clear the rule editor to begin a new rule FileExporterSettingsPanel.DeleteTooltip_1=Delete the selected rule FileExporterSettingsPanel.SaveTooltip_1=Save the current rule +AutoIngestDashboard.bnOpenLogDir.text=Open System Logs Directory +AutoIngestDashboard.bnPrioritizeJob.text=Prioritize Job +AutoIngestDashboard.bnPrioritizeJob.toolTipText=Move this folder to the top of the Pending queue. +AutoIngestDashboard.bnReprocessJob.text=Reprocess Job AutoIngestDashboard.bnPrioritizeFolder.label=<AutoIngestDashboard.bnPrioritizeJob.text> +AutoIngestDashboard.bnPrioritizeJob.actionCommand=<AutoIngestDashboard.bnPrioritizeJob.text> AutoIngestCasePanel.rbDays.text=Days AutoIngestCasePanel.rbWeeks.text=Weeks AutoIngestCasePanel.rbMonths.text=Months @@ -262,74 +297,4 @@ AutoIngestCasePanel.bnRefresh.text=&Refresh AutoIngestCasePanel.bnOpen.text=&Open AutoIngestCasePanel.bnShowLog.toolTipText=Display case log file for selected case AutoIngestCasePanel.bnShowLog.text=&Show Log -AutoIngestCasePanel.rbGroupLabel.text=Show Last 10: -AutoIngestLegacyDashboard.tbStatusMessage.text= -AutoIngestLegacyDashboard.bnShowCaseLog.toolTipText=Display case log file for selected case -AutoIngestLegacyDashboard.bnShowCaseLog.text=Show Case &Log -AutoIngestLegacyDashboard.bnDeleteCase.toolTipText=Delete the selected Case in its entirety -AutoIngestLegacyDashboard.bnDeleteCase.text=&Delete Case -AutoIngestLegacyDashboard.bnCancelJob.toolTipText=Cancel processing of the current Job and move on to the next Job. This functionality is only available for jobs running on current AIM node. -AutoIngestLegacyDashboard.bnCancelJob.text=&Cancel Job -AutoIngestLegacyDashboard.completedTable.toolTipText=The Completed table shows all Jobs that have been processed already -AutoIngestLegacyDashboard.runningTable.toolTipText=The Running table displays the currently running Job and information about it -AutoIngestLegacyDashboard.pendingTable.toolTipText=The Pending table displays the order upcoming Jobs will be processed with the top of the list first -AutoIngestLegacyDashboard.bnPrioritizeCase.toolTipText=Move all images associated with a case to top of Pending queue. -AutoIngestLegacyDashboard.bnPrioritizeCase.text=Prioriti&ze Case -AutoIngestLegacyDashboard.bnPause.toolTipText=Suspend processing of Pending Jobs -AutoIngestLegacyDashboard.bnPause.text=Pause -AutoIngestLegacyDashboard.bnShowProgress.toolTipText=Show the progress of the currently running Job. This functionality is only available for jobs running on current AIM node. -AutoIngestLegacyDashboard.bnShowProgress.text=Ingest Progress -AutoIngestLegacyDashboard.bnOptions.toolTipText=Display options panel. All processing must be paused to open the options panel. -AutoIngestLegacyDashboard.bnOptions.text=&Options -AutoIngestLegacyDashboard.bnExit.toolTipText=Exit Application -AutoIngestLegacyDashboard.bnExit.text=&Exit -AutoIngestLegacyDashboard.bnCancelModule.toolTipText=Cancel processing of the current module within the Job and move on to the next module within the Job. This functionality is only available for jobs running on current AIM node. -AutoIngestLegacyDashboard.bnCancelModule.text=Cancel &Module -AutoIngestLegacyDashboard.bnRefresh.toolTipText=Refresh displayed tables -AutoIngestLegacyDashboard.bnRefresh.text=&Refresh -AutoIngestLegacyDashboard.lbCompleted.text=Completed Jobs -AutoIngestLegacyDashboard.lbRunning.text=Running Jobs -AutoIngestLegacyDashboard.lbPending.text=Pending Jobs -AutoIngestLegacyDashboard.bnReprocessJob.text=Reprocess Job -AutoIngestLegacyDashboard.bnOpenLogDir.text=Open System Logs Directory -AutoIngestLegacyDashboard.tbServicesStatusMessage.text= -AutoIngestLegacyDashboard.lbServicesStatus.text=Services Status: -AutoIngestLegacyDashboard.bnPrioritizeJob.actionCommand=<AutoIngestDashboard.bnPrioritizeJob.text> -AutoIngestLegacyDashboard.bnPrioritizeJob.toolTipText=Move this folder to the top of the Pending queue. -AutoIngestLegacyDashboard.bnPrioritizeJob.text=Prioritize Job -AutoIngestLegacyDashboard.lbStatus.text=Status: -AutoIngestDashboard.bnRefresh.text=&Refresh -AutoIngestDashboard.lbCompleted.text=Completed Jobs -AutoIngestDashboard.lbRunning.text=Running Jobs -AutoIngestDashboard.lbPending.text=Pending Jobs -AutoIngestDashboard.bnDeleteCase.toolTipText=Delete the selected Case in its entirety -AutoIngestDashboard.bnDeleteCase.text=&Delete Case -AutoIngestDashboard.bnCancelJob.toolTipText=Cancel processing of the current Job and move on to the next Job. This functionality is only available for jobs running on current AIM node. -AutoIngestDashboard.bnCancelJob.text=&Cancel Job -AutoIngestDashboard.completedTable.toolTipText=The Completed table shows all Jobs that have been processed already -AutoIngestDashboard.bnReprocessJob.text=Reprocess Job -AutoIngestDashboard.bnOpenLogDir.text=Open System Logs Directory -AutoIngestDashboard.runningTable.toolTipText=The Running table displays the currently running Job and information about it -AutoIngestDashboard.tbServicesStatusMessage.text= -AutoIngestDashboard.pendingTable.toolTipText=The Pending table displays the order upcoming Jobs will be processed with the top of the list first -AutoIngestDashboard.lbServicesStatus.text=Services Status: -AutoIngestDashboard.bnPrioritizeJob.actionCommand=<AutoIngestDashboard.bnPrioritizeJob.text> -AutoIngestDashboard.bnPrioritizeJob.toolTipText=Move this folder to the top of the Pending queue. -AutoIngestDashboard.bnPrioritizeJob.text=Prioritize Job -AutoIngestDashboard.lbStatus.text=Status: -AutoIngestDashboard.tbStatusMessage.text= -AutoIngestDashboard.bnShowCaseLog.toolTipText=Display case log file for selected case -AutoIngestDashboard.bnShowCaseLog.text=Show Case &Log -AutoIngestDashboard.bnPrioritizeCase.toolTipText_1=Move all images associated with a case to top of Pending queue. -AutoIngestDashboard.bnPrioritizeCase.text_1=Prioriti&ze Case -AutoIngestDashboard.bnPause.toolTipText=Suspend processing of Pending Jobs -AutoIngestDashboard.bnPause.text=Pause -AutoIngestDashboard.bnShowProgress.toolTipText=Show the progress of the currently running Job. This functionality is only available for jobs running on current AIM node. -AutoIngestDashboard.bnShowProgress.text=Ingest Progress -AutoIngestDashboard.bnOptions.toolTipText=Display options panel. All processing must be paused to open the options panel. -AutoIngestDashboard.bnOptions.text=&Options -AutoIngestDashboard.bnExit.toolTipText=Exit Application -AutoIngestDashboard.bnExit.text=&Exit -AutoIngestDashboard.bnCancelModule.toolTipText=Cancel processing of the current module within the Job and move on to the next module within the Job. This functionality is only available for jobs running on current AIM node. -AutoIngestDashboard.bnCancelModule.text=Cancel &Module -AutoIngestDashboard.bnRefresh.toolTipText=Refresh displayed tables +AutoIngestCasePanel.rbGroupLabel.text=Show cases accessed in the last 10: \ No newline at end of file diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java index 0ec43d4b3eab6d4308ab854f0410767a62a2764f..f8e4d2791f22e2e28075bd5c21ad0c51a5aa75b9 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java @@ -35,6 +35,7 @@ import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.LayoutFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.LocalFile; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.SleuthkitItemVisitor; @@ -206,7 +207,6 @@ private void indexChunk(String chunk, String sourceName, Map<String, String> fie // but does this really mean we don't want to index it? //skip the file, image id unknown - //JMTODO: does this need to ne internationalized? String msg = NbBundle.getMessage(Ingester.class, "Ingester.ingest.exception.unknownImgId.msg", sourceName); //JMTODO: does this need to ne internationalized? logger.log(Level.SEVERE, msg); @@ -273,6 +273,11 @@ public Map<String, String> visit(Directory d) { return getCommonAndMACTimeFields(d); } + @Override + public Map<String, String> visit(LocalDirectory ld){ + return getCommonAndMACTimeFields(ld); + } + @Override public Map<String, String> visit(LayoutFile lf) { // layout files do not have times diff --git a/nbproject/project.properties b/nbproject/project.properties index 03d618afe67b9cb72bc2b772e0c9b5dd8338ffd1..8df7ff47a0eaaef8387722ecfa784a43575068bb 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -10,7 +10,6 @@ app.version=4.4.1 build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress -project.org.sleuthkit.autopsy.centralrepository=CentralRepository project.org.sleuthkit.autopsy.experimental=Experimental project.org.sleuthkit.autopsy.imagegallery=ImageGallery update_versions=false @@ -32,8 +31,7 @@ modules=\ ${project.org.sleuthkit.autopsy.core}:\ ${project.org.sleuthkit.autopsy.corelibs}:\ ${project.org.sleuthkit.autopsy.imagegallery}:\ - ${project.org.sleuthkit.autopsy.experimental}:\ - ${project.org.sleuthkit.autopsy.centralrepository} + ${project.org.sleuthkit.autopsy.experimental} project.org.sleuthkit.autopsy.core=Core project.org.sleuthkit.autopsy.corelibs=CoreLibs project.org.sleuthkit.autopsy.keywordsearch=KeywordSearch diff --git a/test/script/config.xml b/test/script/config.xml index 6762cdd5ce7b311d8751c5abbb5457ff5c7413dd..89dfa9790deec09adf40efb6ff4d621785a5b769 100644 --- a/test/script/config.xml +++ b/test/script/config.xml @@ -6,12 +6,25 @@ List of tags: image: An image to be ingested build: the path to the build.xml file indir: the path to input directory -outdir: the path to output directory +singleUser_outdir: the path to single-user case output directory global_csv: path to global csv file -golddir: the path to gold directory +singleUser_golddir: the path to single-user case gold directory timing: can be set to True or False. If enabled, record the timing. - -NOTE: Make sure to use windows style for paths! +userCaseType: set this value to do single-user, multi-user or both tests + +List of tags for multi-user case: +multiUser_outdir: a path to multi-user case output directory +multiUser_golddir: a path to multi-user case gold directory +dbHost: PostgreSQL database host name +dbPort: PostgreSQL database port number +dbUserName: PostgreSQL database username +dbPassword: PostgreSQL database password +solrHost: Solr server host name +solrPort: Solr server port number +messageServiceHost: ActiveMQ server hostname +messageServicePort: ActiveMQ server port number + +NOTE: Make sure to use UNC path for mutliUser_outdir, use windows style for other paths! None of these tags are mandatory, and if nothing is provided the file will be looked over and ignored. diff --git a/test/script/tskdbdiff.py b/test/script/tskdbdiff.py index f55fc0a95d772c51adcbc72767bb2f17ced4f7fc..4f3518f5655d5dbdb941402c3841330662d9c09a 100755 --- a/test/script/tskdbdiff.py +++ b/test/script/tskdbdiff.py @@ -300,11 +300,14 @@ def _dump_output_db_nonbb(db_file, dump_file): os.chmod (backup_db_file, 0o777) conn = sqlite3.connect(backup_db_file) - id_path_table = build_id_table(conn.cursor()) + id_files_table = build_id_files_table(conn.cursor()) id_vs_parts_table = build_id_vs_parts_table(conn.cursor()) id_vs_info_table = build_id_vs_info_table(conn.cursor()) id_fs_info_table = build_id_fs_info_table(conn.cursor()) id_objects_table = build_id_objects_table(conn.cursor()) + id_artifact_types_table = build_id_artifact_types_table(conn.cursor()) + id_obj_path_table = build_id_obj_path_table(id_files_table, id_objects_table, id_artifact_types_table) + conn.text_factory = lambda x: x.decode("utf-8", "ignore") # Delete the blackboard tables @@ -314,7 +317,7 @@ def _dump_output_db_nonbb(db_file, dump_file): # Write to the database dump with codecs.open(dump_file, "wb", "utf_8") as db_log: for line in conn.iterdump(): - line = normalize_db_entry(line, id_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_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) db_log.write('%s\n' % line) # Now sort the file @@ -346,12 +349,12 @@ def _get_tmp_file(base, ext): class TskDbDiffException(Exception): pass -def normalize_db_entry(line, table, vs_parts_table, vs_info_table, fs_info_table, objects_table): +def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info_table, objects_table): """ Make testing more consistent and reasonable by doctoring certain db entries. Args: line: a String, the line to remove the object id from. - table: a map from object ids to file paths. + files_table: a map from object ids to file paths. """ files_index = line.find('INSERT INTO "tsk_files"') @@ -361,31 +364,35 @@ def normalize_db_entry(line, table, vs_parts_table, vs_info_table, fs_info_table layout_index = line.find('INSERT INTO "tsk_file_layout"') data_source_info_index = line.find('INSERT INTO "data_source_info"') ingest_job_index = line.find('INSERT INTO "ingest_jobs"') + parens = line[line.find('(') + 1 : line.rfind(')')] fields_list = parens.replace(" ", "").split(',') # remove object ID if (files_index != -1): obj_id = fields_list[0] - path = table[int(obj_id)] + path = files_table[int(obj_id)] newLine = ('INSERT INTO "tsk_files" VALUES(' + ', '.join(fields_list[1:]) + ');') return newLine # remove object ID elif (path_index != -1): - obj_id = fields_list[0] - objValue = table[int(obj_id)] - par_obj_id = objects_table[int(obj_id)] - par_obj_value = table[par_obj_id] - par_obj_name = par_obj_value[par_obj_value.rfind('/')+1:] - #check the par_id that we insert to the path name when we create uniqueName - pathValue = re.sub(par_obj_name + '_' + str(par_obj_id), par_obj_name, fields_list[1]) - + obj_id = int(fields_list[0]) + objValue = files_table[obj_id] + # remove the obj_id from ModuleOutput/EmbeddedFileExtractor directory + idx_pre = fields_list[1].find('EmbeddedFileExtractor') + len('EmbeddedFileExtractor') + if idx_pre > -1: + idx_pos = fields_list[1].find('\\', idx_pre + 2) + dir_to_replace = fields_list[1][idx_pre + 1 : idx_pos] # +1 to skip the file seperator + dir_to_replace = dir_to_replace[0:dir_to_replace.rfind('_')] + pathValue = fields_list[1][:idx_pre+1] + dir_to_replace + fields_list[1][idx_pos:] + else: + pathValue = fields_list[1] newLine = ('INSERT INTO "tsk_files_path" VALUES(' + objValue + ', ' + pathValue + ', ' + ', '.join(fields_list[2:]) + ');') return newLine # remove object ID elif (layout_index != -1): obj_id = fields_list[0] - path= table[int(obj_id)] + path= files_table[int(obj_id)] newLine = ('INSERT INTO "tsk_file_layout" VALUES(' + path + ', ' + ', '.join(fields_list[1:]) + ');') return newLine # remove object ID @@ -403,29 +410,29 @@ def normalize_db_entry(line, table, vs_parts_table, vs_info_table, fs_info_table except Exception as e: return line - if obj_id in table.keys(): - path = table[obj_id] + if obj_id in files_table.keys(): + path = files_table[obj_id] elif obj_id in vs_parts_table.keys(): - path = vs_parts_table[obj_id] + path = vs_parts_table[obj_id] elif obj_id in vs_info_table.keys(): - path = vs_info_table[obj_id] + path = vs_info_table[obj_id] elif obj_id in fs_info_table.keys(): - path = fs_info_table[obj_id] + path = fs_info_table[obj_id] - if parent_id in table.keys(): - parent_path = table[parent_id] + if parent_id in files_table.keys(): + parent_path = files_table[parent_id] elif parent_id in vs_parts_table.keys(): - parent_path = vs_parts_table[parent_id] + parent_path = vs_parts_table[parent_id] elif parent_id in vs_info_table.keys(): - parent_path = vs_info_table[parent_id] + parent_path = vs_info_table[parent_id] elif parent_id in fs_info_table.keys(): - parent_path = fs_info_table[parent_id] + parent_path = fs_info_table[parent_id] if path and parent_path: - return newLine + path + ', ' + parent_path + ', ' + ', '.join(fields_list[2:]) + ');' + return newLine + path + ', ' + parent_path + ', ' + ', '.join(fields_list[2:]) + ');' else: - return line + return line # remove time-based information, ie Test_6/11/14 -> Test elif (report_index != -1): fields_list[1] = "AutopsyTestCase" @@ -467,60 +474,95 @@ def getAssociatedArtifactType(db_file, artifact_id): return "File path: " + info[0] + " Artifact Type: " + info[1] -def build_id_table(artifact_cursor): +def build_id_files_table(db_cursor): """Build the map of object ids to file paths. Args: - artifact_cursor: the database cursor + db_cursor: the database cursor """ # for each row in the db, take the object id, parent path, and name, then create a tuple in the dictionary # with the object id as the key and the full file path (parent + name) as the value - mapping = dict([(row[0], str(row[1]) + str(row[2])) for row in artifact_cursor.execute("SELECT obj_id, parent_path, name FROM tsk_files")]) + mapping = dict([(row[0], str(row[1]) + str(row[2])) for row in db_cursor.execute("SELECT obj_id, parent_path, name FROM tsk_files")]) return mapping -def build_id_vs_parts_table(artifact_cursor): +def build_id_vs_parts_table(db_cursor): """Build the map of object ids to vs_parts. Args: - artifact_cursor: the database cursor + db_cursor: the database cursor """ # for each row in the db, take the object id, addr, and start, then create a tuple in the dictionary # with the object id as the key and (addr + start) as the value - mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in artifact_cursor.execute("SELECT obj_id, addr, start FROM tsk_vs_parts")]) + mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in db_cursor.execute("SELECT obj_id, addr, start FROM tsk_vs_parts")]) return mapping -def build_id_vs_info_table(artifact_cursor): +def build_id_vs_info_table(db_cursor): """Build the map of object ids to vs_info. Args: - artifact_cursor: the database cursor + db_cursor: the database cursor """ # for each row in the db, take the object id, vs_type, and img_offset, then create a tuple in the dictionary # with the object id as the key and (vs_type + img_offset) as the value - mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in artifact_cursor.execute("SELECT obj_id, vs_type, img_offset FROM tsk_vs_info")]) + mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in db_cursor.execute("SELECT obj_id, vs_type, img_offset FROM tsk_vs_info")]) return mapping -def build_id_fs_info_table(artifact_cursor): +def build_id_fs_info_table(db_cursor): """Build the map of object ids to fs_info. Args: - artifact_cursor: the database cursor + db_cursor: the database cursor """ # for each row in the db, take the object id, img_offset, and fs_type, then create a tuple in the dictionary # with the object id as the key and (img_offset + fs_type) as the value - mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in artifact_cursor.execute("SELECT obj_id, img_offset, fs_type FROM tsk_fs_info")]) + mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in db_cursor.execute("SELECT obj_id, img_offset, fs_type FROM tsk_fs_info")]) return mapping -def build_id_objects_table(artifact_cursor): +def build_id_objects_table(db_cursor): """Build the map of object ids to par_id. Args: - artifact_cursor: the database cursor + db_cursor: the database cursor """ # for each row in the db, take the object id, par_obj_id, then create a tuple in the dictionary - # with the object id as the key and par_obj_id as the value - mapping = dict([(row[0], row[1]) for row in artifact_cursor.execute("SELECT obj_id, par_obj_id FROM tsk_objects")]) + # with the object id as the key and par_obj_id, type as the value + mapping = dict([(row[0], [row[1], row[2]]) for row in db_cursor.execute("SELECT * FROM tsk_objects")]) + return mapping + +def build_id_artifact_types_table(db_cursor): + """Build the map of object ids to artifact ids. + + Args: + db_cursor: the database cursor + """ + # for each row in the db, take the object id, par_obj_id, then create a tuple in the dictionary + # with the object id as the key and artifact type as the value + mapping = dict([(row[0], row[1]) for row in db_cursor.execute("SELECT blackboard_artifacts.artifact_obj_id, blackboard_artifact_types.type_name FROM blackboard_artifacts INNER JOIN blackboard_artifact_types ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id ")]) + return mapping + + +def build_id_obj_path_table(files_table, objects_table, artifacts_table): + """Build the map of object ids to artifact ids. + + Args: + files_table: obj_id, path + objects_table: obj_id, par_obj_id, type + artifacts_table: obj_id, artifact_type_name + """ + # make a copy of files_table and updated it with new data from artifats_table + mapping = files_table.copy() + for k, v in objects_table.items(): + if k not in mapping.keys(): # If the mapping table doesn't have data for obj_id(k), we use it's par_obj_id's path+name plus it's artifact_type name as path + if k in artifacts_table.keys(): + par_obj_id = v[0] + path = mapping[par_obj_id] + mapping[k] = path + "/" + artifacts_table[k] + elif v[0] not in mapping.keys(): + if v[0] in artifacts_table.keys(): + par_obj_id = objects_table[v[0]] + path = mapping[par_obj_id] + mapping[k] = path + "/" + artifacts_table[v[0]] return mapping def main(): diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java index 8c0750bbcd59fb6c6755ebfae47f1af25033ea82..3b7d70d929b74da75a36a01ef8d85c2369021971 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java @@ -295,11 +295,15 @@ public static String getRelModuleOutputPath() { */ private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) { List<AbstractFile> derivedFiles = new ArrayList<>(); + + + for (EmailMessage email : emails) { - if (email.hasAttachment()) { - derivedFiles.addAll(handleAttachments(email.getAttachments(), abstractFile)); + BlackboardArtifact msgArtifact = addArtifact(email, abstractFile); + + if ((msgArtifact != null) && (email.hasAttachment())) { + derivedFiles.addAll(handleAttachments(email.getAttachments(), abstractFile, msgArtifact )); } - addArtifact(email, abstractFile); } if (derivedFiles.isEmpty() == false) { @@ -320,7 +324,7 @@ private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) * * @return */ - private List<AbstractFile> handleAttachments(List<EmailMessage.Attachment> attachments, AbstractFile abstractFile) { + private List<AbstractFile> handleAttachments(List<EmailMessage.Attachment> attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact) { List<AbstractFile> files = new ArrayList<>(); for (EmailMessage.Attachment attach : attachments) { String filename = attach.getName(); @@ -334,7 +338,7 @@ private List<AbstractFile> handleAttachments(List<EmailMessage.Attachment> attac try { DerivedFile df = fileManager.addDerivedFile(filename, relPath, - size, cTime, crTime, aTime, mTime, true, abstractFile, "", + size, cTime, crTime, aTime, mTime, true, messageArtifact, "", EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleVersion(), "", encodingType); files.add(df); } catch (TskCoreException ex) { @@ -356,7 +360,8 @@ private List<AbstractFile> handleAttachments(List<EmailMessage.Attachment> attac * @param abstractFile */ @Messages({"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."}) - private void addArtifact(EmailMessage email, AbstractFile abstractFile) { + private BlackboardArtifact addArtifact(EmailMessage email, AbstractFile abstractFile) { + BlackboardArtifact bbart = null; List<BlackboardAttribute> bbattributes = new ArrayList<>(); String to = email.getRecipients(); String cc = email.getCc(); @@ -414,12 +419,9 @@ private void addArtifact(EmailMessage email, AbstractFile abstractFile) { if (rtf.isEmpty() == false) { bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, EmailParserModuleFactory.getModuleName(), rtf)); } - - - try { - BlackboardArtifact bbart; + bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); bbart.addAttributes(bbattributes); @@ -433,6 +435,8 @@ private void addArtifact(EmailMessage email, AbstractFile abstractFile) { } catch (TskCoreException ex) { logger.log(Level.WARNING, null, ex); } + + return bbart; } void postErrorMessage(String subj, String details) {