Merge branch 'timeline-event-mgr-develop' into upstream_timeline-event-mgr

This commit is contained in:
millmanorama 2018-07-19 12:52:51 +02:00
commit 1ba8bd30c5
451 changed files with 12110 additions and 3671 deletions

View File

@ -21,11 +21,6 @@
</target> </target>
<target name="get-thirdparty-dependencies" description="get third-party dependencies"> <target name="get-thirdparty-dependencies" description="get third-party dependencies">
<!--Copy openCV dependencies to release-->
<copy todir="${modules.dir}" >
<fileset dir="${thirdparty.dir}/opencv" />
</copy>
<!--Copy photorec to release--> <!--Copy photorec to release-->
<copy todir="${basedir}/release/photorec_exec" > <copy todir="${basedir}/release/photorec_exec" >
<fileset dir="${thirdparty.dir}/photorec_exec"/> <fileset dir="${thirdparty.dir}/photorec_exec"/>
@ -83,6 +78,8 @@
tofile="${ext.dir}/mchange-commons-java-0.2.9.jar"/> tofile="${ext.dir}/mchange-commons-java-0.2.9.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/c3p0-0.9.5.jar" <copy file="${env.TSK_HOME}/bindings/java/lib/c3p0-0.9.5.jar"
tofile="${ext.dir}/c3p0-0.9.5.jar"/> tofile="${ext.dir}/c3p0-0.9.5.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/SparseBitSet-1.1.jar"
tofile="${ext.dir}/SparseBitSet-1.1.jar"/>
</target> </target>
<target name="download-binlist"> <target name="download-binlist">
@ -94,13 +91,17 @@
<target name="getTestDataFiles"> <target name="getTestDataFiles">
<mkdir dir="${basedir}/test/qa-functional/data"/> <mkdir dir="${basedir}/test/qa-functional/data"/>
<get src="https://drive.google.com/uc?id=1dLYGctuvRQMmnzfXPppTM_9gB49eLc_g" dest="${test-input}/embedded.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1dLYGctuvRQMmnzfXPppTM_9gB49eLc_g" dest="${test-input}/EmbeddedIM_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1JACMDyH4y54ypGzFWl82ZzMQf3qbrioP" dest="${test-input}/encryption_detection_bitlocker_test.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1JACMDyH4y54ypGzFWl82ZzMQf3qbrioP" dest="${test-input}/BitlockerDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=17sGybvmBGsWWJYo1IWKmO04oG9hKpPi3" dest="${test-input}/encryption_detection_sqlcipher_test.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=17sGybvmBGsWWJYo1IWKmO04oG9hKpPi3" dest="${test-input}/SqlCipherDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=0BxdBkzm5VKGNT0dGY0dqcHVsU3M" dest="${test-input}/filter_test1.img" skipexisting="true"/> <get src="https://drive.google.com/uc?id=0BxdBkzm5VKGNT0dGY0dqcHVsU3M" dest="${test-input}/IngestFilters_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1bghoSm7z7nhmGIxlllyY1MMlbLntxm7n" dest="${test-input}/local_files_test.zip" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1bghoSm7z7nhmGIxlllyY1MMlbLntxm7n" dest="${test-input}/IngestFilters_local1_v1.zip" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1BrSiUQ1fzxFS9vIaK4mYKX6qIVp9kRWT" dest="${test-input}/password_detection_test.img" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1BrSiUQ1fzxFS9vIaK4mYKX6qIVp9kRWT" dest="${test-input}/PasswordDetection_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1HD8s4rculgHV1qZT5g80Kg7j4m1qccrN" dest="${test-input}/veracrypt_detection_test.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1HD8s4rculgHV1qZT5g80Kg7j4m1qccrN" dest="${test-input}/VeracryptDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1mr9waEDG5H8GBBn_yXwMUQ6senwC1goL" dest="${test-input}/CommonFiles_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1-vmbmAAb2HBLbf58GpAA97ozGUFiYHbN" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1ghDjm0NhI3ShMQ38E-4o7XrGeexpjdJb" dest="${test-input}/CommonFiles_img3_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1SJYJFjiumKEtQmeMPsQ6G3xmABarbKm_" dest="${test-input}/CommonFiles_img4_v1.vhd" skipexisting="true"/>
</target> </target>
<target name="get-deps" depends="init-ivy,getTSKJars,get-thirdparty-dependencies,get-InternalPythonModules, download-binlist,getTestDataFiles"> <target name="get-deps" depends="init-ivy,getTSKJars,get-thirdparty-dependencies,get-InternalPythonModules, download-binlist,getTestDataFiles">

View File

@ -3,7 +3,7 @@ file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar
file.reference.commons-compress-1.14.jar=release/modules/ext/commons-compress-1.14.jar file.reference.commons-compress-1.14.jar=release/modules/ext/commons-compress-1.14.jar
file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar
file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar
file.reference.dd-plist-1.20.jar=release\\modules\\ext\\dd-plist-1.20.jar file.reference.dd-plist-1.20.jar=release/modules/ext/dd-plist-1.20.jar
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.jar file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.jar
@ -12,7 +12,6 @@ file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
file.reference.metadata-extractor-2.10.1.jar=release/modules/ext/metadata-extractor-2.10.1.jar file.reference.metadata-extractor-2.10.1.jar=release/modules/ext/metadata-extractor-2.10.1.jar
file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar
file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
@ -40,6 +39,7 @@ file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8
file.reference.xmpcore-5.1.3.jar=release/modules/ext/xmpcore-5.1.3.jar file.reference.xmpcore-5.1.3.jar=release/modules/ext/xmpcore-5.1.3.jar
file.reference.xz-1.6.jar=release/modules/ext/xz-1.6.jar file.reference.xz-1.6.jar=release/modules/ext/xz-1.6.jar
file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar
file.reference.SparseBitSet-1.1.jar=release/modules/ext/SparseBitSet-1.1.jar
javac.source=1.8 javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial javac.compilerargs=-Xlint -Xlint:-serial
license.file=../LICENSE-2.0.txt license.file=../LICENSE-2.0.txt

View File

@ -339,6 +339,10 @@
<package>org.sleuthkit.autopsy.report</package> <package>org.sleuthkit.autopsy.report</package>
<package>org.sleuthkit.datamodel</package> <package>org.sleuthkit.datamodel</package>
</public-packages> </public-packages>
<class-path-extension>
<runtime-relative-path>ext/jackcess-2.1.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-2.1.8.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path> <runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
<binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin> <binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin>
@ -348,33 +352,33 @@
<binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin> <binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.1.jar</runtime-relative-path> <runtime-relative-path>ext/cxf-rt-transports-http-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.1.jar</binary-origin> <binary-origin>release/modules/ext/cxf-rt-transports-http-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path> <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> <binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path> <runtime-relative-path>ext/bcprov-jdk15on-1.54.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-dbcp2-2.1.1.jar</binary-origin> <binary-origin>release/modules/ext/bcprov-jdk15on-1.54.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jgraphx-v3.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jgraphx-v3.8.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/commons-compress-1.14.jar</runtime-relative-path> <runtime-relative-path>ext/commons-compress-1.14.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-compress-1.14.jar</binary-origin> <binary-origin>release/modules/ext/commons-compress-1.14.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/fontbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/fontbox-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path> <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> <binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jgraphx-v3.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jgraphx-v3.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path> <runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin> <binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
@ -387,6 +391,14 @@
<runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path> <runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path>
<binary-origin>release/modules/ext/mchange-commons-java-0.2.9.jar</binary-origin> <binary-origin>release/modules/ext/mchange-commons-java-0.2.9.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-core-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-core-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/javax.ws.rs-api-2.0.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/javax.ws.rs-api-2.0.1.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/postgresql-9.4.1211.jre7.jar</runtime-relative-path> <runtime-relative-path>ext/postgresql-9.4.1211.jre7.jar</runtime-relative-path>
<binary-origin>release/modules/ext/postgresql-9.4.1211.jre7.jar</binary-origin> <binary-origin>release/modules/ext/postgresql-9.4.1211.jre7.jar</binary-origin>
@ -399,6 +411,10 @@
<runtime-relative-path>ext/metadata-extractor-2.10.1.jar</runtime-relative-path> <runtime-relative-path>ext/metadata-extractor-2.10.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/metadata-extractor-2.10.1.jar</binary-origin> <binary-origin>release/modules/ext/metadata-extractor-2.10.1.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.1.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/tika-core-1.17.jar</runtime-relative-path> <runtime-relative-path>ext/tika-core-1.17.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-core-1.17.jar</binary-origin> <binary-origin>release/modules/ext/tika-core-1.17.jar</binary-origin>
@ -411,58 +427,18 @@
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path> <runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin> <binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/bcprov-jdk15on-1.54.jar</runtime-relative-path>
<binary-origin>release/modules/ext/bcprov-jdk15on-1.54.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackcess-2.1.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-2.1.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackcess-encrypt-2.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-encrypt-2.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jempbox-1.8.13.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jempbox-1.8.13.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/javax.ws.rs-api-2.0.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/javax.ws.rs-api-2.0.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-rt-rs-client-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-rs-client-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-rt-transports-http-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-transports-http-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-core-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-core-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/cxf-rt-frontend-jaxrs-3.0.16.jar</runtime-relative-path> <runtime-relative-path>ext/cxf-rt-frontend-jaxrs-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar</binary-origin> <binary-origin>release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/tika-parsers-1.17.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-parsers-1.17.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/fontbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/fontbox-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/pdfbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/pdfbox-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/pdfbox-tools-2.0.8.jar</runtime-relative-path> <runtime-relative-path>ext/pdfbox-tools-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/pdfbox-tools-2.0.8.jar</binary-origin> <binary-origin>release/modules/ext/pdfbox-tools-2.0.8.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/tika-parsers-1.17.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-parsers-1.17.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path> <runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.8.11.jar</binary-origin> <binary-origin>release/modules/ext/sqlite-jdbc-3.8.11.jar</binary-origin>
@ -483,6 +459,14 @@
<runtime-relative-path>ext/dd-plist-1.20.jar</runtime-relative-path> <runtime-relative-path>ext/dd-plist-1.20.jar</runtime-relative-path>
<binary-origin>release/modules/ext/dd-plist-1.20.jar</binary-origin> <binary-origin>release/modules/ext/dd-plist-1.20.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jempbox-1.8.13.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jempbox-1.8.13.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-rt-rs-client-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-rs-client-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path> <runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin> <binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
@ -491,6 +475,10 @@
<runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path> <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> <binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackcess-encrypt-2.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-encrypt-2.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path> <runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jsoup-1.10.3.jar</binary-origin> <binary-origin>release/modules/ext/jsoup-1.10.3.jar</binary-origin>
@ -499,6 +487,10 @@
<runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path> <runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jdom-2.0.5-contrib.jar</binary-origin> <binary-origin>release/modules/ext/jdom-2.0.5-contrib.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/pdfbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/pdfbox-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path> <runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin> <binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
@ -506,6 +498,10 @@
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/xmpcore-5.1.3.jar</runtime-relative-path> <runtime-relative-path>ext/xmpcore-5.1.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xmpcore-5.1.3.jar</binary-origin> <binary-origin>release/modules/ext/xmpcore-5.1.3.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/SparseBitSet-1.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/SparseBitSet-1.1.jar</binary-origin>
</class-path-extension> </class-path-extension>
</data> </data>
</configuration> </configuration>

View File

@ -37,8 +37,8 @@ import org.sleuthkit.datamodel.TskCoreException;
* Instances of this Action allow users to apply tags to blackboard artifacts. * Instances of this Action allow users to apply tags to blackboard artifacts.
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
"AddBlackboardArtifactTagAction.singularTagResult=Tag Result", "AddBlackboardArtifactTagAction.singularTagResult=Add Result Tag",
"AddBlackboardArtifactTagAction.pluralTagResult=Tag Results", "AddBlackboardArtifactTagAction.pluralTagResult=Add Result Tags",
"# {0} - artifactName", "# {0} - artifactName",
"AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}.", "AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}.",
"AddBlackboardArtifactTagAction.taggingErr=Tagging Error" "AddBlackboardArtifactTagAction.taggingErr=Tagging Error"

View File

@ -38,8 +38,8 @@ import org.sleuthkit.datamodel.TskCoreException;
* Instances of this Action allow users to apply tags to content. * Instances of this Action allow users to apply tags to content.
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
"AddContentTagAction.singularTagFile=Tag File", "AddContentTagAction.singularTagFile=Add File Tag",
"AddContentTagAction.pluralTagFile=Tag Files", "AddContentTagAction.pluralTagFile=Add File Tags",
"# {0} - fileName", "# {0} - fileName",
"AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file.", "AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file.",
"AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag", "AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag",

View File

@ -19,6 +19,8 @@
package org.sleuthkit.autopsy.actions; package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.logging.Level; import java.util.logging.Level;
@ -83,7 +85,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
*/ */
// @@@ This user interface has some significant usability issues and needs // @@@ This user interface has some significant usability issues and needs
// to be reworked. // to be reworked.
private class TagMenu extends JMenu { private final class TagMenu extends JMenu {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -92,6 +94,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
// Get the current set of tag names. // Get the current set of tag names.
Map<String, TagName> tagNamesMap = null; Map<String, TagName> tagNamesMap = null;
List<String> standardTagNames = TagsManager.getStandardTagNames();
try { try {
TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap());
@ -99,13 +102,9 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
} }
// Create a "Quick Tag" sub-menu. // Create a menu item for each of the existing and visible tags.
JMenu quickTagMenu = new JMenu(NbBundle.getMessage(this.getClass(), "AddTagAction.quickTag")); // Selecting one of these menu items adds a tag with the associated tag name.
add(quickTagMenu); List<JMenuItem> standardTagMenuitems = new ArrayList<>();
// Each tag name in the current set of tags gets its own menu item in
// the "Quick Tags" sub-menu. Selecting one of these menu items adds
// a tag with the associated tag name.
if (null != tagNamesMap && !tagNamesMap.isEmpty()) { if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) { for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
String tagDisplayName = entry.getKey(); String tagDisplayName = entry.getKey();
@ -119,27 +118,25 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
tagNameItem.addActionListener((ActionEvent e) -> { tagNameItem.addActionListener((ActionEvent e) -> {
getAndAddTag(entry.getKey(), entry.getValue(), NO_COMMENT); getAndAddTag(entry.getKey(), entry.getValue(), NO_COMMENT);
}); });
quickTagMenu.add(tagNameItem);
} // Show custom tags before predefined tags in the menu
if (standardTagNames.contains(tagDisplayName)) {
standardTagMenuitems.add(tagNameItem);
} else { } else {
JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags")); add(tagNameItem);
empty.setEnabled(false); }
quickTagMenu.add(empty); }
} }
quickTagMenu.addSeparator(); if (getItemCount() > 0) {
addSeparator();
// The "Quick Tag" menu also gets an "Choose Tag..." menu item.
// Selecting this item initiates a dialog that can be used to create
// or select a tag name and adds a tag with the resulting name.
JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag"));
newTagMenuItem.addActionListener((ActionEvent e) -> {
TagName tagName = GetTagNameDialog.doDialog();
if (null != tagName) {
addTag(tagName, NO_COMMENT);
} }
standardTagMenuitems.forEach((menuItem) -> {
add(menuItem);
}); });
quickTagMenu.add(newTagMenuItem);
addSeparator();
// Create a "Choose Tag and Comment..." menu item. Selecting this item initiates // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates
// a dialog that can be used to create or select a tag name with an // a dialog that can be used to create or select a tag name with an
@ -153,6 +150,19 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
} }
}); });
add(tagAndCommentItem); add(tagAndCommentItem);
// Create a "New Tag..." menu item.
// Selecting this item initiates a dialog that can be used to create
// or select a tag name and adds a tag with the resulting name.
JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag"));
newTagMenuItem.addActionListener((ActionEvent e) -> {
TagName tagName = GetTagNameDialog.doDialog();
if (null != tagName) {
addTag(tagName, NO_COMMENT);
}
});
add(newTagMenuItem);
} }
/** /**

View File

@ -20,7 +20,7 @@ AddTagAction.newTag=New Tag...
AddTagAction.tagAndComment=Tag and Comment... AddTagAction.tagAndComment=Tag and Comment...
AddBookmarkTagAction.bookmark.text=Bookmark AddBookmarkTagAction.bookmark.text=Bookmark
GetTagNameAndCommentDialog.noTags=No Tags GetTagNameAndCommentDialog.noTags=No Tags
GetTagNameAndCommentDialog.createTag=Create Tag GetTagNameAndCommentDialog.selectTag=Select Tag
GetTagNameAndCommentDialog.cancelName=cancel GetTagNameAndCommentDialog.cancelName=cancel
GetTagNameDialog.createTag=Create Tag GetTagNameDialog.createTag=Create Tag
GetTagNameDialog.cancelName=Cancel GetTagNameDialog.cancelName=Cancel

View File

@ -23,7 +23,7 @@ AddTagAction.noTags=\u30bf\u30b0\u7121\u3057
AddTagAction.newTag=\u65b0\u898f\u30bf\u30b0\u2026 AddTagAction.newTag=\u65b0\u898f\u30bf\u30b0\u2026
AddTagAction.tagAndComment=\u30bf\u30b0\u3068\u30b3\u30e1\u30f3\u30c8\u3092\u8ffd\u52a0\u2026 AddTagAction.tagAndComment=\u30bf\u30b0\u3068\u30b3\u30e1\u30f3\u30c8\u3092\u8ffd\u52a0\u2026
GetTagNameAndCommentDialog.noTags=\u30bf\u30b0\u7121\u3057 GetTagNameAndCommentDialog.noTags=\u30bf\u30b0\u7121\u3057
GetTagNameAndCommentDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210 GetTagNameAndCommentDialog.selectTag=\u30bf\u30b0\u3092\u9078\u629e
GetTagNameAndCommentDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb GetTagNameAndCommentDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb
GetTagNameDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210 GetTagNameDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210
GetTagNameDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb GetTagNameDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb

View File

@ -38,7 +38,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* artifacts. * artifacts.
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
"DeleteBlackboardArtifactTagAction.deleteTag=Delete Tag", "DeleteBlackboardArtifactTagAction.deleteTag=Remove Selected Tag(s)",
"# {0} - tagName", "# {0} - tagName",
"DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}.", "DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}.",
"DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error" "DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error"

View File

@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* Instances of this Action allow users to delete tags applied to content. * Instances of this Action allow users to delete tags applied to content.
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
"DeleteContentTagAction.deleteTag=Delete Tag", "DeleteContentTagAction.deleteTag=Remove Selected Tag(s)",
"# {0} - tagName", "# {0} - tagName",
"DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}.", "DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}.",
"DeleteContentTagAction.tagDelErr=Tag Deletion Error" "DeleteContentTagAction.tagDelErr=Tag Deletion Error"

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.actions; package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -138,7 +139,7 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
*/ */
@NbBundle.Messages({"# {0} - artifactID", @NbBundle.Messages({"# {0} - artifactID",
"DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."}) "DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."})
private class TagMenu extends JMenu { private final class TagMenu extends JMenu {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -153,6 +154,8 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
= selectedBlackboardArtifactsList.iterator().next(); = selectedBlackboardArtifactsList.iterator().next();
Map<String, TagName> tagNamesMap = null; Map<String, TagName> tagNamesMap = null;
List<String> standardTagNames = TagsManager.getStandardTagNames();
List<JMenuItem> standardTagMenuitems = new ArrayList<>();
try { try {
// Get the current set of tag names. // Get the current set of tag names.
TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
@ -182,16 +185,27 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
tagNameItem.addActionListener((ActionEvent e) -> { tagNameItem.addActionListener((ActionEvent e) -> {
deleteTag(tagName, artifactTag, artifact.getArtifactID()); deleteTag(tagName, artifactTag, artifact.getArtifactID());
}); });
// Show custom tags before predefined tags in the menu
if (standardTagNames.contains(tagDisplayName)) {
standardTagMenuitems.add(tagNameItem);
} else {
add(tagNameItem); add(tagNameItem);
} }
} }
} }
}
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(TagMenu.class.getName()) Logger.getLogger(TagMenu.class.getName())
.log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS .log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS
} }
} }
if ((getItemCount() > 0) && !standardTagMenuitems.isEmpty() ){
addSeparator();
}
standardTagMenuitems.forEach((menuItem) -> {
add(menuItem);
});
if (getItemCount() == 0) { if (getItemCount() == 0) {
setEnabled(false); setEnabled(false);
} }

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.actions; package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -136,7 +137,7 @@ public class DeleteFileContentTagAction extends AbstractAction implements Presen
* creating or selecting a tag name for a tag and specifying an optional tag * creating or selecting a tag name for a tag and specifying an optional tag
* comment. * comment.
*/ */
private class TagMenu extends JMenu { private final class TagMenu extends JMenu {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -150,6 +151,8 @@ public class DeleteFileContentTagAction extends AbstractAction implements Presen
AbstractFile file = selectedAbstractFilesList.iterator().next(); AbstractFile file = selectedAbstractFilesList.iterator().next();
Map<String, TagName> tagNamesMap = null; Map<String, TagName> tagNamesMap = null;
List<String> standardTagNames = TagsManager.getStandardTagNames();
List<JMenuItem> standardTagMenuitems = new ArrayList<>();
try { try {
// Get the current set of tag names. // Get the current set of tag names.
TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
@ -179,16 +182,29 @@ public class DeleteFileContentTagAction extends AbstractAction implements Presen
tagNameItem.addActionListener((ActionEvent e) -> { tagNameItem.addActionListener((ActionEvent e) -> {
deleteTag(tagName, contentTag, file.getId()); deleteTag(tagName, contentTag, file.getId());
}); });
// Show custom tags before predefined tags in the menu
if (standardTagNames.contains(tagDisplayName)) {
standardTagMenuitems.add(tagNameItem);
} else {
add(tagNameItem); add(tagNameItem);
} }
} }
} }
}
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(TagMenu.class.getName()) Logger.getLogger(TagMenu.class.getName())
.log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS .log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS
} }
} }
if ((getItemCount() > 0) && !standardTagMenuitems.isEmpty() ){
addSeparator();
}
standardTagMenuitems.forEach((menuItem) -> {
add(menuItem);
});
if(getItemCount() == 0) { if(getItemCount() == 0) {
setEnabled(false); setEnabled(false);
} }

View File

@ -24,11 +24,11 @@
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Component id="newTagButton" min="-2" max="-2" attributes="0"/> <Component id="newTagButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="165" max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
<Component id="okButton" linkSize="1" min="-2" pref="67" max="-2" attributes="0"/> <Component id="okButton" linkSize="1" min="-2" pref="67" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/> <Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/>
@ -38,14 +38,14 @@
<Component id="commentLabel" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="commentLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="tagLabel" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="tagLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="commentText" max="32767" attributes="0"/>
<Component id="tagCombo" max="32767" attributes="0"/> <Component id="tagCombo" max="32767" attributes="0"/>
<Component id="jScrollPane1" pref="318" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -58,11 +58,11 @@
<Component id="tagLabel" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="tagLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="commentLabel" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="commentLabel" min="-2" max="-2" attributes="0"/>
<Component id="commentText" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="jScrollPane1" min="-2" pref="51" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace pref="37" max="32767" attributes="0"/> <EmptySpace pref="22" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
@ -125,16 +125,6 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JTextField" name="commentText">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="newTagButton"> <Component class="javax.swing.JButton" name="newTagButton">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
@ -145,5 +135,26 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newTagButtonActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newTagButtonActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="commentText">
<Properties>
<Property name="columns" type="int" value="20"/>
<Property name="rows" type="int" value="5"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents> </SubComponents>
</Form> </Form>

View File

@ -22,9 +22,13 @@ import java.awt.Component;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.ActionMap; import javax.swing.ActionMap;
import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListCellRenderer;
@ -43,10 +47,15 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
/**
* This dialog allows tag assignment with a comment attached.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class GetTagNameAndCommentDialog extends JDialog { public class GetTagNameAndCommentDialog extends JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Set<TagName> tagNamesSet = new HashSet<>(); private final List<TagName> tagNamesList = new ArrayList<>();
private final List<TagName> standardTagNamesList = new ArrayList<>();
private TagNameAndComment tagNameAndComment = null; private TagNameAndComment tagNameAndComment = null;
public static class TagNameAndComment { public static class TagNameAndComment {
@ -101,7 +110,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
private GetTagNameAndCommentDialog(Window owner) { private GetTagNameAndCommentDialog(Window owner) {
super(owner, super(owner,
NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.createTag"), NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.selectTag"),
ModalityType.APPLICATION_MODAL); ModalityType.APPLICATION_MODAL);
} }
@ -140,16 +149,29 @@ public class GetTagNameAndCommentDialog extends JDialog {
// not exist in the database). // not exist in the database).
try { try {
TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
tagNamesSet.addAll(tagsManager.getAllTagNames()); List<String> standardTagNames = TagsManager.getStandardTagNames();
Map<String, TagName> tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap());
tagNamesMap.entrySet().stream().map((entry) -> entry.getValue()).forEachOrdered((tagName) -> {
if (standardTagNames.contains(tagName.getDisplayName())) {
standardTagNamesList.add(tagName);
} else {
tagNamesList.add(tagName);
}
});
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(GetTagNameAndCommentDialog.class Logger.getLogger(GetTagNameAndCommentDialog.class
.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS .getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
} }
for (TagName tag : tagNamesSet) { tagNamesList.forEach((tag) -> {
tagCombo.addItem(tag); tagCombo.addItem(tag);
} });
standardTagNamesList.forEach((tag) -> {
tagCombo.addItem(tag);
});
// Center and show the dialog box. // Center and show the dialog box.
this.setLocationRelativeTo(this.getOwner()); this.setLocationRelativeTo(this.getOwner());
@ -170,8 +192,9 @@ public class GetTagNameAndCommentDialog extends JDialog {
tagCombo = new javax.swing.JComboBox<TagName>(); tagCombo = new javax.swing.JComboBox<TagName>();
tagLabel = new javax.swing.JLabel(); tagLabel = new javax.swing.JLabel();
commentLabel = new javax.swing.JLabel(); commentLabel = new javax.swing.JLabel();
commentText = new javax.swing.JTextField();
newTagButton = new javax.swing.JButton(); newTagButton = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
commentText = new javax.swing.JTextArea();
addWindowListener(new java.awt.event.WindowAdapter() { addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) { public void windowClosing(java.awt.event.WindowEvent evt) {
@ -199,9 +222,6 @@ public class GetTagNameAndCommentDialog extends JDialog {
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentLabel.text")); // NOI18N
commentText.setText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.text")); // NOI18N
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.newTagButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.newTagButton.text")); // NOI18N
newTagButton.addActionListener(new java.awt.event.ActionListener() { newTagButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -209,6 +229,12 @@ public class GetTagNameAndCommentDialog extends JDialog {
} }
}); });
commentText.setColumns(20);
commentText.setRows(5);
commentText.setText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.text")); // NOI18N
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.toolTipText")); // NOI18N
jScrollPane1.setViewportView(commentText);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout); getContentPane().setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
@ -218,7 +244,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(newTagButton) .addComponent(newTagButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 165, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton)) .addComponent(cancelButton))
@ -228,8 +254,8 @@ public class GetTagNameAndCommentDialog extends JDialog {
.addComponent(tagLabel)) .addComponent(tagLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(commentText) .addComponent(tagCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(tagCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 318, Short.MAX_VALUE))))
.addContainerGap()) .addContainerGap())
); );
@ -243,10 +269,10 @@ public class GetTagNameAndCommentDialog extends JDialog {
.addComponent(tagCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(tagCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(tagLabel)) .addComponent(tagLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(commentLabel) .addComponent(commentLabel)
.addComponent(commentText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 37, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 22, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cancelButton) .addComponent(cancelButton)
.addComponent(okButton) .addComponent(okButton)
@ -278,7 +304,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
TagName newTagName = GetTagNameDialog.doDialog(this); TagName newTagName = GetTagNameDialog.doDialog(this);
if (newTagName != null) { if (newTagName != null) {
tagNamesSet.add(newTagName); tagNamesList.add(newTagName);
tagCombo.addItem(newTagName); tagCombo.addItem(newTagName);
tagCombo.setSelectedItem(newTagName); tagCombo.setSelectedItem(newTagName);
} }
@ -287,7 +313,8 @@ public class GetTagNameAndCommentDialog extends JDialog {
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton; private javax.swing.JButton cancelButton;
private javax.swing.JLabel commentLabel; private javax.swing.JLabel commentLabel;
private javax.swing.JTextField commentText; private javax.swing.JTextArea commentText;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton newTagButton; private javax.swing.JButton newTagButton;
private javax.swing.JButton okButton; private javax.swing.JButton okButton;
private javax.swing.JComboBox<TagName> tagCombo; private javax.swing.JComboBox<TagName> tagCombo;

View File

@ -46,8 +46,12 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
/**
* Displays existing tag names, and allows the creation of new tags.
*/
@Messages({"GetTagNameDialog.descriptionLabel.text=Description:", @Messages({"GetTagNameDialog.descriptionLabel.text=Description:",
"GetTagNameDialog.notableCheckbox.text=Tag indicates item is notable."}) "GetTagNameDialog.notableCheckbox.text=Tag indicates item is notable."})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class GetTagNameDialog extends JDialog { public class GetTagNameDialog extends JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -0,0 +1,127 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.actions;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javax.swing.SwingWorker;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* This Action allows users to replace a tag applied to blackboard
* artifacts, with another tag
*/
public final class ReplaceBlackboardArtifactTagAction extends ReplaceTagAction<BlackboardArtifactTag> {
private static final Logger logger = Logger.getLogger(ReplaceBlackboardArtifactTagAction.class.getName());
private static final long serialVersionUID = 1L;
// This class is a singleton to support multi-selection of nodes, since
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
// node in the array returns a reference to the same action object from Node.getActions(boolean).
private static ReplaceBlackboardArtifactTagAction instance;
public static synchronized ReplaceBlackboardArtifactTagAction getInstance() {
if (null == instance) {
instance = new ReplaceBlackboardArtifactTagAction();
}
return instance;
}
private ReplaceBlackboardArtifactTagAction() {
super(MENU_TEXT);
}
/**
* Replaces the specified tag on the given artifact with the new one
*
* @param oldArtifactTag tag to be replaced
* @param newTagName name of the tag to replace with
* @param newComment the newComment for the tag use an empty string for no newComment
*/
@NbBundle.Messages({
"# {0} - old tag name",
"# {1} - artifactID",
"ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}."})
@Override
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName, String newComment) {
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
TagsManager tagsManager;
try {
tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Error replacing artifact tag. No open case found.", ex); //NON-NLS
Platform.runLater(()
-> new Alert(Alert.AlertType.ERROR, Bundle.ReplaceBlackboardArtifactTagAction_replaceTag_alert(oldArtifactTag.getName().getDisplayName(), oldArtifactTag.getArtifact().getArtifactID())).show()
);
return null;
}
try {
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldArtifactTag.getName().getDisplayName(), newTagName.getDisplayName(), oldArtifactTag.getContent().getName()}); //NON-NLS
tagsManager.deleteBlackboardArtifactTag(oldArtifactTag);
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName, newComment);
} catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
Platform.runLater(()
-> new Alert(Alert.AlertType.ERROR, Bundle.ReplaceBlackboardArtifactTagAction_replaceTag_alert(oldArtifactTag.getName().getDisplayName(), oldArtifactTag.getArtifact().getArtifactID())).show()
);
}
return null;
}
@Override
protected void done() {
super.done();
try {
get();
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.SEVERE, "Unexpected exception while replacing artifact tag", ex); //NON-NLS
}
}
}.execute();
}
/**
* Returns list of tags selected by user to replace
*
* @return a list of tags
*/
@Override
Collection<? extends BlackboardArtifactTag> getTagsToReplace() {
return Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class);
}
}

View File

@ -0,0 +1,120 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.actions;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javax.swing.SwingWorker;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* This Action allow users to replace a content tag with another tag
*/
public final class ReplaceContentTagAction extends ReplaceTagAction<ContentTag> {
private static final Logger logger = Logger.getLogger(ReplaceContentTagAction.class.getName());
private static final long serialVersionUID = 1L;
// This class is a singleton to support multi-selection of nodes, since
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
// node in the array returns a reference to the same action object from Node.getActions(boolean).
private static ReplaceContentTagAction instance;
public static synchronized ReplaceContentTagAction getInstance() {
if (null == instance) {
instance = new ReplaceContentTagAction();
}
return instance;
}
private ReplaceContentTagAction() {
super(MENU_TEXT);
}
@NbBundle.Messages({
"# {0} - old tag name",
"# {1} - content obj id",
"ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}."})
@Override
protected void replaceTag(ContentTag oldTag, TagName newTagName, String newComment) {
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
TagsManager tagsManager;
try {
tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Error replacing artifact tag. No open case found.", ex); //NON-NLS
Platform.runLater(()
-> new Alert(Alert.AlertType.ERROR, Bundle.ReplaceContentTagAction_replaceTag_alert(oldTag.getName().getDisplayName(), oldTag.getContent().getName())).show()
);
return null;
}
try {
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldTag.getName().getDisplayName(), newTagName.getDisplayName(), oldTag.getContent().getName()}); //NON-NLS
tagsManager.deleteContentTag(oldTag);
tagsManager.addContentTag(oldTag.getContent(), newTagName, newComment);
} catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
Platform.runLater(()
-> new Alert(Alert.AlertType.ERROR, Bundle.ReplaceContentTagAction_replaceTag_alert(oldTag.getName().getDisplayName(), oldTag.getContent().getName())).show()
);
}
return null;
}
@Override
protected void done() {
super.done();
try {
get();
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.SEVERE, "Unexpected exception while replacing content tag", ex); //NON-NLS
}
}
}.execute();
}
/**
* Returns list of content tags selected by user to replace
*
* @return a list of tags
*/
@Override
Collection<? extends ContentTag> getTagsToReplace() {
return Utilities.actionsGlobalContext().lookupAll(ContentTag.class);
}
}

View File

@ -0,0 +1,201 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.actions;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.openide.util.NbBundle;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Abstract class to define context action to replace a tag with another
*
* @param <T> tag type
*/
@NbBundle.Messages({
"ReplaceTagAction.replaceTag=Replace Selected Tag(s) With"
})
abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements Presenter.Popup {
private static final long serialVersionUID = 1L;
protected static final String MENU_TEXT = NbBundle.getMessage(ReplaceTagAction.class,
"ReplaceTagAction.replaceTag");
ReplaceTagAction(String menuText) {
super(menuText);
}
/**
* Subclasses of replaceTagAction should not override actionPerformed,
* but instead override replaceTag.
*
* @param event
*/
@Override
@SuppressWarnings("NoopMethodInAbstractClass")
public void actionPerformed(ActionEvent event) {
}
protected String getActionDisplayName() {
return MENU_TEXT;
}
/**
* Method to actually replace the selected tag with the given new tag
*
* @param oldTag - the TagName which is being removed from the item
* @param newTagName - the TagName which is being added to the itme
* @param comment the comment associated with the tag, empty string for no comment
*/
abstract protected void replaceTag(T oldTag, TagName newTagName, String comment);
/**
* Returns elected tags which are to be replaced
*
* @return
*/
abstract Collection<? extends T> getTagsToReplace();
@Override
public JMenuItem getPopupPresenter() {
return new ReplaceTagMenu();
}
/**
* Instances of this class implement a context menu user interface for
* selecting a tag name to replace the tag with
*/
private final class ReplaceTagMenu extends JMenu {
private static final long serialVersionUID = 1L;
ReplaceTagMenu() {
super(getActionDisplayName());
final Collection<? extends T> selectedTags = getTagsToReplace();
// Get the current set of tag names.
Map<String, TagName> tagNamesMap = null;
List<String> standardTagNames = TagsManager.getStandardTagNames();
try {
TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap());
} catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(ReplaceTagMenu.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
List<JMenuItem> standardTagMenuitems = new ArrayList<>();
// Ideally we should'nt allow user to pick a replacement tag that's already been applied to an item
// In the very least we don't allow them to pick the same tag as the one they are trying to replace
Set<String> existingTagNames = new HashSet<>();
if (!selectedTags.isEmpty()) {
T firstTag = selectedTags.iterator().next();
existingTagNames.add(firstTag.getName().getDisplayName());
}
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
String tagDisplayName = entry.getKey();
String notableString = entry.getValue().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString);
// for the bookmark tag name only, added shortcut label
if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) {
tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT);
}
// Add action to replace the tag
tagNameItem.addActionListener((ActionEvent event) -> {
selectedTags.forEach((oldtag) -> {
replaceTag(oldtag, entry.getValue(), oldtag.getComment());
});
});
// Don't allow replacing a tag with same tag.
if (existingTagNames.contains(tagDisplayName)) {
tagNameItem.setEnabled(false);
}
// Show custom tags before predefined tags in the menu
if (standardTagNames.contains(tagDisplayName)) {
standardTagMenuitems.add(tagNameItem);
} else {
add(tagNameItem);
}
}
} else {
JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags"));
empty.setEnabled(false);
add(empty);
}
//
if (this.getItemCount() > 0) {
addSeparator();
}
standardTagMenuitems.forEach((menuItem) -> {
add(menuItem);
});
addSeparator();
JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag"));
newTagMenuItem.addActionListener((ActionEvent event) -> {
TagName newTagName = GetTagNameDialog.doDialog();
if (null != newTagName) {
selectedTags.forEach((oldtag) -> {
replaceTag(oldtag, newTagName, oldtag.getComment());
});
}
});
add(newTagMenuItem);
// Create a "Choose Tag and Comment..." menu item. Selecting this item initiates
// a dialog that can be used to create or select a tag name with an
// optional comment and adds a tag with the resulting name.
JMenuItem tagAndCommentItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.tagAndComment"));
tagAndCommentItem.addActionListener((ActionEvent event) -> {
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog();
if (null != tagNameAndComment) {
selectedTags.forEach((oldtag) -> {
replaceTag(oldtag, tagNameAndComment.getTagName(), tagNameAndComment.getComment());
});
}
});
add(tagAndCommentItem);
}
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,15 +18,22 @@
*/ */
package org.sleuthkit.autopsy.casemodule; package org.sleuthkit.autopsy.casemodule;
import java.awt.Frame;
import javax.swing.JDialog;
/** /**
* Dialog to show add image error messages * Dialog to show add image error messages
*/ */
public class AddImageErrorsDialog extends javax.swing.JDialog { @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class AddImageErrorsDialog extends JDialog {
/** /**
* Creates new form AddImageErrorsDialog * Creates new form AddImageErrorsDialog
*
* @param parent The parent frame.
* @param modal Does this dialog act as a modal?
*/ */
public AddImageErrorsDialog(java.awt.Frame parent, boolean modal) { public AddImageErrorsDialog(Frame parent, boolean modal) {
super(parent, modal); super(parent, modal);
initComponents(); initComponents();
} }

View File

@ -57,6 +57,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* {@link AddImageWizardIngestConfigPanel} (which is a bit weird if you ask m * {@link AddImageWizardIngestConfigPanel} (which is a bit weird if you ask m
* -jm) * -jm)
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
private boolean readyToIngest = false; private boolean readyToIngest = false;
@ -79,7 +80,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
*/ */
private AddImageWizardAddingProgressVisual component; private AddImageWizardAddingProgressVisual component;
private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>()); private final List<Content> newContents = Collections.synchronizedList(new ArrayList<>());
private final DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl(); private final DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl();
private IngestJobSettings ingestJobSettings; private IngestJobSettings ingestJobSettings;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2012 Basis Technology Corp. * Copyright 2012-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -19,16 +19,14 @@
package org.sleuthkit.autopsy.casemodule; package org.sleuthkit.autopsy.casemodule;
import java.awt.Color; import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import org.openide.WizardDescriptor;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
/** /**
* visual component to display progress bar and status updates while adding an * visual component to display progress bar and status updates while adding an
* image in the wizard * image in the wizard
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
private static final String ADDING_DATA_SOURCE_COMPLETE = NbBundle private static final String ADDING_DATA_SOURCE_COMPLETE = NbBundle

View File

@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescript
* The "Add Image" wizard panel1 handling the logic of selecting image file(s) * The "Add Image" wizard panel1 handling the logic of selecting image file(s)
* to add to Case, and pick the time zone. * to add to Case, and pick the time zone.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddImageWizardDataSourceSettingsPanel extends ShortcutWizardDescriptorPanel implements PropertyChangeListener { class AddImageWizardDataSourceSettingsPanel extends ShortcutWizardDescriptorPanel implements PropertyChangeListener {
/** /**

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -37,8 +37,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
/** /**
* visual component for the first panel of add image wizard. Allows the user to * visual component for the first panel of add image wizard. Allows the user to
* choose the data source type and then select the data source * choose the data source type and then select the data source
*
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class AddImageWizardDataSourceSettingsVisual extends JPanel { final class AddImageWizardDataSourceSettingsVisual extends JPanel {
private static final Logger logger = Logger.getLogger(AddImageWizardDataSourceSettingsVisual.class.getName()); private static final Logger logger = Logger.getLogger(AddImageWizardDataSourceSettingsVisual.class.getName());

View File

@ -40,10 +40,11 @@ import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescript
* TODO: review this for dead code. think about moving logic of adding image to * TODO: review this for dead code. think about moving logic of adding image to
* 3rd panel( {@link AddImageWizardAddingProgressPanel}) separate class -jm * 3rd panel( {@link AddImageWizardAddingProgressPanel}) separate class -jm
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel {
@Messages("AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules") @Messages("AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules")
private IngestJobSettingsPanel ingestJobSettingsPanel; private final IngestJobSettingsPanel ingestJobSettingsPanel;
/** /**
* The visual component that displays this panel. If you need to access the * The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent(). * component from this class, just use getComponent().

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2014 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -25,8 +25,8 @@ import javax.swing.JPanel;
/** /**
* UI panel for the ingest job configuration wizard panel of the add data source * UI panel for the ingest job configuration wizard panel of the add data source
* wizard. * wizard.
*
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddImageWizardIngestConfigVisual extends JPanel { class AddImageWizardIngestConfigVisual extends JPanel {
private final JPanel ingestPanel; private final JPanel ingestPanel;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescript
* Create a wizard panel which contains a panel allowing the selection of the * Create a wizard panel which contains a panel allowing the selection of the
* DataSourceProcessor * DataSourceProcessor
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class AddImageWizardSelectDspPanel extends ShortcutWizardDescriptorPanel implements PropertyChangeListener { final class AddImageWizardSelectDspPanel extends ShortcutWizardDescriptorPanel implements PropertyChangeListener {
@NbBundle.Messages("SelectDataSourceProcessorPanel.name.text=Select Type of Data Source To Add") @NbBundle.Messages("SelectDataSourceProcessorPanel.name.text=Select Type of Data Source To Add")

View File

@ -36,6 +36,7 @@ import javax.swing.Box.Filler;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.JToggleButton; import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
@ -46,6 +47,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* Panel which displays the available DataSourceProcessors and allows selection * Panel which displays the available DataSourceProcessors and allows selection
* of one * of one
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class AddImageWizardSelectDspVisual extends JPanel { final class AddImageWizardSelectDspVisual extends JPanel {
private static final Logger logger = Logger.getLogger(AddImageWizardSelectDspVisual.class.getName()); private static final Logger logger = Logger.getLogger(AddImageWizardSelectDspVisual.class.getName());
@ -171,6 +173,9 @@ final class AddImageWizardSelectDspVisual extends JPanel {
constraints.weighty = 1; constraints.weighty = 1;
gridBagLayout.setConstraints(vertGlue, constraints); gridBagLayout.setConstraints(vertGlue, constraints);
jPanel1.setLayout(gridBagLayout); jPanel1.setLayout(gridBagLayout);
SwingUtilities.invokeLater(() -> {
jScrollPane1.getVerticalScrollBar().setValue(0);
});
} }
/** /**

View File

@ -132,6 +132,7 @@ public class Case {
private static final String EXPORT_FOLDER = "Export"; //NON-NLS private static final String EXPORT_FOLDER = "Export"; //NON-NLS
private static final String LOG_FOLDER = "Log"; //NON-NLS private static final String LOG_FOLDER = "Log"; //NON-NLS
private static final String REPORTS_FOLDER = "Reports"; //NON-NLS private static final String REPORTS_FOLDER = "Reports"; //NON-NLS
private static final String CONFIG_FOLDER = "Config"; // NON-NLS
private static final String TEMP_FOLDER = "Temp"; //NON-NLS private static final String TEMP_FOLDER = "Temp"; //NON-NLS
private static final String MODULE_FOLDER = "ModuleOutput"; //NON-NLS private static final String MODULE_FOLDER = "ModuleOutput"; //NON-NLS
private static final String CASE_ACTION_THREAD_NAME = "%s-case-action"; private static final String CASE_ACTION_THREAD_NAME = "%s-case-action";
@ -295,9 +296,10 @@ public class Case {
*/ */
ADDING_DATA_SOURCE_FAILED, ADDING_DATA_SOURCE_FAILED,
/** /**
* A new data source has been added to the current case. The old value * A new data source or series of data sources have been added to the
* of the PropertyChangeEvent is null, the new value is the newly-added * current case. The old value of the PropertyChangeEvent is null, the
* data source (type: Content). Cast the PropertyChangeEvent to * new value is the newly-added data source (type: Content). Cast the
* PropertyChangeEvent to
* org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent to * org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent to
* access additional event data. * access additional event data.
*/ */
@ -1115,6 +1117,10 @@ public class Case {
/* /*
* Open the top components (windows within the main application * Open the top components (windows within the main application
* window). * window).
*
* Note: If the core windows are not opened here, they will be
* opened via the DirectoryTreeTopComponent 'propertyChange()'
* method on a DATA_SOURCE_ADDED event.
*/ */
if (newCurrentCase.hasData()) { if (newCurrentCase.hasData()) {
CoreComponentControl.openCoreWindows(); CoreComponentControl.openCoreWindows();
@ -1368,6 +1374,16 @@ public class Case {
return getOrCreateSubdirectory(REPORTS_FOLDER); return getOrCreateSubdirectory(REPORTS_FOLDER);
} }
/**
* Gets the full path to the config directory for this case, creating it if
* it does not exist.
*
* @return The config directory path.
*/
public String getConfigDirectory() {
return getOrCreateSubdirectory(CONFIG_FOLDER);
}
/** /**
* Gets the full path to the module output directory for this case, creating * Gets the full path to the module output directory for this case, creating
* it if it does not exist. * it if it does not exist.

View File

@ -49,8 +49,8 @@ import org.sleuthkit.autopsy.datamodel.EmptyNode;
* *
* Used to display a list of multi user cases and allow the user to open one of * Used to display a list of multi user cases and allow the user to open one of
* them. * them.
*
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class CaseBrowser extends javax.swing.JPanel implements ExplorerManager.Provider { class CaseBrowser extends javax.swing.JPanel implements ExplorerManager.Provider {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -32,6 +32,7 @@ import org.openide.windows.WindowManager;
* Panel for displaying the case information, including both case details and * Panel for displaying the case information, including both case details and
* ingest job history. * ingest job history.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class CaseInformationPanel extends javax.swing.JPanel { class CaseInformationPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -31,10 +31,11 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* A panel that allows the user to view various properties of a case and change * A panel that allows the user to view various properties of a case and change
* the display name of the case. * the display name of the case.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class CasePropertiesPanel extends javax.swing.JPanel { final class CasePropertiesPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(CasePropertiesPanel.class.getName()); private static final Logger logger = Logger.getLogger(CasePropertiesPanel.class.getName());
private Case theCase; private Case theCase;
/** /**
@ -52,7 +53,7 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
try { try {
theCase = Case.getCurrentCaseThrows(); theCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); logger.log(Level.SEVERE, "Exception while getting open case.", ex);
return; return;
} }
lbCaseNameText.setText(theCase.getDisplayName()); lbCaseNameText.setText(theCase.getDisplayName());
@ -90,7 +91,7 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
currentOrg = correlationCase.getOrg(); currentOrg = correlationCase.getOrg();
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Unable to access Correlation Case when Central Repo is enabled", ex); logger.log(Level.SEVERE, "Unable to access Correlation Case when Central Repo is enabled", ex);
} }
} }
if (currentOrg != null) { if (currentOrg != null) {

View File

@ -35,6 +35,7 @@ import org.openide.windows.WindowManager;
/* /*
* The panel in the default Autopsy startup window. * The panel in the default Autopsy startup window.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class CueBannerPanel extends javax.swing.JPanel { public class CueBannerPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -22,9 +22,9 @@ import java.awt.event.ActionListener;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
/** /**
* * Panel to allow examiner to edit option case properties.
* @author wschaefer
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class EditOptionalCasePropertiesPanel extends javax.swing.JPanel { class EditOptionalCasePropertiesPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -31,7 +31,6 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import static org.sleuthkit.autopsy.casemodule.Bundle.*; import static org.sleuthkit.autopsy.casemodule.Bundle.*;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
@ -46,6 +45,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator;
* to select a file as well as choose the timezone and whether to ignore orphan * to select a file as well as choose the timezone and whether to ignore orphan
* files in FAT32. * files in FAT32.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class ImageFilePanel extends JPanel implements DocumentListener { public class ImageFilePanel extends JPanel implements DocumentListener {
private static final Logger logger = Logger.getLogger(ImageFilePanel.class.getName()); private static final Logger logger = Logger.getLogger(ImageFilePanel.class.getName());

View File

@ -39,6 +39,7 @@ import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Panel for displaying ingest job history. * Panel for displaying ingest job history.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class IngestJobInfoPanel extends javax.swing.JPanel { public final class IngestJobInfoPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(IngestJobInfoPanel.class.getName()); private static final Logger logger = Logger.getLogger(IngestJobInfoPanel.class.getName());
@ -91,7 +92,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
"IngestJobInfoPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"}) "IngestJobInfoPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"})
private class IngestJobTableModel extends AbstractTableModel { private class IngestJobTableModel extends AbstractTableModel {
private List<String> columnHeaders = new ArrayList<>(); private final List<String> columnHeaders = new ArrayList<>();
IngestJobTableModel() { IngestJobTableModel() {
columnHeaders.add(Bundle.IngestJobInfoPanel_IngestJobTableModel_DataSource_header()); columnHeaders.add(Bundle.IngestJobInfoPanel_IngestJobTableModel_DataSource_header());
@ -146,8 +147,8 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
"IngestJobInfoPanel.IngestModuleTableModel.ModuleVersion.header=Module Version"}) "IngestJobInfoPanel.IngestModuleTableModel.ModuleVersion.header=Module Version"})
private class IngestModuleTableModel extends AbstractTableModel { private class IngestModuleTableModel extends AbstractTableModel {
private List<String> columnHeaders = new ArrayList<>(); private final List<String> columnHeaders = new ArrayList<>();
private IngestJobInfo currJob; private final IngestJobInfo currJob;
IngestModuleTableModel(IngestJobInfo currJob) { IngestModuleTableModel(IngestJobInfo currJob) {
columnHeaders.add(Bundle.IngestJobInfoPanel_IngestModuleTableModel_ModuleName_header()); columnHeaders.add(Bundle.IngestJobInfoPanel_IngestModuleTableModel_ModuleName_header());

View File

@ -34,6 +34,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings; import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
/**
* ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or
* C:.
*/
@NbBundle.Messages({ @NbBundle.Messages({
"LocalDiskPanel.errorMessage.noOpenCaseTitle=No open case available", "LocalDiskPanel.errorMessage.noOpenCaseTitle=No open case available",
"LocalDiskPanel.errorMessage.noOpenCaseBody=LocalDiskPanel listener couldn't get the open case.", "LocalDiskPanel.errorMessage.noOpenCaseBody=LocalDiskPanel listener couldn't get the open case.",
@ -45,10 +49,7 @@ import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
"LocalDiskPanel.moduleErrorMessage.body=A module caused an error listening to LocalDiskPanel updates. See log to determine which module. Some data could be incomplete.", "LocalDiskPanel.moduleErrorMessage.body=A module caused an error listening to LocalDiskPanel updates. See log to determine which module. Some data could be incomplete.",
"LocalDiskPanel.localDiskMessage.unspecified=Unspecified" "LocalDiskPanel.localDiskMessage.unspecified=Unspecified"
}) })
/** @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
* ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or
* C:.
*/
final class LocalDiskPanel extends JPanel { final class LocalDiskPanel extends JPanel {
private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName()); private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName());

View File

@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator;
/** /**
* A panel which allows the user to select local files and/or directories. * A panel which allows the user to select local files and/or directories.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class LocalFilesPanel extends javax.swing.JPanel { final class LocalFilesPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -278,7 +279,10 @@ final class LocalFilesPanel extends javax.swing.JPanel {
* *
* @param paths Absolute paths to the selected data source * @param paths Absolute paths to the selected data source
*/ */
@NbBundle.Messages("LocalFilesPanel.pathValidation.error=WARNING: Exception while gettting opon case.") @NbBundle.Messages({
"LocalFilesPanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive",
"LocalFilesPanel.pathValidation.getOpenCase=WARNING: Exception while gettting open case."
})
private void warnIfPathIsInvalid(final List<String> pathsList) { private void warnIfPathIsInvalid(final List<String> pathsList) {
errorLabel.setVisible(false); errorLabel.setVisible(false);
@ -288,13 +292,13 @@ final class LocalFilesPanel extends javax.swing.JPanel {
for (String currentPath : pathsList) { for (String currentPath : pathsList) {
if (!PathValidator.isValid(currentPath, currentCaseType)) { if (!PathValidator.isValid(currentPath, currentCaseType)) {
errorLabel.setVisible(true); errorLabel.setVisible(true);
errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text")); errorLabel.setText(Bundle.LocalFilesPanel_pathValidation_dataSourceOnCDriveError());
return; return;
} }
} }
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
errorLabel.setVisible(true); errorLabel.setVisible(true);
errorLabel.setText(Bundle.LocalFilesPanel_pathValidation_error()); errorLabel.setText(Bundle.LocalFilesPanel_pathValidation_getOpenCase());
} }
} }

View File

@ -32,7 +32,6 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.PathValidator;
@ -40,6 +39,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator;
/** /**
* A panel which allows the user to select a Logical Evidence File (L01) * A panel which allows the user to select a Logical Evidence File (L01)
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class LogicalEvidenceFilePanel extends javax.swing.JPanel implements DocumentListener { final class LogicalEvidenceFilePanel extends javax.swing.JPanel implements DocumentListener {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -28,13 +28,14 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* Add input wizard subpanel for adding local files / dirs to the case
*/
@Messages({ @Messages({
"LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders", "LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders",
"LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)" "LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)"
}) })
/** @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
* Add input wizard subpanel for adding local files / dirs to the case
*/
final class LogicalFilesDspPanel extends JPanel { final class LogicalFilesDspPanel extends JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -35,6 +35,10 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/**
* Dialog to allow the examiner to locate an image when it cannot be found.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class MissingImageDialog extends javax.swing.JDialog { class MissingImageDialog extends javax.swing.JDialog {
private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName()); private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName());
@ -50,7 +54,7 @@ class MissingImageDialog extends javax.swing.JDialog {
} }
static final String allDesc = NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.allDesc.text"); static final String allDesc = NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.allDesc.text");
static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
private JFileChooser fc = new JFileChooser(); private final JFileChooser fc = new JFileChooser();
/** /**
* Instantiate a MissingImageDialog. * Instantiate a MissingImageDialog.

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -28,6 +28,7 @@ import org.openide.windows.WindowManager;
/** /**
* This class extends a JDialog and maintains the MultiUserCasesPanel. * This class extends a JDialog and maintains the MultiUserCasesPanel.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class MultiUserCasesDialog extends JDialog { final class MultiUserCasesDialog extends JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -36,9 +36,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
/** /**
* A panel that allows a user to open cases created by auto ingest. * A panel that allows a user to open cases created by auto ingest.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class MultiUserCasesPanel extends JPanel{ final class MultiUserCasesPanel extends JPanel{
private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName()); private static final Logger logger = Logger.getLogger(MultiUserCasesPanel.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final JDialog parentDialog; private final JDialog parentDialog;
private final CaseBrowser caseBrowserPanel; private final CaseBrowser caseBrowserPanel;
@ -98,7 +99,7 @@ final class MultiUserCasesPanel extends JPanel{
Case.openAsCurrentCase(caseMetadataFilePath); Case.openAsCurrentCase(caseMetadataFilePath);
} catch (CaseActionException ex) { } catch (CaseActionException ex) {
if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) {
LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS
MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage());
} }
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2015 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,9 +18,9 @@
*/ */
package org.sleuthkit.autopsy.casemodule; package org.sleuthkit.autopsy.casemodule;
import java.awt.Component;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import java.awt.*;
import java.io.File; import java.io.File;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JPanel; import javax.swing.JPanel;
@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator;
/** /**
* The JPanel for the first page of the new case wizard. * The JPanel for the first page of the new case wizard.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
private final JFileChooser fileChooser = new JFileChooser(); private final JFileChooser fileChooser = new JFileChooser();

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -16,20 +16,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* NewCaseVisualPanel2.java
*
* Created on Mar 7, 2012, 11:01:48 AM
*/
package org.sleuthkit.autopsy.casemodule; package org.sleuthkit.autopsy.casemodule;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
/** /**
* * The JPanel for the second page of the new case wizard.
* @author dfickling
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class NewCaseVisualPanel2 extends javax.swing.JPanel { final class NewCaseVisualPanel2 extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
/** /**
* Panel used by the the open recent case option of the start window. * Panel used by the the open recent case option of the start window.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class OpenRecentCasePanel extends javax.swing.JPanel { class OpenRecentCasePanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -36,9 +36,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
* Panel which allows for editing and setting of the case details which are * Panel which allows for editing and setting of the case details which are
* optional or otherwise able to be edited. * optional or otherwise able to be edited.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class OptionalCasePropertiesPanel extends javax.swing.JPanel { final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
private final static Logger LOGGER = Logger.getLogger(OptionalCasePropertiesPanel.class.getName()); private final static Logger logger = Logger.getLogger(OptionalCasePropertiesPanel.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private EamOrganization selectedOrg = null; private EamOrganization selectedOrg = null;
private java.util.List<EamOrganization> orgs = null; private java.util.List<EamOrganization> orgs = null;
@ -66,7 +67,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
try { try {
openCase = Case.getCurrentCaseThrows(); openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); logger.log(Level.SEVERE, "Exception while getting open case.", ex);
return; return;
} }
caseDisplayNameTextField.setText(openCase.getDisplayName()); caseDisplayNameTextField.setText(openCase.getDisplayName());
@ -100,9 +101,9 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
selectedOrg = dbManager.getCase(currentCase).getOrg(); selectedOrg = dbManager.getCase(currentCase).getOrg();
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex); logger.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex);
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); logger.log(Level.SEVERE, "Exception while getting open case.", ex);
} }
if (selectedOrg != null) { if (selectedOrg != null) {
@ -145,7 +146,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
}); });
comboBoxOrgName.setSelectedItem(selectedBeforeLoad); comboBoxOrgName.setSelectedItem(selectedBeforeLoad);
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.WARNING, "Unable to populate list of Organizations from Central Repo", ex); logger.log(Level.WARNING, "Unable to populate list of Organizations from Central Repo", ex);
} }
} }
@ -598,9 +599,9 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
correlationCase.setNotes(taNotesText.getText()); correlationCase.setNotes(taNotesText.getText());
dbManager.updateCase(correlationCase); dbManager.updateCase(correlationCase);
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to central repository database", ex); // NON-NLS logger.log(Level.SEVERE, "Error connecting to central repository database", ex); // NON-NLS
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
} finally { } finally {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
} }

View File

@ -1,6 +1,5 @@
OptionsCategory_Name_TagNamesOptions=Tags OptionsCategory_Name_TagNamesOptions=Tags
OptionsCategory_TagNames=TagNames OptionsCategory_TagNames=TagNames
Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0}
TagNameDialog.title.text=New Tag TagNameDialog.title.text=New Tag
TagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; TagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ;
TagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name TagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name

View File

@ -54,7 +54,7 @@ final class TagNameDefinition implements Comparable<TagNameDefinition> {
private static final List<String> STANDARD_TAG_DISPLAY_NAMES = Arrays.asList(Bundle.TagNameDefinition_predefTagNames_bookmark_text(), Bundle.TagNameDefinition_predefTagNames_followUp_text(), private static final List<String> STANDARD_TAG_DISPLAY_NAMES = Arrays.asList(Bundle.TagNameDefinition_predefTagNames_bookmark_text(), Bundle.TagNameDefinition_predefTagNames_followUp_text(),
Bundle.TagNameDefinition_predefTagNames_notableItem_text(), DhsImageCategory.ONE.getDisplayName(), Bundle.TagNameDefinition_predefTagNames_notableItem_text(), DhsImageCategory.ONE.getDisplayName(),
DhsImageCategory.TWO.getDisplayName(), DhsImageCategory.THREE.getDisplayName(), DhsImageCategory.TWO.getDisplayName(), DhsImageCategory.THREE.getDisplayName(),
DhsImageCategory.FOUR.getDisplayName(), DhsImageCategory.FIVE.getDisplayName()); DhsImageCategory.FOUR.getDisplayName(), DhsImageCategory.FIVE.getDisplayName(), DhsImageCategory.ZERO.getDisplayName());
private final String displayName; private final String displayName;
private final String description; private final String description;
private final TagName.HTML_COLOR color; private final TagName.HTML_COLOR color;

View File

@ -19,8 +19,6 @@
package org.sleuthkit.autopsy.casemodule.services; package org.sleuthkit.autopsy.casemodule.services;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import javax.swing.JFrame; import javax.swing.JFrame;
@ -34,6 +32,7 @@ import org.sleuthkit.datamodel.TskData;
@Messages({"TagNameDialog.descriptionLabel.text=Description:", @Messages({"TagNameDialog.descriptionLabel.text=Description:",
"TagNameDialog.notableCheckbox.text=Tag indicates item is notable."}) "TagNameDialog.notableCheckbox.text=Tag indicates item is notable."})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class TagNameDialog extends javax.swing.JDialog { final class TagNameDialog extends javax.swing.JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -27,7 +27,6 @@ import java.util.TreeSet;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.DefaultListModel; import javax.swing.DefaultListModel;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import org.netbeans.spi.options.OptionsPanelController; import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
@ -43,6 +42,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
/** /**
* A panel to allow the user to create and delete custom tag types. * A panel to allow the user to create and delete custom tag types.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -121,6 +121,15 @@ public class TagsManager implements Closeable {
return tagDisplayNames; return tagDisplayNames;
} }
/**
* Returns a list of names of standard/predefined tags
*
* @return list of predefined tag names
*/
public static List<String> getStandardTagNames() {
return TagNameDefinition.getStandardTagNames();
}
/** /**
* Constructs a per case Autopsy service that manages the addition of * Constructs a per case Autopsy service that manages the addition of
* content and artifact tags to the case database. * content and artifact tags to the case database.
@ -157,6 +166,21 @@ public class TagsManager implements Closeable {
return caseDb.getTagNamesInUse(); return caseDb.getTagNamesInUse();
} }
/**
* Selects all of the rows from the tag_names table in the case database for
* which there is at least one matching row in the content_tags or
* blackboard_artifact_tags tables, for the given data source object id.
*
* @param dsObjId data source object id
*
* @return A list, possibly empty, of TagName data transfer objects (DTOs)
* for the rows.
*
* @throws TskCoreException
*/
public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
return caseDb.getTagNamesInUse(dsObjId);
}
/** /**
* Gets a map of tag display names to tag name entries in the case database. * Gets a map of tag display names to tag name entries in the case database.
* It has keys for the display names of the standard tag types, the current * It has keys for the display names of the standard tag types, the current
@ -392,6 +416,24 @@ public class TagsManager implements Closeable {
return caseDb.getContentTagsCountByTagName(tagName); return caseDb.getContentTagsCountByTagName(tagName);
} }
/**
* Gets content tags count by tag name, for the given data source
*
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames and/or addTagName.
*
* @param dsObjId data source object id
*
* @return A count of the content tags with the specified tag name, and for
* the given data source
*
* @throws TskCoreException If there is an error getting the tags count from
* the case database.
*/
public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
return caseDb.getContentTagsCountByTagName(tagName, dsObjId);
}
/** /**
* Gets a content tag by tag id. * Gets a content tag by tag id.
* *
@ -421,6 +463,23 @@ public class TagsManager implements Closeable {
return caseDb.getContentTagsByTagName(tagName); return caseDb.getContentTagsByTagName(tagName);
} }
/**
* Gets content tags by tag name, for the given data source.
*
* @param tagName The tag name of interest.
*
* @param dsObjId data source object id
*
* @return A list, possibly empty, of the content tags with the specified
* tag name, and for the given data source.
*
* @throws TskCoreException If there is an error getting the tags from the
* case database.
*/
public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
return caseDb.getContentTagsByTagName(tagName, dsObjId);
}
/** /**
* Gets content tags count by content. * Gets content tags count by content.
* *
@ -522,6 +581,24 @@ public class TagsManager implements Closeable {
return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); return caseDb.getBlackboardArtifactTagsCountByTagName(tagName);
} }
/**
* Gets an artifact tags count by tag name, for the given data source.
*
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
* @param dsObjId data source object id
*
* @return A count of the artifact tags with the specified tag name,
* for the given data source.
*
* @throws TskCoreException If there is an error getting the tags count from
* the case database.
*/
public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId);
}
/** /**
* Gets an artifact tag by tag id. * Gets an artifact tag by tag id.
* *
@ -553,6 +630,24 @@ public class TagsManager implements Closeable {
return caseDb.getBlackboardArtifactTagsByTagName(tagName); return caseDb.getBlackboardArtifactTagsByTagName(tagName);
} }
/**
* Gets artifact tags by tag name, for specified data source.
*
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
* @param dsObjId data source object id
*
* @return A list, possibly empty, of the artifact tags with the specified
* tag name, for the specified data source.
*
* @throws TskCoreException If there is an error getting the tags from the
* case database.
*/
public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
return caseDb.getBlackboardArtifactTagsByTagName(tagName, dsObjId);
}
/** /**
* Gets artifact tags for a particular artifact. * Gets artifact tags for a particular artifact.
* *

View File

@ -0,0 +1,148 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.centralrepository;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
/**
* An AbstractAction to manage adding and modifying a Central Repository file
* instance comment.
*/
public final class AddEditCentralRepoCommentAction extends AbstractAction {
private static final Logger logger = Logger.getLogger(AddEditCentralRepoCommentAction.class.getName());
private boolean addToDatabase;
private CorrelationAttribute correlationAttribute;
String title;
/**
* Private constructor to create an instance given a CorrelationAttribute.
*
* @param correlationAttribute The correlation attribute to modify.
* @param title The text for the menu item.
*/
private AddEditCentralRepoCommentAction(CorrelationAttribute correlationAttribute, String title) {
super(title);
this.title = title;
this.correlationAttribute = correlationAttribute;
}
/**
* Private constructor to create an instance given an AbstractFile.
*
* @param file The file from which a correlation attribute to modify is
* derived.
* @param title The text for the menu item.
*/
private AddEditCentralRepoCommentAction(AbstractFile file, String title) {
super(title);
this.title = title;
correlationAttribute = EamArtifactUtil.getCorrelationAttributeFromContent(file);
if (correlationAttribute == null) {
addToDatabase = true;
correlationAttribute = EamArtifactUtil.makeCorrelationAttributeFromContent(file);
}
}
@Override
public void actionPerformed(ActionEvent event) {
addEditCentralRepoComment();
}
/**
* Create a Add/Edit dialog for the correlation attribute file instance
* comment. The comment will be updated in the database if the file instance
* exists there, or a new file instance will be added to the database with
* the comment attached otherwise.
*
* The current comment for this instance is returned in case it is needed to
* update the display.
*
* @return the current comment for this instance
*/
public String addEditCentralRepoComment() {
CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title);
centralRepoCommentDialog.display();
if (centralRepoCommentDialog.isCommentUpdated()) {
EamDb dbManager;
try {
dbManager = EamDb.getInstance();
if (addToDatabase) {
dbManager.addArtifact(correlationAttribute);
} else {
dbManager.updateAttributeInstanceComment(correlationAttribute);
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error adding comment", ex);
}
}
return centralRepoCommentDialog.getComment();
}
/**
* Create an instance labeled "Add/Edit Central Repository Comment" given an
* AbstractFile. This is intended for the result view.
*
* @param file The file from which a correlation attribute to modify is
* derived.
*
* @return The instance.
*
* @throws EamDbException
* @throws NoCurrentCaseException
* @throws TskCoreException
*/
@Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoComment=Add/Edit Central Repository Comment"})
public static AddEditCentralRepoCommentAction createAddEditCentralRepoCommentAction(AbstractFile file) {
return new AddEditCentralRepoCommentAction(file,
Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoComment());
}
/**
* Create an instance labeled "Add/Edit Comment" given a
* CorrelationAttribute. This is intended for the content view.
*
* @param correlationAttribute The correlation attribute to modify.
*
* @return The instance.
*/
@Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditComment=Add/Edit Comment"})
public static AddEditCentralRepoCommentAction createAddEditCommentAction(CorrelationAttribute correlationAttribute) {
return new AddEditCentralRepoCommentAction(correlationAttribute,
Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditComment());
}
}

View File

@ -5,3 +5,8 @@ OpenIDE-Module-Long-Description=\
Correlation Engine ingest module and central database. \n\n\ Correlation Engine ingest module and central database. \n\n\
The Correlation Engine ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\ The Correlation Engine ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\
Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest. Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest.
CentralRepoCommentDialog.fileLabel.text=File:
CentralRepoCommentDialog.commentLabel.text=Comment:
CentralRepoCommentDialog.pathLabel.text=
CentralRepoCommentDialog.okButton.text=&OK
CentralRepoCommentDialog.cancelButton.text=C&ancel

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="size" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection component="Form" name="preferredSize" type="property"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<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="jScrollPane1" pref="500" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="fileLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="commentLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="451" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="okButton" min="-2" pref="75" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" pref="75" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="fileLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
<Component id="commentLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="okButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="commentTextArea">
<Properties>
<Property name="columns" type="int" value="20"/>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="5"/>
<Property name="tabSize" type="int" value="4"/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="fileLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.fileLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="pathLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.pathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="commentLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,203 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.centralrepository;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
/**
* Dialog to allow Central Repository file instance comments to be added and
* modified.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class CentralRepoCommentDialog extends javax.swing.JDialog {
private final CorrelationAttribute correlationAttribute;
private boolean commentUpdated = false;
private String currentComment = "";
/**
* Create an instance.
*
* @param correlationAttribute The correlation attribute to be modified.
* @param title The title to assign the dialog.
*/
CentralRepoCommentDialog(CorrelationAttribute correlationAttribute, String title) {
super(WindowManager.getDefault().getMainWindow(), title);
initComponents();
CorrelationAttributeInstance instance = correlationAttribute.getInstances().get(0);
// Store the original comment
if (instance.getComment() != null) {
currentComment = instance.getComment();
}
pathLabel.setText(instance.getFilePath());
commentTextArea.setText(instance.getComment());
this.correlationAttribute = correlationAttribute;
}
/**
* Display the dialog.
*/
void display() {
setModal(true);
setSize(getPreferredSize());
setLocationRelativeTo(this.getParent());
setAlwaysOnTop(false);
pack();
setVisible(true);
}
/**
* Has the comment been updated?
*
* @return True if the comment has been updated; otherwise false.
*/
boolean isCommentUpdated() {
return commentUpdated;
}
/**
* Get the current comment.
* If the user hit OK, this will be the new comment.
* If the user canceled, this will be the original comment.
* @return the comment
*/
String getComment() {
return currentComment;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
commentTextArea = new javax.swing.JTextArea();
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
fileLabel = new javax.swing.JLabel();
pathLabel = new javax.swing.JLabel();
commentLabel = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setSize(getPreferredSize());
commentTextArea.setColumns(20);
commentTextArea.setLineWrap(true);
commentTextArea.setRows(5);
commentTextArea.setTabSize(4);
commentTextArea.setWrapStyleWord(true);
jScrollPane1.setViewportView(commentTextArea);
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(fileLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.fileLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.pathLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.commentLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(fileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pathLabel))
.addComponent(commentLabel))
.addGap(0, 451, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(fileLabel)
.addComponent(pathLabel))
.addGap(19, 19, 19)
.addComponent(commentLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(okButton)
.addComponent(cancelButton))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
currentComment = commentTextArea.getText();
correlationAttribute.getInstances().get(0).setComment(currentComment);
commentUpdated = true;
dispose();
}//GEN-LAST:event_okButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton;
private javax.swing.JLabel commentLabel;
private javax.swing.JTextArea commentTextArea;
private javax.swing.JLabel fileLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton okButton;
private javax.swing.JLabel pathLabel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,56 @@
/*
* Central Repository
*
* Copyright 2018 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.centralrepository;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.Action;
import org.openide.util.Utilities;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider;
import org.sleuthkit.datamodel.AbstractFile;
/**
* This creates a single context menu item for adding or editing a Central
* Repository comment.
*/
@ServiceProvider(service = ContextMenuActionsProvider.class)
public class CentralRepoContextMenuActionsProvider implements ContextMenuActionsProvider {
@Override
public List<Action> getActions() {
ArrayList<Action> actions = new ArrayList<>();
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
if (selectedFiles.size() != 1) {
return actions;
}
for (AbstractFile file : selectedFiles) {
if (EamDbUtil.useCentralRepo() && EamArtifactUtil.isSupportedAbstractFileType(file) && file.isFile()) {
actions.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file));
}
}
return actions;
}
}

View File

@ -3,3 +3,7 @@ DataContentViewerOtherCases.showCaseDetailsMenuItem.text=Show Case Details
DataContentViewerOtherCases.table.toolTip.text=Click column name to sort. Right-click on the table for more options. DataContentViewerOtherCases.table.toolTip.text=Click column name to sort. Right-click on the table for more options.
DataContentViewerOtherCases.exportToCSVMenuItem.text=Export Selected Rows to CSV DataContentViewerOtherCases.exportToCSVMenuItem.text=Export Selected Rows to CSV
DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency
DataContentViewerOtherCases.addCommentMenuItem.text=Add/Edit Comment
DataContentViewerOtherCases.earliestCaseDate.text=Earliest Case Date
DataContentViewerOtherCases.earliestCaseLabel.toolTipText=
DataContentViewerOtherCases.earliestCaseLabel.text=Central Repository Starting Date:

View File

@ -3,6 +3,9 @@
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents> <NonVisualComponents>
<Container class="javax.swing.JPopupMenu" name="rightClickPopupMenu"> <Container class="javax.swing.JPopupMenu" name="rightClickPopupMenu">
<Events>
<EventHandler event="popupMenuWillBecomeVisible" listener="javax.swing.event.PopupMenuListener" parameters="javax.swing.event.PopupMenuEvent" handler="rightClickPopupMenuPopupMenuWillBecomeVisible"/>
</Events>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout"> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
<Property name="useNullLayout" type="boolean" value="true"/> <Property name="useNullLayout" type="boolean" value="true"/>
@ -36,6 +39,13 @@
</Property> </Property>
</Properties> </Properties>
</MenuItem> </MenuItem>
<MenuItem class="javax.swing.JMenuItem" name="addCommentMenuItem">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties" key="DataContentViewerOtherCases.addCommentMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</MenuItem>
</SubComponents> </SubComponents>
</Container> </Container>
<Component class="javax.swing.JFileChooser" name="CSVFileChooser"> <Component class="javax.swing.JFileChooser" name="CSVFileChooser">
@ -70,7 +80,7 @@
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="otherCasesPanel" pref="52" max="32767" attributes="0"/> <Component id="otherCasesPanel" pref="483" max="32767" attributes="0"/>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
@ -93,10 +103,10 @@
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="60" max="32767" attributes="0"/> <EmptySpace min="0" pref="483" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0"> <Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="tableContainerPanel" pref="52" max="32767" attributes="0"/> <Component id="tableContainerPanel" pref="483" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/> <EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
@ -114,17 +124,36 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="tableScrollPane" alignment="1" max="32767" attributes="0"/> <Group type="102" alignment="1" attributes="0">
<Component id="tableStatusPanel" alignment="1" max="32767" attributes="0"/> <Component id="tableStatusPanel" pref="1282" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="218" max="-2" attributes="0"/>
</Group>
<Component id="tableScrollPane" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="earliestCaseLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="earliestCaseDate" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="tableStatusPanelLabel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Component id="tableScrollPane" max="32767" attributes="0"/> <Component id="tableScrollPane" pref="176" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="earliestCaseLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="earliestCaseDate" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="tableStatusPanelLabel" min="-2" pref="16" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="tableStatusPanel" min="-2" max="-2" attributes="0"/> <Component id="tableStatusPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -164,6 +193,23 @@
</Component> </Component>
</SubComponents> </SubComponents>
</Container> </Container>
<Component class="javax.swing.JLabel" name="earliestCaseLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties" key="DataContentViewerOtherCases.earliestCaseLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties" key="DataContentViewerOtherCases.earliestCaseLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="earliestCaseDate">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties" key="DataContentViewerOtherCases.earliestCaseDate.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="tableStatusPanel"> <Container class="javax.swing.JPanel" name="tableStatusPanel">
<Properties> <Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
@ -175,28 +221,15 @@
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="tableStatusPanelLabel" pref="780" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="16" max="32767" attributes="0"/> <EmptySpace min="0" pref="16" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="tableStatusPanelLabel" min="-2" pref="16" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
<SubComponents> </Container>
<Component class="javax.swing.JLabel" name="tableStatusPanelLabel"> <Component class="javax.swing.JLabel" name="tableStatusPanelLabel">
<Properties> <Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> <Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
@ -209,6 +242,4 @@
</SubComponents> </SubComponents>
</Container> </Container>
</SubComponents> </SubComponents>
</Container>
</SubComponents>
</Form> </Form>

View File

@ -18,55 +18,50 @@
*/ */
package org.sleuthkit.autopsy.centralrepository.contentviewer; package org.sleuthkit.autopsy.centralrepository.contentviewer;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.GroupLayout;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.DEFAULT_OPTION; import static javax.swing.JOptionPane.DEFAULT_OPTION;
import static javax.swing.JOptionPane.PLAIN_MESSAGE; import static javax.swing.JOptionPane.PLAIN_MESSAGE;
import static javax.swing.JOptionPane.ERROR_MESSAGE; import static javax.swing.JOptionPane.ERROR_MESSAGE;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.LayoutStyle;
import javax.swing.ListSelectionModel;
import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.TableCellRenderer; import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import org.openide.awt.Mnemonics; import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.AddEditCentralRepoCommentAction;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -76,9 +71,9 @@ import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
/** /**
* View correlation results from other cases * View correlation results from other cases
@ -89,7 +84,9 @@ import org.sleuthkit.datamodel.TskDataException;
"DataContentViewerOtherCases.toolTip=Displays instances of the selected file/artifact from other occurrences.",}) "DataContentViewerOtherCases.toolTip=Displays instances of the selected file/artifact from other occurrences.",})
public class DataContentViewerOtherCases extends JPanel implements DataContentViewer { public class DataContentViewerOtherCases extends JPanel implements DataContentViewer {
private final static Logger LOGGER = Logger.getLogger(DataContentViewerOtherCases.class.getName()); private static final long serialVersionUID = -1L;
private final static Logger logger = Logger.getLogger(DataContentViewerOtherCases.class.getName());
private final DataContentViewerOtherCasesTableModel tableModel; private final DataContentViewerOtherCasesTableModel tableModel;
private final Collection<CorrelationAttribute> correlationAttributes; private final Collection<CorrelationAttribute> correlationAttributes;
@ -123,10 +120,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
try { try {
saveToCSV(); saveToCSV();
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
} }
} else if (jmi.equals(showCommonalityMenuItem)) { } else if (jmi.equals(showCommonalityMenuItem)) {
showCommonalityDetails(); showCommonalityDetails();
} else if (jmi.equals(addCommentMenuItem)) {
try {
OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow());
AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute());
String currentComment = action.addEditCentralRepoComment();
selectedNode.updateComment(currentComment);
otherCasesTable.repaint();
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error performing Add/Edit Comment action", ex);
}
} }
} }
}; };
@ -135,11 +142,13 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
selectAllMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList);
showCaseDetailsMenuItem.addActionListener(actList); showCaseDetailsMenuItem.addActionListener(actList);
showCommonalityMenuItem.addActionListener(actList); showCommonalityMenuItem.addActionListener(actList);
addCommentMenuItem.addActionListener(actList);
// Set background of every nth row as light grey. // Set background of every nth row as light grey.
TableCellRenderer renderer = new DataContentViewerOtherCasesTableCellRenderer(); TableCellRenderer renderer = new DataContentViewerOtherCasesTableCellRenderer();
otherCasesTable.setDefaultRenderer(Object.class, renderer); otherCasesTable.setDefaultRenderer(Object.class, renderer);
tableStatusPanelLabel.setVisible(false); tableStatusPanelLabel.setVisible(false);
} }
@Messages({"DataContentViewerOtherCases.correlatedArtifacts.isEmpty=There are no files or artifacts to correlate.", @Messages({"DataContentViewerOtherCases.correlatedArtifacts.isEmpty=There are no files or artifacts to correlate.",
@ -150,7 +159,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
"DataContentViewerOtherCases.correlatedArtifacts.title=Attribute Frequency", "DataContentViewerOtherCases.correlatedArtifacts.title=Attribute Frequency",
"DataContentViewerOtherCases.correlatedArtifacts.failed=Failed to get frequency details."}) "DataContentViewerOtherCases.correlatedArtifacts.failed=Failed to get frequency details."})
/** /**
* Show how common the selected correlationAttributes are with details dialog. * Show how common the selected correlationAttributes are with details
* dialog.
*/ */
private void showCommonalityDetails() { private void showCommonalityDetails() {
if (correlationAttributes.isEmpty()) { if (correlationAttributes.isEmpty()) {
@ -159,7 +169,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(), Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
DEFAULT_OPTION, PLAIN_MESSAGE); DEFAULT_OPTION, PLAIN_MESSAGE);
} else { } else {
StringBuilder msg = new StringBuilder(); StringBuilder msg = new StringBuilder(correlationAttributes.size());
int percentage; int percentage;
try { try {
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
@ -174,7 +184,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(), Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
DEFAULT_OPTION, PLAIN_MESSAGE); DEFAULT_OPTION, PLAIN_MESSAGE);
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting commonality details.", ex); logger.log(Level.SEVERE, "Error getting commonality details.", ex);
JOptionPane.showConfirmDialog(showCommonalityMenuItem, JOptionPane.showConfirmDialog(showCommonalityMenuItem,
Bundle.DataContentViewerOtherCases_correlatedArtifacts_failed(), Bundle.DataContentViewerOtherCases_correlatedArtifacts_failed(),
Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(), Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
@ -189,23 +199,14 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
"DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error", "DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error",
"DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."}) "DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."})
private void showCaseDetails(int selectedRowViewIdx) { private void showCaseDetails(int selectedRowViewIdx) {
Case openCase;
try {
openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(),
Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(),
DEFAULT_OPTION, PLAIN_MESSAGE);
return;
}
String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError(); String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
try { try {
if (-1 != selectedRowViewIdx) { if (-1 != selectedRowViewIdx) {
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx); int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx);
CorrelationAttribute eamArtifact = (CorrelationAttribute) tableModel.getRow(selectedRowModelIdx); OtherOccurrenceNodeData nodeData = (OtherOccurrenceNodeData) tableModel.getRow(selectedRowModelIdx);
CorrelationCase eamCasePartial = eamArtifact.getInstances().get(0).getCorrelationCase(); CorrelationCase eamCasePartial = nodeData.getCorrelationAttributeInstance().getCorrelationCase();
if (eamCasePartial == null) { if (eamCasePartial == null) {
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(), Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(),
@ -215,7 +216,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} }
caseDisplayName = eamCasePartial.getDisplayName(); caseDisplayName = eamCasePartial.getDisplayName();
// query case details // query case details
CorrelationCase eamCase = dbManager.getCase(openCase); CorrelationCase eamCase = dbManager.getCaseByUUID(eamCasePartial.getCaseUUID());
if (eamCase == null) { if (eamCase == null) {
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(), Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
@ -236,6 +237,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
DEFAULT_OPTION, PLAIN_MESSAGE); DEFAULT_OPTION, PLAIN_MESSAGE);
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error loading case details", ex);
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(), Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
caseDisplayName, caseDisplayName,
@ -298,7 +300,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} }
} catch (IOException ex) { } catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Error writing selected rows to CSV.", ex); logger.log(Level.SEVERE, "Error writing selected rows to CSV.", ex);
} }
} }
@ -309,6 +311,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// start with empty table // start with empty table
tableModel.clearTable(); tableModel.clearTable();
correlationAttributes.clear(); correlationAttributes.clear();
earliestCaseDate.setText(Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable());
} }
@Override @Override
@ -389,7 +392,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
try { try {
content = nodeBbArtifact.getSleuthkitCase().getContentById(nodeBbArtifact.getObjectID()); content = nodeBbArtifact.getSleuthkitCase().getContentById(nodeBbArtifact.getObjectID());
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error retrieving blackboard artifact", ex); // NON-NLS logger.log(Level.SEVERE, "Error retrieving blackboard artifact", ex); // NON-NLS
return null; return null;
} }
@ -435,7 +438,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} }
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS logger.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
} }
} else { } else {
@ -448,65 +451,123 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} }
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS logger.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
} }
} }
return ret; return ret;
} }
@Messages({"DataContentViewerOtherCases.earliestCaseNotAvailable= Not Enabled."})
/** /**
* Query the db for artifact instances from other cases correlated to the * Gets the list of Eam Cases and determines the earliest case creation date.
* given central repository artifact. Will not show instances from the same * Sets the label to display the earliest date string to the user.
* datasource / device */
private void setEarliestCaseDate() {
String dateStringDisplay = Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable();
if (EamDb.isEnabled()) {
LocalDateTime earliestDate = LocalDateTime.now(DateTimeZone.UTC);
DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US);
try {
EamDb dbManager = EamDb.getInstance();
List<CorrelationCase> cases = dbManager.getCases();
for (CorrelationCase aCase : cases) {
LocalDateTime caseDate = LocalDateTime.fromDateFields(datetimeFormat.parse(aCase.getCreationDate()));
if (caseDate.isBefore(earliestDate)) {
earliestDate = caseDate;
dateStringDisplay = aCase.getCreationDate();
}
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
} catch (ParseException ex) {
logger.log(Level.SEVERE, "Error parsing date of cases from database.", ex); // NON-NLS
}
}
earliestCaseDate.setText(dateStringDisplay);
}
/**
* Query the central repo database (if enabled) and the case database to find all
* artifact instances correlated to the given central repository artifact. If the
* central repo is not enabled, this will only return files from the current case
* with matching MD5 hashes.
* *
* @param corAttr CorrelationAttribute to query for * @param corAttr CorrelationAttribute to query for
* @param dataSourceName Data source to filter results * @param dataSourceName Data source to filter results
* @param deviceId Device Id to filter results * @param deviceId Device Id to filter results
* *
* @return A collection of correlated artifact instances from other cases * @return A collection of correlated artifact instances
*/ */
private Map<UniquePathKey,CorrelationAttributeInstance> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { private Map<UniquePathKey,OtherOccurrenceNodeData> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
// @@@ Check exception // @@@ Check exception
try { try {
final Case openCase = Case.getCurrentCase(); final Case openCase = Case.getCurrentCase();
String caseUUID = openCase.getName(); String caseUUID = openCase.getName();
HashMap<UniquePathKey,CorrelationAttributeInstance> artifactInstances = new HashMap<>();
HashMap<UniquePathKey,OtherOccurrenceNodeData> nodeDataMap = new HashMap<>();
if (EamDb.isEnabled()) { if (EamDb.isEnabled()) {
EamDb dbManager = EamDb.getInstance(); List<CorrelationAttributeInstance> instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue());
artifactInstances.putAll(dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream()
.filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) for (CorrelationAttributeInstance artifactInstance:instances) {
// Only add the attribute if it isn't the object the user selected.
// We consider it to be a different object if at least one of the following is true:
// - the case UUID is different
// - the data source name is different
// - the data source device ID is different
// - the file path is different
if (!artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
|| !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName) || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
|| !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)) || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)
.collect(Collectors.toMap(correlationAttr -> new UniquePathKey(correlationAttr.getCorrelationDataSource().getDeviceID(), correlationAttr.getFilePath()), || !artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName())) {
correlationAttr -> correlationAttr)));
OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
UniquePathKey uniquePathKey = new UniquePathKey(newNode);
nodeDataMap.put(uniquePathKey, newNode);
}
}
} }
if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { if (corAttr.getCorrelationType().getDisplayName().equals("Files")) {
List<AbstractFile> caseDbFiles = addCaseDbMatches(corAttr, openCase); List<AbstractFile> caseDbFiles = getCaseDbMatches(corAttr, openCase);
for (AbstractFile caseDbFile : caseDbFiles) { for (AbstractFile caseDbFile : caseDbFiles) {
addOrUpdateAttributeInstance(openCase, artifactInstances, caseDbFile); addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile);
} }
} }
return artifactInstances; return nodeDataMap;
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS logger.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
// do nothing. // do nothing.
// @@@ Review this behavior // @@@ Review this behavior
LOGGER.log(Level.SEVERE, "Exception while querying open case.", ex); // NON-NLS logger.log(Level.SEVERE, "Exception while querying open case.", ex); // NON-NLS
} }
return new HashMap<>(0); return new HashMap<>(0);
} }
private List<AbstractFile> addCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { /**
* Get all other abstract files in the current case with the same MD5 as the selected node.
* @param corAttr The CorrelationAttribute containing the MD5 to search for
* @param openCase The current case
* @return List of matching AbstractFile objects
* @throws NoCurrentCaseException
* @throws TskCoreException
* @throws EamDbException
*/
private List<AbstractFile> getCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException {
String md5 = corAttr.getCorrelationValue(); String md5 = corAttr.getCorrelationValue();
SleuthkitCase tsk = openCase.getSleuthkitCase(); SleuthkitCase tsk = openCase.getSleuthkitCase();
List<AbstractFile> matches = tsk.findAllFilesWhere(String.format("md5 = '%s'", new Object[]{md5})); List<AbstractFile> matches = tsk.findAllFilesWhere(String.format("md5 = '%s'", new Object[]{md5}));
@ -522,75 +583,64 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} }
/** /**
* Adds the file to the artifactInstances map if it does not already exist * Adds the file to the nodeDataMap map if it does not already exist
* *
* @param autopsyCase * @param autopsyCase
* @param artifactInstances * @param nodeDataMap
* @param newFile * @param newFile
*
* @throws TskCoreException * @throws TskCoreException
* @throws EamDbException * @throws EamDbException
*/ */
private void addOrUpdateAttributeInstance(final Case autopsyCase, Map<UniquePathKey,CorrelationAttributeInstance> artifactInstances, AbstractFile newFile) throws TskCoreException, EamDbException { private void addOrUpdateNodeData(final Case autopsyCase, Map<UniquePathKey,OtherOccurrenceNodeData> nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException {
// figure out if the casedb file is known via either hash or tags OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(newFile, autopsyCase);
TskData.FileKnown localKnown = newFile.getKnown();
if (localKnown != TskData.FileKnown.BAD) { // If the caseDB object has a notable tag associated with it, update
// the known status to BAD
if (newNode.getKnown() != TskData.FileKnown.BAD) {
List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile); List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile);
for (ContentTag tag : fileMatchTags) { for (ContentTag tag : fileMatchTags) {
TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus(); TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus();
if (tagKnownStatus.equals(TskData.FileKnown.BAD)) { if (tagKnownStatus.equals(TskData.FileKnown.BAD)) {
localKnown = TskData.FileKnown.BAD; newNode.updateKnown(TskData.FileKnown.BAD);
break; break;
} }
} }
} }
// make a key to see if the file is already in the map // Make a key to see if the file is already in the map
String filePath = newFile.getParentPath() + newFile.getName(); UniquePathKey uniquePathKey = new UniquePathKey(newNode);
String deviceId;
try {
deviceId = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()).getDeviceId();
} catch (TskDataException | TskCoreException ex) {
LOGGER.log(Level.WARNING, "Error getting data source info: " + ex);
return;
}
UniquePathKey uniquePathKey = new UniquePathKey(deviceId, filePath);
// double check that the CR version is BAD if the caseDB version is BAD. // If this node is already in the list, the only thing we need to do is
if (artifactInstances.containsKey(uniquePathKey)) { // update the known status to BAD if the caseDB version had known status BAD.
if (localKnown == TskData.FileKnown.BAD) { // Otherwise this is a new node so add the new node to the map.
CorrelationAttributeInstance prevInstance = artifactInstances.get(uniquePathKey); if (nodeDataMap.containsKey(uniquePathKey)) {
prevInstance.setKnownStatus(localKnown); if (newNode.getKnown() == TskData.FileKnown.BAD) {
OtherOccurrenceNodeData prevInstance = nodeDataMap.get(uniquePathKey);
prevInstance.updateKnown(newNode.getKnown());
} }
} } else {
// add the data from the case DB by pushing data into CorrelationAttributeInstance class nodeDataMap.put(uniquePathKey, newNode);
else {
// NOTE: If we are in here, it is likely because CR is not enabled. So, we cannot rely
// on any of the methods that query the DB.
CorrelationCase correlationCase = new CorrelationCase(autopsyCase.getName(), autopsyCase.getDisplayName());
CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, newFile.getDataSource());
CorrelationAttributeInstance caseDbInstance = new CorrelationAttributeInstance(correlationCase, correlationDataSource, filePath, "", localKnown);
artifactInstances.put(uniquePathKey, caseDbInstance);
} }
} }
@Override @Override
public boolean isSupported(Node node) { public boolean isSupported(Node node) {
this.file = this.getAbstractFileFromNode(node);
// Is supported if this node
// has correlatable content (File, BlackboardArtifact) OR
// other common files across datasources.
// Is supported if one of the following is true:
// - The central repo is enabled and the node has correlatable content
// (either through the MD5 hash of the associated file or through a BlackboardArtifact)
// - The central repo is disabled and the backing file has a valid MD5 hash
this.file = this.getAbstractFileFromNode(node);
if (EamDb.isEnabled()) { if (EamDb.isEnabled()) {
return this.file != null return this.file != null
&& this.file.getSize() > 0 && this.file.getSize() > 0
&& !getCorrelationAttributesFromNode(node).isEmpty(); && !getCorrelationAttributesFromNode(node).isEmpty();
} else { } else {
return this.file != null return this.file != null
&& this.file.getSize() > 0; && this.file.getSize() > 0
&& ((this.file.getMd5Hash() != null) && ( ! this.file.getMd5Hash().isEmpty()));
} }
} }
@ -632,22 +682,14 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// get the attributes we can correlate on // get the attributes we can correlate on
correlationAttributes.addAll(getCorrelationAttributesFromNode(node)); correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
for (CorrelationAttribute corAttr : correlationAttributes) { for (CorrelationAttribute corAttr : correlationAttributes) {
Map<UniquePathKey, CorrelationAttributeInstance> corAttrInstances = new HashMap<>(0); Map<UniquePathKey,OtherOccurrenceNodeData> correlatedNodeDataMap = new HashMap<>(0);
// get correlation and reference set instances from DB // get correlation and reference set instances from DB
corAttrInstances.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
correlatedNodeDataMap.values().forEach((nodeData) -> {
tableModel.addNodeData(nodeData);
corAttrInstances.values().forEach((corAttrInstance) -> {
try {
CorrelationAttribute newCeArtifact = new CorrelationAttribute(
corAttr.getCorrelationType(),
corAttr.getCorrelationValue()
);
newCeArtifact.addInstance(corAttrInstance);
tableModel.addEamArtifact(newCeArtifact);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error creating correlation attribute", ex);
}
}); });
} }
@ -660,6 +702,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
clearMessageOnTableStatusPanel(); clearMessageOnTableStatusPanel();
setColumnWidths(); setColumnWidths();
} }
setEarliestCaseDate();
} }
private void setColumnWidths() { private void setColumnWidths() {
@ -690,159 +733,206 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
rightClickPopupMenu = new JPopupMenu(); rightClickPopupMenu = new javax.swing.JPopupMenu();
selectAllMenuItem = new JMenuItem(); selectAllMenuItem = new javax.swing.JMenuItem();
exportToCSVMenuItem = new JMenuItem(); exportToCSVMenuItem = new javax.swing.JMenuItem();
showCaseDetailsMenuItem = new JMenuItem(); showCaseDetailsMenuItem = new javax.swing.JMenuItem();
showCommonalityMenuItem = new JMenuItem(); showCommonalityMenuItem = new javax.swing.JMenuItem();
CSVFileChooser = new JFileChooser(); addCommentMenuItem = new javax.swing.JMenuItem();
otherCasesPanel = new JPanel(); CSVFileChooser = new javax.swing.JFileChooser();
tableContainerPanel = new JPanel(); otherCasesPanel = new javax.swing.JPanel();
tableScrollPane = new JScrollPane(); tableContainerPanel = new javax.swing.JPanel();
otherCasesTable = new JTable(); tableScrollPane = new javax.swing.JScrollPane();
tableStatusPanel = new JPanel(); otherCasesTable = new javax.swing.JTable();
tableStatusPanelLabel = new JLabel(); earliestCaseLabel = new javax.swing.JLabel();
earliestCaseDate = new javax.swing.JLabel();
tableStatusPanel = new javax.swing.JPanel();
tableStatusPanelLabel = new javax.swing.JLabel();
Mnemonics.setLocalizedText(selectAllMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
}
public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
}
public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
rightClickPopupMenuPopupMenuWillBecomeVisible(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N
rightClickPopupMenu.add(selectAllMenuItem); rightClickPopupMenu.add(selectAllMenuItem);
Mnemonics.setLocalizedText(exportToCSVMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N
rightClickPopupMenu.add(exportToCSVMenuItem); rightClickPopupMenu.add(exportToCSVMenuItem);
Mnemonics.setLocalizedText(showCaseDetailsMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N
rightClickPopupMenu.add(showCaseDetailsMenuItem); rightClickPopupMenu.add(showCaseDetailsMenuItem);
Mnemonics.setLocalizedText(showCommonalityMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N
rightClickPopupMenu.add(showCommonalityMenuItem); rightClickPopupMenu.add(showCommonalityMenuItem);
setMinimumSize(new Dimension(1500, 10)); org.openide.awt.Mnemonics.setLocalizedText(addCommentMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.addCommentMenuItem.text")); // NOI18N
rightClickPopupMenu.add(addCommentMenuItem);
setMinimumSize(new java.awt.Dimension(1500, 10));
setOpaque(false); setOpaque(false);
setPreferredSize(new Dimension(1500, 44)); setPreferredSize(new java.awt.Dimension(1500, 44));
otherCasesPanel.setPreferredSize(new Dimension(1500, 144)); otherCasesPanel.setPreferredSize(new java.awt.Dimension(1500, 144));
tableContainerPanel.setPreferredSize(new Dimension(1500, 63)); tableContainerPanel.setPreferredSize(new java.awt.Dimension(1500, 63));
tableScrollPane.setPreferredSize(new Dimension(1500, 30)); tableScrollPane.setPreferredSize(new java.awt.Dimension(1500, 30));
otherCasesTable.setAutoCreateRowSorter(true); otherCasesTable.setAutoCreateRowSorter(true);
otherCasesTable.setModel(tableModel); otherCasesTable.setModel(tableModel);
otherCasesTable.setToolTipText(NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N otherCasesTable.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N
otherCasesTable.setComponentPopupMenu(rightClickPopupMenu); otherCasesTable.setComponentPopupMenu(rightClickPopupMenu);
otherCasesTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); otherCasesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
tableScrollPane.setViewportView(otherCasesTable); tableScrollPane.setViewportView(otherCasesTable);
tableStatusPanel.setPreferredSize(new Dimension(1500, 16)); org.openide.awt.Mnemonics.setLocalizedText(earliestCaseLabel, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseLabel.text")); // NOI18N
earliestCaseLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseLabel.toolTipText")); // NOI18N
tableStatusPanelLabel.setForeground(new Color(255, 0, 51)); org.openide.awt.Mnemonics.setLocalizedText(earliestCaseDate, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseDate.text")); // NOI18N
GroupLayout tableStatusPanelLayout = new GroupLayout(tableStatusPanel); tableStatusPanel.setPreferredSize(new java.awt.Dimension(1500, 16));
javax.swing.GroupLayout tableStatusPanelLayout = new javax.swing.GroupLayout(tableStatusPanel);
tableStatusPanel.setLayout(tableStatusPanelLayout); tableStatusPanel.setLayout(tableStatusPanelLayout);
tableStatusPanelLayout.setHorizontalGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) tableStatusPanelLayout.setHorizontalGroup(
tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE) .addGap(0, 0, Short.MAX_VALUE)
.addGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(tableStatusPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(tableStatusPanelLabel, GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
.addContainerGap()))
); );
tableStatusPanelLayout.setVerticalGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) tableStatusPanelLayout.setVerticalGroup(
tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 16, Short.MAX_VALUE) .addGap(0, 16, Short.MAX_VALUE)
.addGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(tableStatusPanelLayout.createSequentialGroup()
.addComponent(tableStatusPanelLabel, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE)))
); );
GroupLayout tableContainerPanelLayout = new GroupLayout(tableContainerPanel); tableStatusPanelLabel.setForeground(new java.awt.Color(255, 0, 51));
javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel);
tableContainerPanel.setLayout(tableContainerPanelLayout); tableContainerPanel.setLayout(tableContainerPanelLayout);
tableContainerPanelLayout.setHorizontalGroup(tableContainerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) tableContainerPanelLayout.setHorizontalGroup(
.addComponent(tableScrollPane, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tableStatusPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup()
); .addComponent(tableStatusPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1282, Short.MAX_VALUE)
tableContainerPanelLayout.setVerticalGroup(tableContainerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGap(218, 218, 218))
.addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(tableContainerPanelLayout.createSequentialGroup() .addGroup(tableContainerPanelLayout.createSequentialGroup()
.addComponent(tableScrollPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(earliestCaseLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tableStatusPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(earliestCaseDate)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap()) .addContainerGap())
); );
tableContainerPanelLayout.setVerticalGroup(
GroupLayout otherCasesPanelLayout = new GroupLayout(otherCasesPanel); tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
otherCasesPanel.setLayout(otherCasesPanelLayout); .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup()
otherCasesPanelLayout.setHorizontalGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 176, Short.MAX_VALUE)
.addGap(0, 1500, Short.MAX_VALUE) .addGap(0, 0, 0)
.addGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(tableContainerPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(earliestCaseLabel)
.addComponent(earliestCaseDate))
.addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, 0)
.addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0))
); );
otherCasesPanelLayout.setVerticalGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGap(0, 60, Short.MAX_VALUE) javax.swing.GroupLayout otherCasesPanelLayout = new javax.swing.GroupLayout(otherCasesPanel);
.addGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) otherCasesPanel.setLayout(otherCasesPanelLayout);
otherCasesPanelLayout.setHorizontalGroup(
otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1500, Short.MAX_VALUE)
.addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tableContainerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
otherCasesPanelLayout.setVerticalGroup(
otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 483, Short.MAX_VALUE)
.addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(otherCasesPanelLayout.createSequentialGroup() .addGroup(otherCasesPanelLayout.createSequentialGroup()
.addComponent(tableContainerPanel, GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE) .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 483, Short.MAX_VALUE)
.addGap(0, 0, 0))) .addGap(0, 0, 0)))
); );
GroupLayout layout = new GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) layout.setHorizontalGroup(
.addComponent(otherCasesPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
); );
layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) layout.setVerticalGroup(
.addComponent(otherCasesPanel, GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 483, Short.MAX_VALUE)
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
boolean enableCentralRepoActions = false;
if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) {
int rowIndex = otherCasesTable.getSelectedRow();
OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex);
if (selectedNode.isCentralRepoNode()) {
enableCentralRepoActions = true;
}
}
addCommentMenuItem.setVisible(enableCentralRepoActions);
showCaseDetailsMenuItem.setVisible(enableCentralRepoActions);
showCommonalityMenuItem.setVisible(enableCentralRepoActions);
}//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private JFileChooser CSVFileChooser; private javax.swing.JFileChooser CSVFileChooser;
private JMenuItem exportToCSVMenuItem; private javax.swing.JMenuItem addCommentMenuItem;
private JPanel otherCasesPanel; private javax.swing.JLabel earliestCaseDate;
private JTable otherCasesTable; private javax.swing.JLabel earliestCaseLabel;
private JPopupMenu rightClickPopupMenu; private javax.swing.JMenuItem exportToCSVMenuItem;
private JMenuItem selectAllMenuItem; private javax.swing.JPanel otherCasesPanel;
private JMenuItem showCaseDetailsMenuItem; private javax.swing.JTable otherCasesTable;
private JMenuItem showCommonalityMenuItem; private javax.swing.JPopupMenu rightClickPopupMenu;
private JPanel tableContainerPanel; private javax.swing.JMenuItem selectAllMenuItem;
private JScrollPane tableScrollPane; private javax.swing.JMenuItem showCaseDetailsMenuItem;
private JPanel tableStatusPanel; private javax.swing.JMenuItem showCommonalityMenuItem;
private JLabel tableStatusPanelLabel; private javax.swing.JPanel tableContainerPanel;
private javax.swing.JScrollPane tableScrollPane;
private javax.swing.JPanel tableStatusPanel;
private javax.swing.JLabel tableStatusPanelLabel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
/** /**
* Used as a key to ensure we eliminate duplicates from the result set by not overwriting CR correlation instances. * Used as a key to ensure we eliminate duplicates from the result set by
* not overwriting CR correlation instances.
*/ */
static final class UniquePathKey { static final class UniquePathKey {
private final String dataSourceID; private final String dataSourceID;
private final String filePath; private final String filePath;
private final String type;
UniquePathKey(String theDataSource, String theFilePath) { UniquePathKey(OtherOccurrenceNodeData nodeData) {
super(); super();
dataSourceID = theDataSource; dataSourceID = nodeData.getDeviceID();
filePath = theFilePath.toLowerCase(); if (nodeData.getFilePath() != null) {
filePath = nodeData.getFilePath().toLowerCase();
} else {
filePath = null;
} }
type = nodeData.getType();
/**
*
* @return the dataSourceID device ID
*/
String getDataSourceID() {
return dataSourceID;
}
/**
*
* @return the filPath including the filename and extension.
*/
String getFilePath() {
return filePath;
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (other instanceof UniquePathKey) { if (other instanceof UniquePathKey) {
return ((UniquePathKey) other).getDataSourceID().equals(dataSourceID) && ((UniquePathKey) other).getFilePath().equals(filePath); UniquePathKey otherKey = (UniquePathKey)(other);
return ( Objects.equals(otherKey.dataSourceID, this.dataSourceID)
&& Objects.equals(otherKey.filePath, this.filePath)
&& Objects.equals(otherKey.type, this.type));
} }
return false; return false;
} }
@ -852,7 +942,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
//int hash = 7; //int hash = 7;
//hash = 67 * hash + this.dataSourceID.hashCode(); //hash = 67 * hash + this.dataSourceID.hashCode();
//hash = 67 * hash + this.filePath.hashCode(); //hash = 67 * hash + this.filePath.hashCode();
return Objects.hash(dataSourceID, filePath); return Objects.hash(dataSourceID, filePath, type);
} }
} }

View File

@ -68,10 +68,10 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
} }
}; };
List<CorrelationAttribute> eamArtifacts; List<OtherOccurrenceNodeData> nodeDataList;
DataContentViewerOtherCasesTableModel() { DataContentViewerOtherCasesTableModel() {
eamArtifacts = new ArrayList<>(); nodeDataList = new ArrayList<>();
} }
@Override @Override
@ -95,7 +95,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
@Override @Override
public int getRowCount() { public int getRowCount() {
return eamArtifacts.size(); return nodeDataList.size();
} }
@Override @Override
@ -105,15 +105,15 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
@Override @Override
public Object getValueAt(int rowIdx, int colIdx) { public Object getValueAt(int rowIdx, int colIdx) {
if (0 == eamArtifacts.size()) { if (0 == nodeDataList.size()) {
return Bundle.DataContentViewerOtherCasesTableModel_noData(); return Bundle.DataContentViewerOtherCasesTableModel_noData();
} }
return mapValueById(rowIdx, TableColumns.values()[colIdx]); return mapValueById(rowIdx, TableColumns.values()[colIdx]);
} }
public Object getRow(int rowIdx) { Object getRow(int rowIdx) {
return eamArtifacts.get(rowIdx); return nodeDataList.get(rowIdx);
} }
/** /**
@ -125,40 +125,39 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
* @return value in the cell * @return value in the cell
*/ */
private Object mapValueById(int rowIdx, TableColumns colId) { private Object mapValueById(int rowIdx, TableColumns colId) {
CorrelationAttribute eamArtifact = eamArtifacts.get(rowIdx); OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx);
CorrelationAttributeInstance eamArtifactInstance = eamArtifact.getInstances().get(0);
String value = Bundle.DataContentViewerOtherCasesTableModel_noData(); String value = Bundle.DataContentViewerOtherCasesTableModel_noData();
switch (colId) { switch (colId) {
case CASE_NAME: case CASE_NAME:
if (null != eamArtifactInstance.getCorrelationCase()) { if (null != nodeData.getCaseName()) {
value = eamArtifactInstance.getCorrelationCase().getDisplayName(); value = nodeData.getCaseName();
} }
break; break;
case DEVICE: case DEVICE:
if (null != eamArtifactInstance.getCorrelationDataSource()) { if (null != nodeData.getDeviceID()) {
value = eamArtifactInstance.getCorrelationDataSource().getDeviceID(); value = nodeData.getDeviceID();
} }
break; break;
case DATA_SOURCE: case DATA_SOURCE:
if (null != eamArtifactInstance.getCorrelationDataSource()) { if (null != nodeData.getDataSourceName()) {
value = eamArtifactInstance.getCorrelationDataSource().getName(); value = nodeData.getDataSourceName();
} }
break; break;
case FILE_PATH: case FILE_PATH:
value = eamArtifactInstance.getFilePath(); value = nodeData.getFilePath();
break; break;
case TYPE: case TYPE:
value = eamArtifact.getCorrelationType().getDisplayName(); value = nodeData.getType();
break; break;
case VALUE: case VALUE:
value = eamArtifact.getCorrelationValue(); value = nodeData.getValue();
break; break;
case KNOWN: case KNOWN:
value = eamArtifactInstance.getKnownStatus().getName(); value = nodeData.getKnown().getName();
break; break;
case COMMENT: case COMMENT:
value = eamArtifactInstance.getComment(); value = nodeData.getComment();
break; break;
} }
return value; return value;
@ -170,18 +169,17 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
} }
/** /**
* Add one local central repository artifact to the table. * Add one correlated instance object to the table
* *
* @param eamArtifact central repository artifact to add to the * @param newNodeData data to add to the table
* table
*/ */
public void addEamArtifact(CorrelationAttribute eamArtifact) { void addNodeData(OtherOccurrenceNodeData newNodeData) {
eamArtifacts.add(eamArtifact); nodeDataList.add(newNodeData);
fireTableDataChanged(); fireTableDataChanged();
} }
public void clearTable() { void clearTable() {
eamArtifacts.clear(); nodeDataList.clear();
fireTableDataChanged(); fireTableDataChanged();
} }

View File

@ -0,0 +1,233 @@
/*
* Central Repository
*
* Copyright 2018 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.centralrepository.contentviewer;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
/**
* Class for populating the Other Occurrences tab
*/
class OtherOccurrenceNodeData {
// For now hard code the string for the central repo files type, since
// getting it dynamically can fail.
private static final String FILE_TYPE_STR = "Files";
private final String caseName;
private String deviceID;
private String dataSourceName;
private final String filePath;
private final String typeStr;
private final CorrelationAttribute.Type type;
private final String value;
private TskData.FileKnown known;
private String comment;
private AbstractFile originalAbstractFile = null;
private CorrelationAttributeInstance originalCorrelationInstance = null;
/**
* Create a node from a central repo instance.
* @param instance The central repo instance
* @param type The type of the instance
* @param value The value of the instance
*/
OtherOccurrenceNodeData(CorrelationAttributeInstance instance, CorrelationAttribute.Type type, String value) {
caseName = instance.getCorrelationCase().getDisplayName();
deviceID = instance.getCorrelationDataSource().getDeviceID();
dataSourceName = instance.getCorrelationDataSource().getName();
filePath = instance.getFilePath();
this.typeStr = type.getDisplayName();
this.type = type;
this.value = value;
known = instance.getKnownStatus();
comment = instance.getComment();
originalCorrelationInstance = instance;
}
/**
* Create a node from an abstract file.
* @param newFile The abstract file
* @param autopsyCase The current case
* @throws EamDbException
*/
OtherOccurrenceNodeData(AbstractFile newFile, Case autopsyCase) throws EamDbException {
caseName = autopsyCase.getDisplayName();
try {
DataSource dataSource = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId());
deviceID = dataSource.getDeviceId();
dataSourceName = dataSource.getName();
} catch (TskDataException | TskCoreException ex) {
throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId(), ex);
}
filePath = newFile.getParentPath() + newFile.getName();
typeStr = FILE_TYPE_STR;
this.type = null;
value = newFile.getMd5Hash();
known = newFile.getKnown();
comment = "";
originalAbstractFile = newFile;
}
/**
* Check if this node is a "file" type
* @return true if it is a file type
*/
boolean isFileType() {
return FILE_TYPE_STR.equals(typeStr);
}
/**
* Update the known status for this node
* @param newKnownStatus The new known status
*/
void updateKnown(TskData.FileKnown newKnownStatus) {
known = newKnownStatus;
}
/**
* Update the comment for this node
* @param newComment The new comment
*/
void updateComment(String newComment) {
comment = newComment;
}
/**
* Check if this is a central repo node.
* @return true if this node was created from a central repo instance, false otherwise
*/
boolean isCentralRepoNode() {
return (originalCorrelationInstance != null);
}
/**
* Uses the saved instance plus type and value to make a new CorrelationAttribute.
* Should only be called if isCentralRepoNode() is true.
* @return the newly created CorrelationAttribute
*/
CorrelationAttribute createCorrelationAttribute() throws EamDbException {
if (! isCentralRepoNode() ) {
throw new EamDbException("Can not create CorrelationAttribute for non central repo node");
}
CorrelationAttribute attr = new CorrelationAttribute(type, value);
attr.addInstance(originalCorrelationInstance);
return attr;
}
/**
* Get the case name
* @return the case name
*/
String getCaseName() {
return caseName;
}
/**
* Get the device ID
* @return the device ID
*/
String getDeviceID() {
return deviceID;
}
/**
* Get the data source name
* @return the data source name
*/
String getDataSourceName() {
return dataSourceName;
}
/**
* Get the file path
* @return the file path
*/
String getFilePath() {
return filePath;
}
/**
* Get the type (as a string)
* @return the type
*/
String getType() {
return typeStr;
}
/**
* Get the value (MD5 hash for files)
* @return the value
*/
String getValue() {
return value;
}
/**
* Get the known status
* @return the known status
*/
TskData.FileKnown getKnown() {
return known;
}
/**
* Get the comment
* @return the comment
*/
String getComment() {
return comment;
}
/**
* Get the backing abstract file.
* Should only be called if isCentralRepoNode() is false
* @return the original abstract file
*/
AbstractFile getAbstractFile() throws EamDbException {
if (originalCorrelationInstance == null) {
throw new EamDbException("AbstractFile is null");
}
return originalAbstractFile;
}
/**
* Get the backing CorrelationAttributeInstance.
* Should only be called if isCentralRepoNode() is true
* @return the original CorrelationAttributeInstance
* @throws EamDbException
*/
CorrelationAttributeInstance getCorrelationAttributeInstance() throws EamDbException {
if (originalCorrelationInstance == null) {
throw new EamDbException("CorrelationAttributeInstance is null");
}
return originalCorrelationInstance;
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2017 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -24,8 +24,8 @@ import org.sleuthkit.datamodel.TskData;
/** /**
* *
* Used to store details about a specific instance of a * Used to store details about a specific instance of a CorrelationAttribute.
* CorrelationAttribute. Includes its data source, path, etc. * Includes its data source, path, etc.
* *
*/ */
@Messages({ @Messages({
@ -43,13 +43,6 @@ public class CorrelationAttributeInstance implements Serializable {
private String comment; private String comment;
private TskData.FileKnown knownStatus; private TskData.FileKnown knownStatus;
public CorrelationAttributeInstance(
CorrelationCase eamCase,
CorrelationDataSource eamDataSource
) throws EamDbException {
this(-1, eamCase, eamDataSource, "", null, TskData.FileKnown.UNKNOWN);
}
public CorrelationAttributeInstance( public CorrelationAttributeInstance(
CorrelationCase eamCase, CorrelationCase eamCase,
CorrelationDataSource eamDataSource, CorrelationDataSource eamDataSource,
@ -58,14 +51,6 @@ public class CorrelationAttributeInstance implements Serializable {
this(-1, eamCase, eamDataSource, filePath, null, TskData.FileKnown.UNKNOWN); this(-1, eamCase, eamDataSource, filePath, null, TskData.FileKnown.UNKNOWN);
} }
public CorrelationAttributeInstance(
CorrelationCase eamCase,
CorrelationDataSource eamDataSource,
String filePath,
String comment
) throws EamDbException {
this(-1, eamCase, eamDataSource, filePath, comment, TskData.FileKnown.UNKNOWN);
}
public CorrelationAttributeInstance( public CorrelationAttributeInstance(
CorrelationCase eamCase, CorrelationCase eamCase,
@ -117,6 +102,16 @@ public class CorrelationAttributeInstance implements Serializable {
+ this.getComment(); + this.getComment();
} }
/**
* Is this a database instance?
*
* @return True if the instance ID is greater or equal to zero; otherwise
* false.
*/
public boolean isDatabaseInstance() {
return (ID >= 0);
}
/** /**
* @return the database ID * @return the database ID
*/ */
@ -160,8 +155,8 @@ public class CorrelationAttributeInstance implements Serializable {
} }
/** /**
* Get this knownStatus. This only indicates whether an item has been * Get this knownStatus. This only indicates whether an item has been tagged
* tagged as notable and should never return KNOWN. * as notable and should never return KNOWN.
* *
* @return BAD if the item has been tagged as notable, UNKNOWN otherwise * @return BAD if the item has been tagged as notable, UNKNOWN otherwise
*/ */
@ -170,10 +165,11 @@ public class CorrelationAttributeInstance implements Serializable {
} }
/** /**
* Set the knownStatus. This only indicates whether an item has been * Set the knownStatus. This only indicates whether an item has been tagged
* tagged as notable and should never be set to KNOWN. * as notable and should never be set to KNOWN.
* *
* @param knownStatus Should be BAD if the item is tagged as notable, UNKNOWN otherwise * @param knownStatus Should be BAD if the item is tagged as notable,
* UNKNOWN otherwise
*/ */
public void setKnownStatus(TskData.FileKnown knownStatus) { public void setKnownStatus(TskData.FileKnown knownStatus) {
this.knownStatus = knownStatus; this.knownStatus = knownStatus;

View File

@ -40,15 +40,21 @@ public class CorrelationDataSource implements Serializable {
private final String name; private final String name;
/** /**
* * @param correlationCase CorrelationCase object data source is associated with. Must have been created by EamDB and have a valid ID.
* @param caseId * @param deviceId User specified case-specific ID
* @param deviceId * @param name Display name of data source
* @param name
*/ */
public CorrelationDataSource(int caseId, String deviceId, String name) { public CorrelationDataSource(CorrelationCase correlationCase, String deviceId, String name) {
this(caseId, -1, deviceId, name); this(correlationCase.getID(), -1, deviceId, name);
} }
/**
*
* @param caseId Row ID for Case in DB
* @param dataSourceId Row ID for this data source in DB (or -1)
* @param deviceId User specified ID for device (unique per case)
* @param name User specified name
*/
CorrelationDataSource(int caseId, CorrelationDataSource(int caseId,
int dataSourceId, int dataSourceId,
String deviceId, String deviceId,
@ -61,6 +67,7 @@ public class CorrelationDataSource implements Serializable {
/** /**
* Create a CorrelationDataSource object from a TSK Content object. * Create a CorrelationDataSource object from a TSK Content object.
* This will add it to the central repository.
* *
* @param correlationCase the current CorrelationCase used for ensuring * @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource * uniqueness of DataSource
@ -84,7 +91,18 @@ public class CorrelationDataSource implements Serializable {
} catch (TskDataException | TskCoreException ex) { } catch (TskDataException | TskCoreException ex) {
throw new EamDbException("Error getting data source info: " + ex.getMessage()); throw new EamDbException("Error getting data source info: " + ex.getMessage());
} }
return new CorrelationDataSource(correlationCase.getID(), -1, deviceId, dataSource.getName());
CorrelationDataSource correlationDataSource = null;
if (EamDbUtil.useCentralRepo()) {
correlationDataSource = EamDb.getInstance().getDataSource(correlationCase, deviceId);
}
if (correlationDataSource == null) {
correlationDataSource = new CorrelationDataSource(correlationCase, deviceId, dataSource.getName());
if (EamDbUtil.useCentralRepo()) {
EamDb.getInstance().newDataSource(correlationDataSource);
}
}
return correlationDataSource;
} }
@Override @Override
@ -102,7 +120,7 @@ public class CorrelationDataSource implements Serializable {
/** /**
* Get the database row ID * Get the database row ID
* *
* @return the ID * @return the ID or -1 if unknown
*/ */
int getID() { int getID() {
return dataSourceID; return dataSourceID;

View File

@ -39,7 +39,7 @@ import org.sleuthkit.datamodel.TskData;
public class EamArtifactUtil { public class EamArtifactUtil {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(EamArtifactUtil.class.getName()); private static final Logger logger = Logger.getLogger(EamArtifactUtil.class.getName());
public EamArtifactUtil() { public EamArtifactUtil() {
} }
@ -76,14 +76,14 @@ public class EamArtifactUtil {
// have switch based on artifact type // have switch based on artifact type
for (CorrelationAttribute.Type aType : EamDb.getInstance().getDefinedCorrelationTypes()) { for (CorrelationAttribute.Type aType : EamDb.getInstance().getDefinedCorrelationTypes()) {
if ((checkEnabled && aType.isEnabled()) || !checkEnabled) { if ((checkEnabled && aType.isEnabled()) || !checkEnabled) {
CorrelationAttribute eamArtifact = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(aType, bbArtifact); CorrelationAttribute correlationAttribute = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(aType, bbArtifact);
if (eamArtifact != null) { if (correlationAttribute != null) {
eamArtifacts.add(eamArtifact); eamArtifacts.add(correlationAttribute);
} }
} }
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS logger.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS
return eamArtifacts; return eamArtifacts;
} }
@ -115,10 +115,10 @@ public class EamArtifactUtil {
eamArtifact.addInstance(eamInstance); eamArtifact.addInstance(eamInstance);
} }
} catch (TskCoreException | EamDbException ex) { } catch (TskCoreException | EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS logger.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS
return eamArtifacts; return eamArtifacts;
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS logger.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS
return eamArtifacts; return eamArtifacts;
} }
} }
@ -202,10 +202,10 @@ public class EamArtifactUtil {
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
return null; return null;
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
return null; return null;
} }
@ -216,6 +216,45 @@ public class EamArtifactUtil {
} }
} }
/**
* Retrieve CorrelationAttribute from the given Content.
*
* @param content The content object
*
* @return The new CorrelationAttribute, or null if retrieval failed.
*/
public static CorrelationAttribute getCorrelationAttributeFromContent(Content content) {
if (!(content instanceof AbstractFile)) {
return null;
}
final AbstractFile file = (AbstractFile) content;
if (!isSupportedAbstractFileType(file)) {
return null;
}
CorrelationAttribute correlationAttribute = null;
try {
CorrelationAttribute.Type type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCaseThrows());
if (null == correlationCase) {
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCaseThrows());
}
CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource());
String value = file.getMd5Hash();
String filePath = (file.getParentPath() + file.getName()).toLowerCase();
correlationAttribute = EamDb.getInstance().getCorrelationAttribute(type, correlationCase, correlationDataSource, value, filePath);
} catch (TskCoreException | EamDbException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Error retrieving correlation attribute.", ex);
}
return correlationAttribute;
}
/** /**
* Create an EamArtifact from the given Content. Will return null if an * Create an EamArtifact from the given Content. Will return null if an
* artifact can not be created - this is not necessarily an error case, it * artifact can not be created - this is not necessarily an error case, it
@ -237,7 +276,7 @@ public class EamArtifactUtil {
final AbstractFile af = (AbstractFile) content; final AbstractFile af = (AbstractFile) content;
if (!isValidCentralRepoFile(af)) { if (!isSupportedAbstractFileType(af)) {
return null; return null;
} }
@ -262,7 +301,7 @@ public class EamArtifactUtil {
eamArtifact.addInstance(cei); eamArtifact.addInstance(cei);
return eamArtifact; return eamArtifact;
} catch (TskCoreException | EamDbException | NoCurrentCaseException ex) { } catch (TskCoreException | EamDbException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Error making correlation attribute.", ex); logger.log(Level.SEVERE, "Error making correlation attribute.", ex);
return null; return null;
} }
} }
@ -271,21 +310,17 @@ public class EamArtifactUtil {
* Check whether the given abstract file should be processed for the central * Check whether the given abstract file should be processed for the central
* repository. * repository.
* *
* @param af The file to test * @param file The file to test
* *
* @return true if the file should be added to the central repo, false * @return true if the file should be added to the central repo, false
* otherwise * otherwise
*/ */
public static boolean isValidCentralRepoFile(AbstractFile af) { public static boolean isSupportedAbstractFileType(AbstractFile file) {
if (af == null) { if (file == null) {
return false; return false;
} }
if (af.getKnown() == TskData.FileKnown.KNOWN) { switch (file.getType()) {
return false;
}
switch (af.getType()) {
case UNALLOC_BLOCKS: case UNALLOC_BLOCKS:
case UNUSED_BLOCKS: case UNUSED_BLOCKS:
case SLACK: case SLACK:
@ -297,9 +332,9 @@ public class EamArtifactUtil {
case LOCAL: case LOCAL:
return true; return true;
case FS: case FS:
return af.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC); return file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC);
default: default:
LOGGER.log(Level.WARNING, "Unexpected file type {0}", af.getType().getName()); logger.log(Level.WARNING, "Unexpected file type {0}", file.getType().getName());
return false; return false;
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2017 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -35,6 +35,7 @@ public interface EamDb {
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
= new CaseDbSchemaVersionNumber(1, 1); = new CaseDbSchemaVersionNumber(1, 1);
/** /**
* Get the instance * Get the instance
* *
@ -158,7 +159,9 @@ public interface EamDb {
* Retrieves Central Repo case based on an Autopsy Case * Retrieves Central Repo case based on an Autopsy Case
* *
* @param autopsyCase Autopsy case to find corresponding CR case for * @param autopsyCase Autopsy case to find corresponding CR case for
*
* @return CR Case * @return CR Case
*
* @throws EamDbException * @throws EamDbException
*/ */
CorrelationCase getCase(Case autopsyCase) throws EamDbException; CorrelationCase getCase(Case autopsyCase) throws EamDbException;
@ -309,6 +312,34 @@ public interface EamDb {
*/ */
void bulkInsertCases(List<CorrelationCase> cases) throws EamDbException; void bulkInsertCases(List<CorrelationCase> cases) throws EamDbException;
/**
* Update a correlation attribute instance comment in the database with that
* in the associated CorrelationAttribute object.
*
* @param eamArtifact The correlation attribute whose database instance will
* be updated.
*
* @throws EamDbException
*/
void updateAttributeInstanceComment(CorrelationAttribute eamArtifact) throws EamDbException;
/**
* Find a correlation attribute in the Central Repository database given the
* instance type, case, data source, value, and file path.
*
* @param type The type of instance.
* @param correlationCase The case tied to the instance.
* @param correlationDataSource The data source tied to the instance.
* @param value The value tied to the instance.
* @param filePath The file path tied to the instance.
*
* @return The correlation attribute if it exists; otherwise null.
*
* @throws EamDbException
*/
CorrelationAttribute getCorrelationAttribute(CorrelationAttribute.Type type, CorrelationCase correlationCase,
CorrelationDataSource correlationDataSource, String value, String filePath) throws EamDbException;
/** /**
* Sets an eamArtifact instance to the given known status. If eamArtifact * Sets an eamArtifact instance to the given known status. If eamArtifact
* exists, it is updated. If eamArtifact does not exist nothing happens * exists, it is updated. If eamArtifact does not exist nothing happens
@ -329,6 +360,15 @@ public interface EamDb {
*/ */
List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException; List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException;
/**
* Gets list of matching eamArtifact instances that have knownStatus =
* "Bad".
*
* @param aType EamArtifact.Type to search for
* @return List with 0 or more matching eamArtifact instances.
* @throws EamDbException
*/
List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType) throws EamDbException;
/** /**
* Count matching eamArtifacts instances that have knownStatus = "Bad". * Count matching eamArtifacts instances that have knownStatus = "Bad".
* *
@ -357,6 +397,7 @@ public interface EamDb {
* Remove a reference set and all values contained in it. * Remove a reference set and all values contained in it.
* *
* @param referenceSetID * @param referenceSetID
*
* @throws EamDbException * @throws EamDbException
*/ */
public void deleteReferenceSet(int referenceSetID) throws EamDbException; public void deleteReferenceSet(int referenceSetID) throws EamDbException;
@ -369,7 +410,9 @@ public interface EamDb {
* @param referenceSetID * @param referenceSetID
* @param referenceSetName * @param referenceSetName
* @param version * @param version
*
* @return true if a matching entry exists in the central repository * @return true if a matching entry exists in the central repository
*
* @throws EamDbException * @throws EamDbException
*/ */
public boolean referenceSetIsValid(int referenceSetID, String referenceSetName, String version) throws EamDbException; public boolean referenceSetIsValid(int referenceSetID, String referenceSetName, String version) throws EamDbException;
@ -381,7 +424,9 @@ public interface EamDb {
* *
* @param referenceSetName * @param referenceSetName
* @param version * @param version
*
* @return true if a matching set is found * @return true if a matching set is found
*
* @throws EamDbException * @throws EamDbException
*/ */
public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException; public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException;
@ -392,7 +437,9 @@ public interface EamDb {
* *
* @param hash * @param hash
* @param referenceSetID * @param referenceSetID
*
* @return true if the hash is found in the reference set * @return true if the hash is found in the reference set
*
* @throws EamDbException * @throws EamDbException
*/ */
public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException; public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException;
@ -403,6 +450,7 @@ public interface EamDb {
* @param value * @param value
* @param referenceSetID * @param referenceSetID
* @param correlationTypeID * @param correlationTypeID
*
* @return true if the hash is found in the reference set * @return true if the hash is found in the reference set
*/ */
public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException; public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException;
@ -422,11 +470,11 @@ public interface EamDb {
* *
* @param eamOrg The organization to add * @param eamOrg The organization to add
* *
* @return the Organization ID of the newly created organization. * @return The organization with the org ID set.
* *
* @throws EamDbException * @throws EamDbException
*/ */
long newOrganization(EamOrganization eamOrg) throws EamDbException; EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException;
/** /**
* Get all organizations * Get all organizations
@ -452,7 +500,9 @@ public interface EamDb {
* Get the organization associated with the given reference set. * Get the organization associated with the given reference set.
* *
* @param referenceSetID ID of the reference set * @param referenceSetID ID of the reference set
*
* @return The organization object * @return The organization object
*
* @throws EamDbException * @throws EamDbException
*/ */
EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException; EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException;
@ -513,7 +563,8 @@ public interface EamDb {
* Add a new reference instance * Add a new reference instance
* *
* @param eamGlobalFileInstance The reference instance to add * @param eamGlobalFileInstance The reference instance to add
* @param correlationType Correlation Type that this Reference Instance is * @param correlationType Correlation Type that this Reference
* Instance is
* *
* @throws EamDbException * @throws EamDbException
*/ */
@ -620,8 +671,18 @@ public interface EamDb {
* (meaning the database is in use). * (meaning the database is in use).
* *
* @return the lock, or null if locking is not supported * @return the lock, or null if locking is not supported
*
* @throws EamDbException if the coordination service is running but we fail * @throws EamDbException if the coordination service is running but we fail
* to get the lock * to get the lock
*/ */
public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException; public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException;
/**
* Process the Artifact instance in the EamDb
*
* @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
* @throws EamDbException
*/
void processInstanceTable(CorrelationAttribute.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException;
} }

View File

@ -42,18 +42,18 @@ public class EamDbUtil {
private static final String DEFAULT_ORG_NAME = "Not Specified"; private static final String DEFAULT_ORG_NAME = "Not Specified";
/** /**
* Close the prepared statement. * Close the statement.
* *
* @param preparedStatement * @param statement The statement to be closed.
* *
* @throws EamDbException * @throws EamDbException
*/ */
public static void closePreparedStatement(PreparedStatement preparedStatement) { public static void closeStatement(Statement statement) {
if (null != preparedStatement) { if (null != statement) {
try { try {
preparedStatement.close(); statement.close();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Error closing PreparedStatement.", ex); LOGGER.log(Level.SEVERE, "Error closing Statement.", ex);
} }
} }
} }
@ -361,4 +361,18 @@ public class EamDbUtil {
return "reference_" + type.getDbTableName(); return "reference_" + type.getDbTableName();
} }
/**
* Close the prepared statement.
*
* @param preparedStatement The prepared statement to be closed.
*
* @deprecated Use closeStatement() instead.
*
* @throws EamDbException
*/
@Deprecated
public static void closePreparedStatement(PreparedStatement preparedStatement) {
closeStatement(preparedStatement);
}
} }

View File

@ -29,7 +29,7 @@ public class EamOrganization {
private String pocEmail; private String pocEmail;
private String pocPhone; private String pocPhone;
public EamOrganization( EamOrganization(
int orgID, int orgID,
String name, String name,
String pocName, String pocName,
@ -84,7 +84,7 @@ public class EamOrganization {
/** /**
* @param orgID the orgID to set * @param orgID the orgID to set
*/ */
public void setOrgID(int orgID) { void setOrgID(int orgID) {
this.orgID = orgID; this.orgID = orgID;
} }

View File

@ -0,0 +1,109 @@
/*
* Central Repository
*
* Copyright 2015-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.centralrepository.datamodel;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* CallBack Interface to process attribute instance Table. Used in EamDb.processInstanceTable
* is called only once. The implementation of this method needs to call resultset.next to
* loop through each row of attribute instance table.
*/
public interface InstanceTableCallback {
/**
* Process the attribute instance
*
* @param resultSet attribute instance table.
*/
void process(ResultSet resultSet);
/**
*
* @param resultSet attribute instance table
* @return ID of the instance
* @throws SQLException
*/
static int getId(ResultSet resultSet) throws SQLException{
return resultSet.getInt("id");
}
/**
*
* @param resultSet attribute instance table
* @return Case ID of a given instance
* @throws SQLException
*/
static int getCaseId(ResultSet resultSet) throws SQLException {
return resultSet.getInt("case_id");
}
/**
*
* @param resultSet attribute instance table
* @return Data source id of a particular instance
* @throws SQLException
*/
static int getDataSourceId(ResultSet resultSet) throws SQLException {
return resultSet.getInt("data_source_id");
}
/**
*
* @param resultSet attribute instance table
* @return md5 hash value of the instance
* @throws SQLException
*/
static String getValue(ResultSet resultSet) throws SQLException {
return resultSet.getString("value");
}
/**
*
* @param resultSet attribute instance table
* @return file path of the instance
* @throws SQLException
*/
static String getFilePath(ResultSet resultSet) throws SQLException {
return resultSet.getString("file_path");
}
/**
*
* @param resultSet attribute instance table
* @return status integer based on whether instance is marked notable or not
* @throws SQLException
*/
static int getKnownStatus(ResultSet resultSet) throws SQLException {
return resultSet.getInt("known_status");
}
/**
*
* @param resultSet attribute instance table
* @return previous comment made for the instance
* @throws SQLException
*/
static String getComment(ResultSet resultSet) throws SQLException {
return resultSet.getString("comment");
}
}

View File

@ -24,8 +24,6 @@ import java.sql.Statement;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException;
import org.sleuthkit.autopsy.casemodule.CaseActionException;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -34,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* Central Repository database implementation using Postgres as a * Central Repository database implementation using Postgres as a
* backend * backend
*/ */
public class PostgresEamDb extends AbstractSqlEamDb { final class PostgresEamDb extends AbstractSqlEamDb {
private final static Logger LOGGER = Logger.getLogger(PostgresEamDb.class.getName()); private final static Logger LOGGER = Logger.getLogger(PostgresEamDb.class.getName());
@ -116,7 +114,7 @@ public class PostgresEamDb extends AbstractSqlEamDb {
String instancesTemplate = "TRUNCATE TABLE %s_instances RESTART IDENTITY CASCADE"; String instancesTemplate = "TRUNCATE TABLE %s_instances RESTART IDENTITY CASCADE";
String referencesTemplate = "TRUNCATE TABLE reference_%s RESTART IDENTITY CASCADE"; String referencesTemplate = "TRUNCATE TABLE reference_%s RESTART IDENTITY CASCADE";
for (CorrelationAttribute.Type type : DEFAULT_CORRELATION_TYPES) { for (CorrelationAttribute.Type type : defaultCorrelationTypes) {
dropContent.executeUpdate(String.format(instancesTemplate, type.getDbTableName())); dropContent.executeUpdate(String.format(instancesTemplate, type.getDbTableName()));
// FUTURE: support other reference types // FUTURE: support other reference types
if (type.getId() == CorrelationAttribute.FILES_TYPE_ID) { if (type.getId() == CorrelationAttribute.FILES_TYPE_ID) {

View File

@ -35,6 +35,8 @@ import org.sleuthkit.autopsy.coreutils.TextConverterException;
/** /**
* Settings for the Postgres implementation of the Central Repository database * Settings for the Postgres implementation of the Central Repository database
*
* NOTE: This is public scope because the options panel calls it directly to set/get
*/ */
public final class PostgresEamDbSettings { public final class PostgresEamDbSettings {
@ -42,7 +44,6 @@ public final class PostgresEamDbSettings {
private final String DEFAULT_HOST = ""; // NON-NLS private final String DEFAULT_HOST = ""; // NON-NLS
private final int DEFAULT_PORT = 5432; private final int DEFAULT_PORT = 5432;
private final String DEFAULT_DBNAME = "central_repository"; // NON-NLS private final String DEFAULT_DBNAME = "central_repository"; // NON-NLS
private final int DEFAULT_BULK_THRESHHOLD = 1000;
private final String DEFAULT_USERNAME = ""; private final String DEFAULT_USERNAME = "";
private final String DEFAULT_PASSWORD = ""; private final String DEFAULT_PASSWORD = "";
private final String VALIDATION_QUERY = "SELECT version()"; // NON-NLS private final String VALIDATION_QUERY = "SELECT version()"; // NON-NLS
@ -89,15 +90,15 @@ public final class PostgresEamDbSettings {
try { try {
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.bulkThreshold"); // NON-NLS String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.bulkThreshold"); // NON-NLS
if (bulkThresholdString == null || bulkThresholdString.isEmpty()) { if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
} else { } else {
this.bulkThreshold = Integer.parseInt(bulkThresholdString); this.bulkThreshold = Integer.parseInt(bulkThresholdString);
if (getBulkThreshold() <= 0) { if (getBulkThreshold() <= 0) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
} }
} }
} catch (NumberFormatException ex) { } catch (NumberFormatException ex) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
} }
userName = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.user"); // NON-NLS userName = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.user"); // NON-NLS
@ -139,7 +140,7 @@ public final class PostgresEamDbSettings {
* *
* @return * @return
*/ */
public String getConnectionURL(boolean usePostgresDb) { String getConnectionURL(boolean usePostgresDb) {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
url.append(getJDBCBaseURI()); url.append(getJDBCBaseURI());
url.append(getHost()); url.append(getHost());
@ -220,7 +221,7 @@ public final class PostgresEamDbSettings {
LOGGER.log(Level.SEVERE, "Failed to execute database existance query.", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Failed to execute database existance query.", ex); // NON-NLS
return false; return false;
} finally { } finally {
EamDbUtil.closePreparedStatement(ps); EamDbUtil.closeStatement(ps);
EamDbUtil.closeResultSet(rs); EamDbUtil.closeResultSet(rs);
EamDbUtil.closeConnection(conn); EamDbUtil.closeConnection(conn);
} }
@ -231,7 +232,7 @@ public final class PostgresEamDbSettings {
* Use the current settings and the schema version query to test the * Use the current settings and the schema version query to test the
* database schema. * database schema.
* *
* @return true if successfull connection, else false. * @return true if successful connection, else false.
*/ */
public boolean verifyDatabaseSchema() { public boolean verifyDatabaseSchema() {
Connection conn = getEphemeralConnection(false); Connection conn = getEphemeralConnection(false);
@ -493,7 +494,7 @@ public final class PostgresEamDbSettings {
return result; return result;
} }
public boolean isChanged() { boolean isChanged() {
String hostString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS String hostString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS
String portString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.port"); // NON-NLS String portString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.port"); // NON-NLS
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.dbName"); // NON-NLS String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.dbName"); // NON-NLS
@ -568,7 +569,7 @@ public final class PostgresEamDbSettings {
/** /**
* @return the bulkThreshold * @return the bulkThreshold
*/ */
public int getBulkThreshold() { int getBulkThreshold() {
return bulkThreshold; return bulkThreshold;
} }
@ -622,21 +623,21 @@ public final class PostgresEamDbSettings {
/** /**
* @return the VALIDATION_QUERY * @return the VALIDATION_QUERY
*/ */
public String getValidationQuery() { String getValidationQuery() {
return VALIDATION_QUERY; return VALIDATION_QUERY;
} }
/** /**
* @return the POSTGRES_DRIVER * @return the POSTGRES_DRIVER
*/ */
public String getDriver() { String getDriver() {
return JDBC_DRIVER; return JDBC_DRIVER;
} }
/** /**
* @return the JDBC_BASE_URI * @return the JDBC_BASE_URI
*/ */
public String getJDBCBaseURI() { String getJDBCBaseURI() {
return JDBC_BASE_URI; return JDBC_BASE_URI;
} }

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.centralrepository.datamodel; package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.io.File;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
@ -38,7 +37,7 @@ import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
* All methods in AbstractSqlEamDb that read or write to the database should * All methods in AbstractSqlEamDb that read or write to the database should
* be overriden here and use appropriate locking. * be overriden here and use appropriate locking.
*/ */
public class SqliteEamDb extends AbstractSqlEamDb { final class SqliteEamDb extends AbstractSqlEamDb {
private final static Logger LOGGER = Logger.getLogger(SqliteEamDb.class.getName()); private final static Logger LOGGER = Logger.getLogger(SqliteEamDb.class.getName());
@ -125,7 +124,7 @@ public class SqliteEamDb extends AbstractSqlEamDb {
String instancesTemplate = "DELETE FROM %s_instances"; String instancesTemplate = "DELETE FROM %s_instances";
String referencesTemplate = "DELETE FROM global_files"; String referencesTemplate = "DELETE FROM global_files";
for (CorrelationAttribute.Type type : DEFAULT_CORRELATION_TYPES) { for (CorrelationAttribute.Type type : defaultCorrelationTypes) {
dropContent.executeUpdate(String.format(instancesTemplate, type.getDbTableName())); dropContent.executeUpdate(String.format(instancesTemplate, type.getDbTableName()));
// FUTURE: support other reference types // FUTURE: support other reference types
if (type.getId() == CorrelationAttribute.FILES_TYPE_ID) { if (type.getId() == CorrelationAttribute.FILES_TYPE_ID) {
@ -590,6 +589,24 @@ public class SqliteEamDb extends AbstractSqlEamDb {
} }
} }
/**
*
* Gets list of matching eamArtifact instances that have knownStatus =
* "Bad".
* @param aType EamArtifact.Type to search for
* @return List with 0 or more matching eamArtifact instances.
* @throws EamDbException
*/
@Override
public List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType) throws EamDbException {
try{
acquireSharedLock();
return super.getArtifactInstancesKnownBad(aType);
} finally {
releaseSharedLock();
}
}
/** /**
* Count matching eamArtifacts instances that have knownStatus = "Bad". * Count matching eamArtifacts instances that have knownStatus = "Bad".
* *
@ -662,6 +679,22 @@ public class SqliteEamDb extends AbstractSqlEamDb {
} }
} }
/**
* Process the Artifact instance in the EamDb
*
* @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
* @throws EamDbException
*/
@Override
public void processInstanceTable(CorrelationAttribute.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException {
try {
acquireSharedLock();
super.processInstanceTable(type, instanceTableCallback);
} finally {
releaseSharedLock();
}
}
/** /**
* Check whether a reference set with the given name/version is in the central repo. * Check whether a reference set with the given name/version is in the central repo.
* Used to check for name collisions when creating reference sets. * Used to check for name collisions when creating reference sets.
@ -708,7 +741,7 @@ public class SqliteEamDb extends AbstractSqlEamDb {
* @throws EamDbException * @throws EamDbException
*/ */
@Override @Override
public long newOrganization(EamOrganization eamOrg) throws EamDbException { public EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException {
try{ try{
acquireExclusiveLock(); acquireExclusiveLock();
return super.newOrganization(eamOrg); return super.newOrganization(eamOrg);

View File

@ -35,13 +35,14 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/** /**
* Settings for the sqlite implementation of the Central Repository database * Settings for the sqlite implementation of the Central Repository database
*
* NOTE: This is public scope because the options panel calls it directly to set/get
*/ */
public final class SqliteEamDbSettings { public final class SqliteEamDbSettings {
private final static Logger LOGGER = Logger.getLogger(SqliteEamDbSettings.class.getName()); private final static Logger LOGGER = Logger.getLogger(SqliteEamDbSettings.class.getName());
private final String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS private final String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS
private final String DEFAULT_DBDIRECTORY = PlatformUtil.getUserDirectory() + File.separator + "central_repository"; // NON-NLS private final String DEFAULT_DBDIRECTORY = PlatformUtil.getUserDirectory() + File.separator + "central_repository"; // NON-NLS
private final int DEFAULT_BULK_THRESHHOLD = 1000;
private final String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS private final String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS
private final String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS private final String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS
private final String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS private final String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS
@ -75,15 +76,15 @@ public final class SqliteEamDbSettings {
try { try {
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.bulkThreshold"); // NON-NLS String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.bulkThreshold"); // NON-NLS
if (bulkThresholdString == null || bulkThresholdString.isEmpty()) { if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
} else { } else {
this.bulkThreshold = Integer.parseInt(bulkThresholdString); this.bulkThreshold = Integer.parseInt(bulkThresholdString);
if (getBulkThreshold() <= 0) { if (getBulkThreshold() <= 0) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
} }
} }
} catch (NumberFormatException ex) { } catch (NumberFormatException ex) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
} }
} }
@ -162,7 +163,7 @@ public final class SqliteEamDbSettings {
* *
* @return * @return
*/ */
public String getConnectionURL() { String getConnectionURL() {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
url.append(getJDBCBaseURI()); url.append(getJDBCBaseURI());
url.append(getFileNameWithPath()); url.append(getFileNameWithPath());
@ -439,7 +440,7 @@ public final class SqliteEamDbSettings {
return result; return result;
} }
public boolean isChanged() { boolean isChanged() {
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS
String dbDirectoryString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS String dbDirectoryString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.bulkThreshold"); // NON-NLS String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.bulkThreshold"); // NON-NLS
@ -474,14 +475,14 @@ public final class SqliteEamDbSettings {
/** /**
* @return the bulkThreshold * @return the bulkThreshold
*/ */
public int getBulkThreshold() { int getBulkThreshold() {
return bulkThreshold; return bulkThreshold;
} }
/** /**
* @param bulkThreshold the bulkThreshold to set * @param bulkThreshold the bulkThreshold to set
*/ */
public void setBulkThreshold(int bulkThreshold) throws EamDbException { void setBulkThreshold(int bulkThreshold) throws EamDbException {
if (bulkThreshold > 0) { if (bulkThreshold > 0) {
this.bulkThreshold = bulkThreshold; this.bulkThreshold = bulkThreshold;
} else { } else {
@ -525,21 +526,21 @@ public final class SqliteEamDbSettings {
/** /**
* @return the DRIVER * @return the DRIVER
*/ */
public String getDriver() { String getDriver() {
return JDBC_DRIVER; return JDBC_DRIVER;
} }
/** /**
* @return the VALIDATION_QUERY * @return the VALIDATION_QUERY
*/ */
public String getValidationQuery() { String getValidationQuery() {
return VALIDATION_QUERY; return VALIDATION_QUERY;
} }
/** /**
* @return the JDBC_BASE_URI * @return the JDBC_BASE_URI
*/ */
public String getJDBCBaseURI() { String getJDBCBaseURI() {
return JDBC_BASE_URI; return JDBC_BASE_URI;
} }

View File

@ -450,10 +450,10 @@ final class CaseEventListener implements PropertyChangeListener {
correlationCase = dbManager.newCase(openCase); correlationCase = dbManager.newCase(openCase);
} }
if (null == dbManager.getDataSource(correlationCase, deviceId)) { if (null == dbManager.getDataSource(correlationCase, deviceId)) {
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource)); CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource);
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS LOGGER.log(Level.SEVERE, "Error adding new data source to the central repository", ex); //NON-NLS
} catch (TskCoreException | TskDataException ex) { } catch (TskCoreException | TskDataException ex) {
LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
} }

View File

@ -276,12 +276,12 @@ public class IngestEventsListener {
} }
} }
if (FALSE == eamArtifacts.isEmpty()) { if (FALSE == eamArtifacts.isEmpty()) {
try {
for (CorrelationAttribute eamArtifact : eamArtifacts) { for (CorrelationAttribute eamArtifact : eamArtifacts) {
try {
dbManager.addArtifact(eamArtifact); dbManager.addArtifact(eamArtifact);
}
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS LOGGER.log(Level.SEVERE, "Error adding artifact to database.", ex); //NON-NLS
}
} }
} // DATA_ADDED } // DATA_ADDED
} }

View File

@ -49,7 +49,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.HashUtility;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor; import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
/** /**
@ -102,7 +102,11 @@ final class IngestModule implements FileIngestModule {
return ProcessResult.ERROR; return ProcessResult.ERROR;
} }
if (!EamArtifactUtil.isValidCentralRepoFile(abstractFile)) { if (!EamArtifactUtil.isSupportedAbstractFileType(abstractFile)) {
return ProcessResult.OK;
}
if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) {
return ProcessResult.OK; return ProcessResult.OK;
} }
@ -131,9 +135,9 @@ final class IngestModule implements FileIngestModule {
*/ */
if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) { if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
try { try {
TimingMetric timingMetric = EnterpriseHealthMonitor.getTimingMetric("Correlation Engine: Notable artifact query"); TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Notable artifact query");
List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
EnterpriseHealthMonitor.submitTimingMetric(timingMetric); HealthMonitor.submitTimingMetric(timingMetric);
if (!caseDisplayNamesList.isEmpty()) { if (!caseDisplayNamesList.isEmpty()) {
postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList); postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList);
} }

View File

@ -24,6 +24,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
/** /**
* Ingest job settings panel for the Correlation Engine module. * Ingest job settings panel for the Correlation Engine module.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
/** /**

View File

@ -36,9 +36,10 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
/** /**
* Dialog to add a new organization to the Central Repository database * Dialog to add a new organization to the Central Repository database
*/ */
public class AddNewOrganizationDialog extends javax.swing.JDialog { @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddNewOrganizationDialog extends javax.swing.JDialog {
private static final Logger LOGGER = Logger.getLogger(AddNewOrganizationDialog.class.getName()); private static final Logger logger = Logger.getLogger(AddNewOrganizationDialog.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Collection<JTextField> textBoxes; private final Collection<JTextField> textBoxes;
@ -51,7 +52,7 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
* Creates new form AddNewOrganizationDialog * Creates new form AddNewOrganizationDialog
*/ */
@Messages({"AddNewOrganizationDialog.addNewOrg.msg=Add New Organization"}) @Messages({"AddNewOrganizationDialog.addNewOrg.msg=Add New Organization"})
public AddNewOrganizationDialog() { AddNewOrganizationDialog() {
super((JFrame) WindowManager.getDefault().getMainWindow(), super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.AddNewOrganizationDialog_addNewOrg_msg(), Bundle.AddNewOrganizationDialog_addNewOrg_msg(),
true); // NON-NLS true); // NON-NLS
@ -65,6 +66,7 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
display(); display();
} }
// populates the dialog with existing case information to edit
public AddNewOrganizationDialog(EamOrganization orgToEdit) { public AddNewOrganizationDialog(EamOrganization orgToEdit) {
super((JFrame) WindowManager.getDefault().getMainWindow(), super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.AddNewOrganizationDialog_addNewOrg_msg(), Bundle.AddNewOrganizationDialog_addNewOrg_msg(),
@ -193,10 +195,19 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
} }
} }
/**
*
* @return True if new org was added or existing org changed
*/
public boolean isChanged() { public boolean isChanged() {
return hasChanged; return hasChanged;
} }
/**
* Only valid if isChanged() is true.
*
* @return Org that was added or changed. null if nothing changed
*/
public EamOrganization getNewOrg() { public EamOrganization getNewOrg() {
return newOrg; return newOrg;
} }
@ -332,12 +343,12 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
try { try {
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
if (organizationToEdit != null) { if (organizationToEdit != null) {
//check if new name exists with ID other than the one in use here // make a copy in case the update fails
newOrg = new EamOrganization(organizationToEdit.getOrgID(), newOrg = dbManager.getOrganizationByID(organizationToEdit.getOrgID());
tfOrganizationName.getText(), newOrg.setName(tfOrganizationName.getText());
tfPocName.getText(), newOrg.setPocName(tfPocName.getText());
tfPocEmail.getText(), newOrg.setPocEmail(tfPocEmail.getText());
tfPocPhone.getText()); newOrg.setPocPhone(tfPocPhone.getText());
dbManager.updateOrganization(newOrg); dbManager.updateOrganization(newOrg);
} else { } else {
newOrg = new EamOrganization( newOrg = new EamOrganization(
@ -345,13 +356,14 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
tfPocName.getText(), tfPocName.getText(),
tfPocEmail.getText(), tfPocEmail.getText(),
tfPocPhone.getText()); tfPocPhone.getText());
newOrg.setOrgID((int)dbManager.newOrganization(newOrg)); newOrg = dbManager.newOrganization(newOrg);
} }
hasChanged = true; hasChanged = true;
dispose(); dispose();
} catch (EamDbException ex) { } catch (EamDbException ex) {
lbWarningMsg.setText(Bundle.AddNewOrganizationDialog_bnOk_addFailed_text()); lbWarningMsg.setText(Bundle.AddNewOrganizationDialog_bnOk_addFailed_text());
LOGGER.log(Level.SEVERE, "Failed adding new organization.", ex); logger.log(Level.SEVERE, "Failed adding new organization.", ex);
newOrg = null;
} }
}//GEN-LAST:event_bnOKActionPerformed }//GEN-LAST:event_bnOKActionPerformed

View File

@ -65,3 +65,13 @@ GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations
GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases. GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases.
GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties
GlobalSettingsPanel.organizationPanel.border.title=Organizations GlobalSettingsPanel.organizationPanel.border.title=Organizations
GlobalSettingsPanel.casesPanel.border.title=Case Details
GlobalSettingsPanel.showCasesButton.text=Show Cases
ShowCasesDialog.closeButton.AccessibleContext.accessibleName=Close
ShowCasesDialog.closeButton.actionCommand=Close
ShowCasesDialog.closeButton.text=Close
ShowCasesDialog.caseDetailsTable.toolTipText=Click column name to sort. Right-click on the table for more options.
ShowCasesDialog.title=Case Details
GlobalSettingsPanel.Case\ Details.AccessibleContext.accessibleName=Cases Details
ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription=Click column name to sort.
GlobalSettingsPanel.casesTextArea.text=Display table that lists central repository case details.

View File

@ -47,9 +47,9 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresEamDbSettings;
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteEamDbSettings; import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteEamDbSettings;
/** /**
* * Configuration dialog for Central Repository database settings.
* @author nick
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class EamDbSettingsDialog extends JDialog { public class EamDbSettingsDialog extends JDialog {
private static final Logger logger = Logger.getLogger(EamDbSettingsDialog.class.getName()); private static final Logger logger = Logger.getLogger(EamDbSettingsDialog.class.getName());
@ -96,11 +96,8 @@ public class EamDbSettingsDialog extends JDialog {
public boolean accept(File pathname) { public boolean accept(File pathname) {
if (pathname.isDirectory()) { if (pathname.isDirectory()) {
return true; return true;
} else if (pathname.getName().toLowerCase().equals((CENTRAL_REPO_DB_NAME + CENTRAL_REPO_SQLITE_EXT).toLowerCase())) {
return true;
} else {
return false;
} }
return pathname.getName().toLowerCase().equals((CENTRAL_REPO_DB_NAME + CENTRAL_REPO_SQLITE_EXT).toLowerCase());
} }
@Override @Override

View File

@ -27,7 +27,7 @@
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" pref="488" max="32767" attributes="0"/> <Component id="jScrollPane1" alignment="0" pref="517" max="32767" attributes="0"/>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
@ -57,23 +57,25 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="lbCentralRepository" max="32767" attributes="0"/> <Component id="lbCentralRepository" pref="1022" max="32767" attributes="0"/>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Component id="cbUseCentralRepo" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
<Component id="pnCorrelationProperties" alignment="0" pref="1016" max="32767" attributes="0"/>
<Component id="organizationPanel" alignment="1" max="32767" attributes="0"/>
<Component id="casesPanel" alignment="0" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cbUseCentralRepo" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="tbOops" min="-2" pref="974" max="-2" attributes="0"/> <Component id="tbOops" min="-2" pref="974" max="-2" attributes="0"/>
<EmptySpace pref="36" max="32767" attributes="0"/>
</Group> </Group>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
<Component id="pnCorrelationProperties" alignment="0" pref="1012" max="32767" attributes="0"/>
<Component id="organizationPanel" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -90,8 +92,10 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="organizationPanel" min="-2" max="-2" attributes="0"/> <Component id="organizationPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="casesPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbOops" min="-2" max="-2" attributes="0"/> <Component id="tbOops" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="92" max="32767" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -328,7 +332,7 @@
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="organizationScrollPane" max="32767" attributes="0"/> <Component id="organizationScrollPane" pref="992" max="32767" attributes="0"/>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Component id="manageOrganizationButton" min="-2" max="-2" attributes="0"/> <Component id="manageOrganizationButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
@ -398,6 +402,100 @@
</Container> </Container>
</SubComponents> </SubComponents>
</Container> </Container>
<Container class="javax.swing.JPanel" name="casesPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Case Details">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.casesPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
</TitledBorder>
</Border>
</Property>
<Property name="name" type="java.lang.String" value="Case Details" noResource="true"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.Case Details.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
<Layout>
<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="casesScrollPane" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="showCasesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" 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="casesScrollPane" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="showCasesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="showCasesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.showCasesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showCasesButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="casesScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="casesTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
</Property>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="2"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.casesTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JTextField" name="tbOops"> <Component class="javax.swing.JTextField" name="tbOops">
<Properties> <Properties>
<Property name="editable" type="boolean" value="false"/> <Property name="editable" type="boolean" value="false"/>

View File

@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteEamDbSettings;
/** /**
* Main settings panel for the Central Repository * Main settings panel for the Central Repository
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -123,6 +124,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
manageOrganizationButton = new javax.swing.JButton(); manageOrganizationButton = new javax.swing.JButton();
organizationScrollPane = new javax.swing.JScrollPane(); organizationScrollPane = new javax.swing.JScrollPane();
organizationTextArea = new javax.swing.JTextArea(); organizationTextArea = new javax.swing.JTextArea();
casesPanel = new javax.swing.JPanel();
showCasesButton = new javax.swing.JButton();
casesScrollPane = new javax.swing.JScrollPane();
casesTextArea = new javax.swing.JTextArea();
tbOops = new javax.swing.JTextField(); tbOops = new javax.swing.JTextField();
setName(""); // NOI18N setName(""); // NOI18N
@ -275,7 +280,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGroup(organizationPanelLayout.createSequentialGroup() .addGroup(organizationPanelLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(organizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(organizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(organizationScrollPane) .addComponent(organizationScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 992, Short.MAX_VALUE)
.addGroup(organizationPanelLayout.createSequentialGroup() .addGroup(organizationPanelLayout.createSequentialGroup()
.addComponent(manageOrganizationButton) .addComponent(manageOrganizationButton)
.addGap(0, 0, Short.MAX_VALUE))) .addGap(0, 0, Short.MAX_VALUE)))
@ -291,6 +296,52 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGap(8, 8, 8)) .addGap(8, 8, 8))
); );
casesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.casesPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N
casesPanel.setName("Case Details"); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(showCasesButton, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.showCasesButton.text")); // NOI18N
showCasesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showCasesButtonActionPerformed(evt);
}
});
casesScrollPane.setBorder(null);
casesTextArea.setEditable(false);
casesTextArea.setBackground(new java.awt.Color(240, 240, 240));
casesTextArea.setColumns(20);
casesTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
casesTextArea.setLineWrap(true);
casesTextArea.setRows(2);
casesTextArea.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.casesTextArea.text")); // NOI18N
casesTextArea.setWrapStyleWord(true);
casesTextArea.setBorder(null);
casesScrollPane.setViewportView(casesTextArea);
javax.swing.GroupLayout casesPanelLayout = new javax.swing.GroupLayout(casesPanel);
casesPanel.setLayout(casesPanelLayout);
casesPanelLayout.setHorizontalGroup(
casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(casesPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(casesScrollPane)
.addGroup(casesPanelLayout.createSequentialGroup()
.addComponent(showCasesButton)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
casesPanelLayout.setVerticalGroup(
casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, casesPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(casesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(showCasesButton)
.addGap(8, 8, 8))
);
tbOops.setEditable(false); tbOops.setEditable(false);
tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12));
tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N
@ -300,20 +351,21 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
jPanel1.setLayout(jPanel1Layout); jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup( jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lbCentralRepository, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lbCentralRepository, javax.swing.GroupLayout.DEFAULT_SIZE, 1022, Short.MAX_VALUE)
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.DEFAULT_SIZE, 1016, Short.MAX_VALUE)
.addComponent(organizationPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(casesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(cbUseCentralRepo) .addComponent(cbUseCentralRepo)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 974, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 974, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap(36, Short.MAX_VALUE)) .addGap(0, 0, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 1012, Short.MAX_VALUE)
.addComponent(organizationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
); );
jPanel1Layout.setVerticalGroup( jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -328,10 +380,14 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(casesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 92, Short.MAX_VALUE)) .addContainerGap())
); );
casesPanel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.Case Details.AccessibleContext.accessibleName")); // NOI18N
jScrollPane1.setViewportView(jPanel1); jScrollPane1.setViewportView(jPanel1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
@ -342,13 +398,13 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 517, Short.MAX_VALUE)
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void bnManageTypesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTypesActionPerformed private void bnManageTypesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTypesActionPerformed
store(); store();
ManageCorrelationPropertiesDialog dialog = new ManageCorrelationPropertiesDialog(); ManageCorrelationPropertiesDialog manageCorrelationDialog = new ManageCorrelationPropertiesDialog();
firePropertyChange(OptionsPanelController.PROP_VALID, null, null); firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
}//GEN-LAST:event_bnManageTypesActionPerformed }//GEN-LAST:event_bnManageTypesActionPerformed
@ -373,9 +429,14 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private void manageOrganizationButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_manageOrganizationButtonActionPerformed private void manageOrganizationButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_manageOrganizationButtonActionPerformed
store(); store();
ManageOrganizationsDialog dialog = new ManageOrganizationsDialog(); ManageOrganizationsDialog manageOrganizationsDialog = new ManageOrganizationsDialog();
}//GEN-LAST:event_manageOrganizationButtonActionPerformed }//GEN-LAST:event_manageOrganizationButtonActionPerformed
private void showCasesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCasesButtonActionPerformed
store();
ShowCasesDialog showCasesDialog = new ShowCasesDialog();
}//GEN-LAST:event_showCasesButtonActionPerformed
@Override @Override
@Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."}) @Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."})
public void load() { public void load() {
@ -552,12 +613,18 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
organizationPanel.setEnabled(enable && !ingestRunning); organizationPanel.setEnabled(enable && !ingestRunning);
organizationTextArea.setEnabled(enable && !ingestRunning); organizationTextArea.setEnabled(enable && !ingestRunning);
manageOrganizationButton.setEnabled(enable && !ingestRunning); manageOrganizationButton.setEnabled(enable && !ingestRunning);
showCasesButton.setEnabled(enable && !ingestRunning);
casesPanel.setEnabled(enable && !ingestRunning);
casesTextArea.setEnabled(enable && !ingestRunning);
return true; return true;
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bnDbConfigure; private javax.swing.JButton bnDbConfigure;
private javax.swing.JButton bnManageTypes; private javax.swing.JButton bnManageTypes;
private javax.swing.JPanel casesPanel;
private javax.swing.JScrollPane casesScrollPane;
private javax.swing.JTextArea casesTextArea;
private javax.swing.JCheckBox cbUseCentralRepo; private javax.swing.JCheckBox cbUseCentralRepo;
private javax.swing.JScrollPane correlationPropertiesScrollPane; private javax.swing.JScrollPane correlationPropertiesScrollPane;
private javax.swing.JTextArea correlationPropertiesTextArea; private javax.swing.JTextArea correlationPropertiesTextArea;
@ -576,6 +643,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private javax.swing.JTextArea organizationTextArea; private javax.swing.JTextArea organizationTextArea;
private javax.swing.JPanel pnCorrelationProperties; private javax.swing.JPanel pnCorrelationProperties;
private javax.swing.JPanel pnDatabaseConfiguration; private javax.swing.JPanel pnDatabaseConfiguration;
private javax.swing.JButton showCasesButton;
private javax.swing.JTextField tbOops; private javax.swing.JTextField tbOops;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2017 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,8 +18,6 @@
*/ */
package org.sleuthkit.autopsy.centralrepository.optionspanel; package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@ -40,6 +38,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
* Dialog to handle management of artifact types handled by the Central * Dialog to handle management of artifact types handled by the Central
* Repository * Repository
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class ManageCorrelationPropertiesDialog extends javax.swing.JDialog { final class ManageCorrelationPropertiesDialog extends javax.swing.JDialog {
private static final Logger LOGGER = Logger.getLogger(ManageCorrelationPropertiesDialog.class.getName()); private static final Logger LOGGER = Logger.getLogger(ManageCorrelationPropertiesDialog.class.getName());

View File

@ -37,6 +37,10 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Configuration dialog to manage organizations for the Central Repository.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class ManageOrganizationsDialog extends JDialog { public final class ManageOrganizationsDialog extends JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[545, 415]"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="showCasesPanel" pref="1188" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<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="6" max="-2" attributes="0"/>
<Component id="showCasesPanel" pref="473" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="showCasesPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[527, 407]"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="1188" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="showCasesScrollPane" alignment="0" pref="527" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="473" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="showCasesScrollPane" alignment="0" pref="407" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="showCasesScrollPane">
<Properties>
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[535, 415]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="outCasesPane">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="1423" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="innerCaseScrollPane" alignment="0" pref="1423" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="500" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="innerCaseScrollPane" alignment="0" pref="500" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="innerCaseScrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="caseDetailsTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="tableModel" type="code"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.caseDetailsTable.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="1"/>
</Property>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="closeButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="closeButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,190 @@
/*
* Central Repository
*
* Copyright 2015-2018 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.centralrepository.optionspanel;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JDialog;
import javax.swing.JFrame;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Dialog to display table of CorrelationCase information from the CR tab of options.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class ShowCasesDialog extends JDialog {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(ShowCasesDialog.class.getName());
private final ShowCasesTableModel tableModel;
@Messages({"ShowCasesDialog.title_text=All Cases Details"})
/**
* Creates new form ShowCases Panel
*/
ShowCasesDialog() {
super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.ShowCasesDialog_title_text(),
true);
tableModel = new ShowCasesTableModel();
initComponents();
try {
EamDb dbManager = EamDb.getInstance();
List<CorrelationCase> eamCases = dbManager.getCases();
for(CorrelationCase eamCase : eamCases) {
tableModel.addEamCase(eamCase);
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
}
display();
}
private void display() {
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
showCasesPanel = new javax.swing.JPanel();
showCasesScrollPane = new javax.swing.JScrollPane();
outCasesPane = new javax.swing.JPanel();
innerCaseScrollPane = new javax.swing.JScrollPane();
caseDetailsTable = new javax.swing.JTable();
closeButton = new javax.swing.JButton();
setTitle(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.title")); // NOI18N
setMinimumSize(new java.awt.Dimension(545, 415));
showCasesPanel.setPreferredSize(new java.awt.Dimension(527, 407));
showCasesScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
showCasesScrollPane.setPreferredSize(new java.awt.Dimension(535, 415));
innerCaseScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
caseDetailsTable.setAutoCreateRowSorter(true);
caseDetailsTable.setModel(tableModel);
caseDetailsTable.setToolTipText(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.caseDetailsTable.toolTipText")); // NOI18N
caseDetailsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
caseDetailsTable.getTableHeader().setReorderingAllowed(false);
innerCaseScrollPane.setViewportView(caseDetailsTable);
caseDetailsTable.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription")); // NOI18N
javax.swing.GroupLayout outCasesPaneLayout = new javax.swing.GroupLayout(outCasesPane);
outCasesPane.setLayout(outCasesPaneLayout);
outCasesPaneLayout.setHorizontalGroup(
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1423, Short.MAX_VALUE)
.addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1423, Short.MAX_VALUE))
);
outCasesPaneLayout.setVerticalGroup(
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 500, Short.MAX_VALUE)
.addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE))
);
showCasesScrollPane.setViewportView(outCasesPane);
javax.swing.GroupLayout showCasesPanelLayout = new javax.swing.GroupLayout(showCasesPanel);
showCasesPanel.setLayout(showCasesPanelLayout);
showCasesPanelLayout.setHorizontalGroup(
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1188, Short.MAX_VALUE)
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE))
);
showCasesPanelLayout.setVerticalGroup(
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 473, Short.MAX_VALUE)
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 407, Short.MAX_VALUE))
);
org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.text")); // NOI18N
closeButton.setActionCommand(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.actionCommand")); // NOI18N
closeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
closeButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1188, Short.MAX_VALUE)
.addGap(6, 6, 6))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(closeButton)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 473, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(closeButton)
.addContainerGap())
);
closeButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.AccessibleContext.accessibleName")); // NOI18N
pack();
}// </editor-fold>//GEN-END:initComponents
private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
dispose();
}//GEN-LAST:event_closeButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTable caseDetailsTable;
private javax.swing.JButton closeButton;
private javax.swing.JScrollPane innerCaseScrollPane;
private javax.swing.JPanel outCasesPane;
private javax.swing.JPanel showCasesPanel;
private javax.swing.JScrollPane showCasesScrollPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,187 @@
/*
* Central Repository
*
* Copyright 2018 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.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
/**
* Model for cells to display correlation case information
*/
class ShowCasesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
@Messages({"ShowCasesTableModel.case=Case Name",
"ShowCasesTableModel.creationDate=Creation Date",
"ShowCasesTableModel.caseNumber=Case Number",
"ShowCasesTableModel.examinerName=Examiner Name",
"ShowCasesTableModel.examinerEmail=Examiner Email",
"ShowCasesTableModel.examinerPhone=Examiner Phone",
"ShowCasesTableModel.notes=Notes",
"ShowCasesTableModel.noData=No Cases"})
/**
* Enum which lists columns of interest from CorrelationCase.
*/
enum TableColumns {
// Ordering here determines displayed column order in Content Viewer.
// If order is changed, update the CellRenderer to ensure correct row coloring.
CASE_NAME(Bundle.ShowCasesTableModel_case(), 200),
CREATION_DATE(Bundle.ShowCasesTableModel_creationDate(), 150),
CASE_NUMBER(Bundle.ShowCasesTableModel_caseNumber(), 100),
EXAMINER_NAME(Bundle.ShowCasesTableModel_examinerName(), 200),
EXAMINER_EMAIL(Bundle.ShowCasesTableModel_examinerEmail(), 100),
EXAMINER_PHONE(Bundle.ShowCasesTableModel_examinerPhone(), 100),
NOTES(Bundle.ShowCasesTableModel_notes(), 450);
private final String columnName;
private final int columnWidth;
TableColumns(String columnName, int columnWidth) {
this.columnName = columnName;
this.columnWidth = columnWidth;
}
String columnName() {
return columnName;
}
int columnWidth() {
return columnWidth;
}
};
/**
* list of Eam Cases from central repository.
*/
private List<CorrelationCase> eamCases;
ShowCasesTableModel() {
eamCases = new ArrayList<>();
}
@Override
public int getColumnCount() {
return TableColumns.values().length;
}
/**
* Get the preferred width that has been configured for this column.
*
* A value of 0 means that no preferred width has been defined for this
* column.
*
* @param colIdx Column index
*
* @return preferred column width >= 0
*/
int getColumnPreferredWidth(int colIdx) {
return TableColumns.values()[colIdx].columnWidth();
}
@Override
public int getRowCount() {
return eamCases.size();
}
@Override
public String getColumnName(int colIdx) {
return TableColumns.values()[colIdx].columnName();
}
@Override
public Object getValueAt(int rowIdx, int colIdx) {
if (eamCases.isEmpty()) {
return Bundle.ShowCasesTableModel_noData();
}
return mapValueById(rowIdx, TableColumns.values()[colIdx]);
}
Object getRow(int rowIdx) {
return eamCases.get(rowIdx);
}
/**
* Map a rowIdx and colId to the value in that cell.
*
* @param rowIdx Index of row to search
* @param colId ID of column to search
*
* @return value in the cell
*/
private Object mapValueById(int rowIdx, TableColumns colId) {
CorrelationCase eamCase = eamCases.get(rowIdx);
String value = Bundle.ShowCasesTableModel_noData();
switch (colId) {
case CASE_NAME:
value = eamCase.getDisplayName();
break;
case CREATION_DATE:
value = eamCase.getCreationDate();
break;
case CASE_NUMBER:
value = eamCase.getCaseNumber();
break;
case EXAMINER_NAME:
value = eamCase.getExaminerName();
break;
case EXAMINER_EMAIL:
value = eamCase.getExaminerEmail();
break;
case EXAMINER_PHONE:
value = eamCase.getExaminerPhone();
break;
case NOTES:
value = eamCase.getNotes();
break;
default:
break;
}
return value;
}
@Override
public Class<String> getColumnClass(int colIdx) {
return String.class;
}
/**
* Add one local central repository case to the table.
*
* @param eamCase central repository case to add to the
* table
*/
void addEamCase(CorrelationCase eamCase) {
eamCases.add(eamCase);
fireTableDataChanged();
}
void clearTable() {
eamCases.clear();
fireTableDataChanged();
}
}

View File

@ -20,13 +20,14 @@
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import java.util.Map; import java.util.Map;
import org.sleuthkit.datamodel.TskData.FileKnown;
/** /**
* Provides logic for selecting common files from all data sources. * Provides logic for selecting common files from all data sources.
*/ */
final class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilder { final public class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilder {
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where (known != 1 OR known IS NULL)%s GROUP BY md5 HAVING COUNT(*) > 1) order by md5"; //NON-NLS private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where (known != "+ FileKnown.KNOWN.getFileKnownValue() + " OR known IS NULL)%s GROUP BY md5 HAVING COUNT(DISTINCT data_source_obj_id) > 1) order by md5"; //NON-NLS
/** /**
* Implements the algorithm for getting common files across all data * Implements the algorithm for getting common files across all data
@ -36,7 +37,7 @@ final class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilde
* @param filterByMediaMimeType match only on files whose mime types can be broadly categorized as media types * @param filterByMediaMimeType match only on files whose mime types can be broadly categorized as media types
* @param filterByDocMimeType match only on files whose mime types can be broadly categorized as document types * @param filterByDocMimeType match only on files whose mime types can be broadly categorized as document types
*/ */
AllDataSourcesCommonFilesAlgorithm(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) { public AllDataSourcesCommonFilesAlgorithm(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) {
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType); super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
} }

View File

@ -7,7 +7,7 @@ CommonFilesPanel.selectedFileCategoriesButton.text=Match on the following file c
CommonFilesPanel.selectedFileCategoriesButton.toolTipText=Select from the options below... CommonFilesPanel.selectedFileCategoriesButton.toolTipText=Select from the options below...
CommonFilesPanel.pictureVideoCheckbox.text=Pictures and Videos CommonFilesPanel.pictureVideoCheckbox.text=Pictures and Videos
CommonFilesPanel.documentsCheckbox.text=Documents CommonFilesPanel.documentsCheckbox.text=Documents
CommonFilesPanel.commonFilesSearchLabel.text=<html>Find duplicate files in the current case.</html> CommonFilesPanel.commonFilesSearchLabel.text=<html>Find files in multiple data sources in the current case.</html>
CommonFilesPanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results... CommonFilesPanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results...
CommonFilesPanel.allFileCategoriesRadioButton.text=Match on all file types CommonFilesPanel.allFileCategoriesRadioButton.text=Match on all file types
CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates: CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates:

View File

@ -20,22 +20,24 @@
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Utility and wrapper model around data required for Common Files Search results. * Utility and wrapper model around data required for Common Files Search results.
* Subclass this to implement different selections of files from the case. * Subclass this to implement different selections of files from the case.
*/ */
final class CommonFilesMetadata { final public class CommonFilesMetadata {
private final Map<String, Md5Metadata> metadata; private final Map<Integer, List<Md5Metadata>> metadata;
/** /**
* Create meta dat object which can be handed off to the node factories * Create a metadata object which can be handed off to the node
* factories.
* *
* @param metadata map of md5 to parent-level node meta data * @param metadata list of Md5Metadata indexed by size of Md5Metadata
*/ */
CommonFilesMetadata(Map<String, Md5Metadata> metadata) { CommonFilesMetadata(Map<Integer, List<Md5Metadata>> metadata){
this.metadata = metadata; this.metadata = metadata;
} }
@ -48,11 +50,11 @@ final class CommonFilesMetadata {
* @param md5 key * @param md5 key
* @return * @return
*/ */
Md5Metadata getMetadataForMd5(String md5) { List<Md5Metadata> getMetadataForMd5(Integer instanceCount) {
return this.metadata.get(md5); return this.metadata.get(instanceCount);
} }
Map<String, Md5Metadata> getMetadata() { public Map<Integer, List<Md5Metadata>> getMetadata() {
return Collections.unmodifiableMap(this.metadata); return Collections.unmodifiableMap(this.metadata);
} }
@ -60,10 +62,13 @@ final class CommonFilesMetadata {
* How many distinct file instances exist for this metadata? * How many distinct file instances exist for this metadata?
* @return number of file instances * @return number of file instances
*/ */
int size() { public int size() {
int count = 0; int count = 0;
for (Md5Metadata data : this.metadata.values()) { for (List<Md5Metadata> data : this.metadata.values()) {
count += data.size(); for(Md5Metadata md5 : data){
count += md5.size();
}
} }
return count; return count;
} }

View File

@ -27,6 +27,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
@ -46,12 +47,12 @@ import org.sleuthkit.datamodel.TskCoreException;
* This entire thing runs on a background thread where exceptions are handled. * This entire thing runs on a background thread where exceptions are handled.
*/ */
@SuppressWarnings("PMD.AbstractNaming") @SuppressWarnings("PMD.AbstractNaming")
abstract class CommonFilesMetadataBuilder { public abstract class CommonFilesMetadataBuilder {
private final Map<Long, String> dataSourceIdToNameMap; private final Map<Long, String> dataSourceIdToNameMap;
private final boolean filterByMedia; private final boolean filterByMedia;
private final boolean filterByDoc; private final boolean filterByDoc;
private static final String filterByMimeTypesWhereClause = " and mime_type in (%s)"; //NON-NLS // where %s is csv list of mime_types to filter on private static final String FILTER_BY_MIME_TYPES_WHERE_CLAUSE = " and mime_type in (%s)"; //NON-NLS // where %s is csv list of mime_types to filter on
/* /*
* The set of the MIME types that will be checked for extension mismatches * The set of the MIME types that will be checked for extension mismatches
@ -199,7 +200,21 @@ abstract class CommonFilesMetadataBuilder {
} }
} }
return new CommonFilesMetadata(commonFiles); Map<Integer, List<Md5Metadata>> instanceCollatedCommonFiles = new TreeMap<>();
for(Md5Metadata md5Metadata : commonFiles.values()){
Integer size = md5Metadata.size();
if(instanceCollatedCommonFiles.containsKey(size)){
instanceCollatedCommonFiles.get(size).add(md5Metadata);
} else {
ArrayList<Md5Metadata> value = new ArrayList<>();
value.add(md5Metadata);
instanceCollatedCommonFiles.put(size, value);
}
}
return new CommonFilesMetadata(instanceCollatedCommonFiles);
} }
/** /**
@ -228,7 +243,7 @@ abstract class CommonFilesMetadataBuilder {
mimeTypeFilter.append("'").append(mimeType).append("',"); mimeTypeFilter.append("'").append(mimeType).append("',");
} }
mimeTypeString = mimeTypeFilter.toString().substring(0, mimeTypeFilter.length() - 1); mimeTypeString = mimeTypeFilter.toString().substring(0, mimeTypeFilter.length() - 1);
mimeTypeString = String.format(filterByMimeTypesWhereClause, new Object[]{mimeTypeString}); mimeTypeString = String.format(FILTER_BY_MIME_TYPES_WHERE_CLAUSE, new Object[]{mimeTypeString});
} }
return mimeTypeString; return mimeTypeString;
} }

View File

@ -23,20 +23,18 @@ import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.datamodel.Md5Node;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
/** /**
* Wrapper node for <code>Md5Node</code> used to display common files search * Wrapper node for <code>Md5Node</code> used to display common files search
* results in the top right pane. Calls <code>Md5NodeFactory</code>. * results in the top right pane. Calls <code>InstanceCountNodeFactory</code>.
*/ */
final public class CommonFilesNode extends DisplayableItemNode { final public class CommonFilesNode extends DisplayableItemNode {
CommonFilesNode(CommonFilesMetadata metadataList) { CommonFilesNode(CommonFilesMetadata metadataList) {
super(Children.create(new Md5NodeFactory(metadataList), true), Lookups.singleton(CommonFilesNode.class)); super(Children.create(new InstanceCountNodeFactory(metadataList), true));
} }
@NbBundle.Messages({ @NbBundle.Messages({
@ -62,35 +60,31 @@ final public class CommonFilesNode extends DisplayableItemNode {
} }
/** /**
* ChildFactory which builds CommonFileParentNodes from the * Used to generate <code>InstanceCountNode</code>s.
* CommonFilesMetaaData models.
*/ */
static class Md5NodeFactory extends ChildFactory<String> { static class InstanceCountNodeFactory extends ChildFactory<Integer>{
private final CommonFilesMetadata metadata;
/** /**
* List of models, each of which is a parent node matching a single md5, * Build a factory which converts a <code>CommonFilesMetadata</code>
* containing children FileNodes. * object into <code>DisplayableItemNode</code>s.
* @param metadata
*/ */
private CommonFilesMetadata metadata; InstanceCountNodeFactory(CommonFilesMetadata metadata){
Md5NodeFactory(CommonFilesMetadata metadata) {
this.metadata = metadata; this.metadata = metadata;
} }
protected void removeNotify() {
metadata = null;
}
@Override @Override
protected Node createNodeForKey(String md5){ protected boolean createKeys(List<Integer> list) {
Md5Metadata metadata = this.metadata.getMetadataForMd5(md5);
return new Md5Node(metadata);
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(this.metadata.getMetadata().keySet()); list.addAll(this.metadata.getMetadata().keySet());
return true; return true;
} }
@Override
protected Node createNodeForKey(Integer instanceCount){
List<Md5Metadata> md5Metadata = this.metadata.getMetadataForMd5(instanceCount);
return new InstanceCountNode(instanceCount, md5Metadata);
}
} }
} }

View File

@ -18,12 +18,9 @@
*/ */
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import java.io.File;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -31,10 +28,11 @@ import java.util.logging.Level;
import javax.swing.ComboBoxModel; import javax.swing.ComboBoxModel;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerManager;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
@ -42,8 +40,6 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -97,10 +93,6 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
new SwingWorker<Map<Long, String>, Void>() { new SwingWorker<Map<Long, String>, Void>() {
private static final String SELECT_DATA_SOURCES_LOGICAL = "select obj_id, name from tsk_files where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))";
private static final String SELECT_DATA_SOURCES_IMAGE = "select obj_id, name from tsk_image_names where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))";
private void updateUi() { private void updateUi() {
String[] dataSourcesNames = new String[CommonFilesPanel.this.dataSourceMap.size()]; String[] dataSourcesNames = new String[CommonFilesPanel.this.dataSourceMap.size()];
@ -112,12 +104,15 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
CommonFilesPanel.this.selectDataSourceComboBox.setModel(CommonFilesPanel.this.dataSourcesList); CommonFilesPanel.this.selectDataSourceComboBox.setModel(CommonFilesPanel.this.dataSourcesList);
boolean multipleDataSources = this.caseHasMultipleSources(); boolean multipleDataSources = this.caseHasMultipleSources();
CommonFilesPanel.this.allDataSourcesRadioButton.setEnabled(multipleDataSources);
CommonFilesPanel.this.allDataSourcesRadioButton.setSelected(multipleDataSources); CommonFilesPanel.this.allDataSourcesRadioButton.setEnabled(true);
CommonFilesPanel.this.allDataSourcesRadioButton.setSelected(true);
if (!multipleDataSources) { if (!multipleDataSources) {
CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(true); CommonFilesPanel.this.withinDataSourceRadioButton.setEnabled(false);
withinDataSourceSelected(true); CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(false);
withinDataSourceSelected(false);
CommonFilesPanel.this.selectDataSourceComboBox.setEnabled(false);
} }
CommonFilesPanel.this.searchButton.setEnabled(true); CommonFilesPanel.this.searchButton.setEnabled(true);
@ -128,51 +123,13 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
} }
private boolean caseHasMultipleSources() { private boolean caseHasMultipleSources() {
return CommonFilesPanel.this.dataSourceMap.size() >= 2; return CommonFilesPanel.this.dataSourceMap.size() >= 3;
}
private void loadLogicalSources(SleuthkitCase tskDb, Map<Long, String> dataSouceMap) throws TskCoreException, SQLException {
//try block releases resources - exceptions are handled in done()
try (
CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_LOGICAL);
ResultSet resultSet = query.getResultSet()) {
while (resultSet.next()) {
Long objectId = resultSet.getLong(1);
String dataSourceName = resultSet.getString(2);
dataSouceMap.put(objectId, dataSourceName);
}
}
}
private void loadImageSources(SleuthkitCase tskDb, Map<Long, String> dataSouceMap) throws SQLException, TskCoreException {
//try block releases resources - exceptions are handled in done()
try (
CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_IMAGE);
ResultSet resultSet = query.getResultSet()) {
while (resultSet.next()) {
Long objectId = resultSet.getLong(1);
String dataSourceName = resultSet.getString(2);
File image = new File(dataSourceName);
String dataSourceNameTrimmed = image.getName();
dataSouceMap.put(objectId, dataSourceNameTrimmed);
}
}
} }
@Override @Override
protected Map<Long, String> doInBackground() throws NoCurrentCaseException, TskCoreException, SQLException { protected Map<Long, String> doInBackground() throws NoCurrentCaseException, TskCoreException, SQLException {
DataSourceLoader loader = new DataSourceLoader();
Map<Long, String> dataSouceMap = new HashMap<>(); return loader.getDataSourceMap();
Case currentCase = Case.getCurrentCaseThrows();
SleuthkitCase tskDb = currentCase.getSleuthkitCase();
loadLogicalSources(tskDb, dataSouceMap);
loadImageSources(tskDb, dataSouceMap);
return dataSouceMap;
} }
@Override @Override
@ -212,6 +169,8 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
"CommonFilesPanel.search.results.titleAll=Common Files (All Data Sources)", "CommonFilesPanel.search.results.titleAll=Common Files (All Data Sources)",
"CommonFilesPanel.search.results.titleSingle=Common Files (Match Within Data Source: %s)", "CommonFilesPanel.search.results.titleSingle=Common Files (Match Within Data Source: %s)",
"CommonFilesPanel.search.results.pathText=Common Files Search Results", "CommonFilesPanel.search.results.pathText=Common Files Search Results",
"CommonFilesPanel.search.done.searchProgressGathering=Gathering Common Files Search Results.",
"CommonFilesPanel.search.done.searchProgressDisplay=Displaying Common Files Search Results.",
"CommonFilesPanel.search.done.tskCoreException=Unable to run query against DB.", "CommonFilesPanel.search.done.tskCoreException=Unable to run query against DB.",
"CommonFilesPanel.search.done.noCurrentCaseException=Unable to open case file.", "CommonFilesPanel.search.done.noCurrentCaseException=Unable to open case file.",
"CommonFilesPanel.search.done.exception=Unexpected exception running Common Files Search.", "CommonFilesPanel.search.done.exception=Unexpected exception running Common Files Search.",
@ -223,6 +182,7 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
new SwingWorker<CommonFilesMetadata, Void>() { new SwingWorker<CommonFilesMetadata, Void>() {
private String tabTitle; private String tabTitle;
private ProgressHandle progress;
private void setTitleForAllDataSources() { private void setTitleForAllDataSources() {
this.tabTitle = Bundle.CommonFilesPanel_search_results_titleAll(); this.tabTitle = Bundle.CommonFilesPanel_search_results_titleAll();
@ -250,7 +210,11 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
@Override @Override
@SuppressWarnings({"BoxedValueEquality", "NumberEquality"}) @SuppressWarnings({"BoxedValueEquality", "NumberEquality"})
protected CommonFilesMetadata doInBackground() throws TskCoreException, NoCurrentCaseException, SQLException { protected CommonFilesMetadata doInBackground() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
progress = ProgressHandle.createHandle(Bundle.CommonFilesPanel_search_done_searchProgressGathering());
progress.start();
progress.switchToIndeterminate();
Long dataSourceId = determineDataSourceId(); Long dataSourceId = determineDataSourceId();
CommonFilesMetadataBuilder builder; CommonFilesMetadataBuilder builder;
@ -285,22 +249,21 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
protected void done() { protected void done() {
try { try {
super.done(); super.done();
CommonFilesMetadata metadata = get(); CommonFilesMetadata metadata = get();
CommonFilesNode commonFilesNode = new CommonFilesNode(metadata); CommonFilesNode commonFilesNode = new CommonFilesNode(metadata);
//TODO this could be enumerating the children!!!
DataResultFilterNode dataResultFilterNode = new DataResultFilterNode(commonFilesNode, ExplorerManager.find(CommonFilesPanel.this)); DataResultFilterNode dataResultFilterNode = new DataResultFilterNode(commonFilesNode, ExplorerManager.find(CommonFilesPanel.this));
TableFilterNode tableFilterWithDescendantsNode = new TableFilterNode(dataResultFilterNode); TableFilterNode tableFilterWithDescendantsNode = new TableFilterNode(dataResultFilterNode, 3);
DataResultViewerTable table = new DataResultViewerTable(); DataResultViewerTable table = new CommonFilesSearchResultsViewerTable();
Collection<DataResultViewer> viewers = new ArrayList<>(1); Collection<DataResultViewer> viewers = new ArrayList<>(1);
viewers.add(table); viewers.add(table);
progress.setDisplayName(Bundle.CommonFilesPanel_search_done_searchProgressDisplay());
DataResultTopComponent.createInstance(tabTitle, pathText, tableFilterWithDescendantsNode, metadata.size(), viewers); DataResultTopComponent.createInstance(tabTitle, pathText, tableFilterWithDescendantsNode, metadata.size(), viewers);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, "Interrupted while loading Common Files", ex); LOGGER.log(Level.SEVERE, "Interrupted while loading Common Files", ex);
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_search_done_interupted()); MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_search_done_interupted());
@ -321,6 +284,8 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
errorMessage = Bundle.CommonFilesPanel_search_done_exception(); errorMessage = Bundle.CommonFilesPanel_search_done_exception();
} }
MessageNotifyUtil.Message.error(errorMessage); MessageNotifyUtil.Message.error(errorMessage);
} finally {
progress.finish();
} }
} }
}.execute(); }.execute();

View File

@ -19,11 +19,13 @@
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.util.logging.Level;
import org.openide.util.HelpCtx; import org.openide.util.HelpCtx;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction; import org.openide.util.actions.CallableSystemAction;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.coreutils.Logger;
/** /**
* Encapsulates a menu action which triggers the common files search dialog. * Encapsulates a menu action which triggers the common files search dialog.
@ -32,6 +34,7 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
private static CommonFilesSearchAction instance = null; private static CommonFilesSearchAction instance = null;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(CommonFilesSearchAction.class.getName());
CommonFilesSearchAction() { CommonFilesSearchAction() {
super(); super();
@ -40,7 +43,13 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
@Override @Override
public boolean isEnabled(){ public boolean isEnabled(){
return super.isEnabled() && Case.isCaseOpen() && Installer.isJavaFxInited(); boolean shouldBeEnabled = false;
try {
shouldBeEnabled = Case.isCaseOpen() && Case.getCurrentCase().getDataSources().size() > 1;
} catch(TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting data sources for action enabled check", ex);
}
return super.isEnabled() && shouldBeEnabled;
} }
public static synchronized CommonFilesSearchAction getDefault() { public static synchronized CommonFilesSearchAction getDefault() {

View File

@ -0,0 +1,92 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2018 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.commonfilesearch;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
/**
* <code>DataResultViewerTable</code> which overrides the default column header
* width calculations. The <code>CommonFilesSearchResultsViewerTable</code>
* presents multiple tiers of data which are not always present and it may not
* make sense to try to calculate the column widths for such tables by sampling
* rows and looking for wide cells. Rather, we just pick some reasonable values.
*/
public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
private static final Map<String, Integer> COLUMN_WIDTHS;
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(CommonFilesSearchResultsViewerTable.class.getName());
private static final int DEFAULT_WIDTH = 100;
static {
Map<String, Integer> map = new HashMap<>();
map.put(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), 260);
map.put(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), 65);
map.put(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), 300);
map.put(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), 200);
map.put(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), 100);
map.put(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), 130);
map.put(Bundle.CommonFilesSearchResultsViewerTable_tagsColLbl1(), 300);
COLUMN_WIDTHS = Collections.unmodifiableMap(map);
}
@NbBundle.Messages({
"CommonFilesSearchResultsViewerTable.filesColLbl=Files",
"CommonFilesSearchResultsViewerTable.instancesColLbl=Instances",
"CommonFilesSearchResultsViewerTable.pathColLbl=Parent Path",
"CommonFilesSearchResultsViewerTable.hashsetHitsColLbl=Hash Set Hits",
"CommonFilesSearchResultsViewerTable.dataSourceColLbl=Data Source(s)",
"CommonFilesSearchResultsViewerTable.mimeTypeColLbl=MIME Type",
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
})
@Override
protected void setColumnWidths() {
TableColumnModel model = this.getColumnModel();
Enumeration<TableColumn> columnsEnumerator = model.getColumns();
while (columnsEnumerator.hasMoreElements()) {
TableColumn column = columnsEnumerator.nextElement();
final String headerValue = column.getHeaderValue().toString();
final Integer defaultWidth = COLUMN_WIDTHS.get(headerValue);
if(defaultWidth == null){
column.setPreferredWidth(DEFAULT_WIDTH);
LOGGER.log(Level.SEVERE, String.format("Tried to set width on a column not supported by the CommonFilesSearchResultsViewerTable: %s", headerValue));
} else {
column.setPreferredWidth(defaultWidth);
}
}
}
}

View File

@ -0,0 +1,95 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2018 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.commonfilesearch;
import java.io.File;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Encapsulates logic required to create a mapping of data sources in the
* current case to their data source IDs.
*
* Intended to be used within the context of a SwingWorker or other background
* thread.
*/
public class DataSourceLoader {
private static final String SELECT_DATA_SOURCES_LOGICAL = "select obj_id, name from tsk_files where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))";
private static final String SELECT_DATA_SOURCES_IMAGE = "select obj_id, name from tsk_image_names where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))";
private void loadLogicalSources(SleuthkitCase tskDb, Map<Long, String> dataSouceMap) throws TskCoreException, SQLException {
//try block releases resources - exceptions are handled in done()
try (
SleuthkitCase.CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_LOGICAL);
ResultSet resultSet = query.getResultSet()
) {
while (resultSet.next()) {
Long objectId = resultSet.getLong(1);
String dataSourceName = resultSet.getString(2);
dataSouceMap.put(objectId, dataSourceName);
}
}
}
private void loadImageSources(SleuthkitCase tskDb, Map<Long, String> dataSouceMap) throws SQLException, TskCoreException {
//try block releases resources - exceptions are handled in done()
try (
SleuthkitCase.CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_IMAGE);
ResultSet resultSet = query.getResultSet()) {
while (resultSet.next()) {
Long objectId = resultSet.getLong(1);
String dataSourceName = resultSet.getString(2);
File image = new File(dataSourceName);
String dataSourceNameTrimmed = image.getName();
dataSouceMap.put(objectId, dataSourceNameTrimmed);
}
}
}
/**
* Get a map of data source Ids to their string names for the current case.
*
* @return Map of Long (id) to String (name)
* @throws NoCurrentCaseException
* @throws TskCoreException
* @throws SQLException
*/
public Map<Long, String> getDataSourceMap() throws NoCurrentCaseException, TskCoreException, SQLException {
Map<Long, String> dataSouceMap = new HashMap<>();
Case currentCase = Case.getCurrentCaseThrows();
SleuthkitCase tskDb = currentCase.getSleuthkitCase();
loadLogicalSources(tskDb, dataSouceMap);
loadImageSources(tskDb, dataSouceMap);
return dataSouceMap;
}
}

View File

@ -0,0 +1,88 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.commonfilesearch;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Used by the Common Files search feature to encapsulate instances of a given
MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
*/
public class FileInstanceNode extends FileNode {
private final String dataSource;
/**
* Create a node which can be used in a multilayer tree table and is based
* on an <code>AbstractFile</code>.
*
* @param fsContent
* @param dataSource
*/
public FileInstanceNode(AbstractFile fsContent, String dataSource) {
super(fsContent);
this.dataSource = dataSource;
this.setDisplayName(fsContent.getName());
}
@Override
public boolean isLeafTypeNode(){
//Not used atm - could maybe be leveraged for better use in Children objects
return true;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
String getDataSource() {
return this.dataSource;
}
@NbBundle.Messages({"FileInstanceNode.createSheet.noDescription= "})
@Override
protected Sheet createSheet() {
Sheet sheet = new Sheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
final String NO_DESCR = Bundle.FileInstanceNode_createSheet_noDescription();
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsForFile(this.getContent())));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
this.addTagProperty(sheetSet);
return sheet;
}
}

View File

@ -0,0 +1,146 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2018 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.commonfilesearch;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
/**
* Node used to indicate the number of matches found with the MD5 children
* of this Node.
*/
final public class InstanceCountNode extends DisplayableItemNode {
final private int instanceCount;
final private List<Md5Metadata> metadataList;
/**
* Create a node with the given number of instances, and the given
* selection of metadata.
* @param instanceCount
* @param md5Metadata
*/
@NbBundle.Messages({
"InstanceCountNode.displayName=Files with %s instances (%s)"
})
public InstanceCountNode(int instanceCount, List<Md5Metadata> md5Metadata) {
super(Children.create(new Md5NodeFactory(md5Metadata), true));
this.instanceCount = instanceCount;
this.metadataList = md5Metadata;
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), md5Metadata.size()));
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
}
/**
* Number of matches found for each of the MD5 children.
* @return int match count
*/
int getInstanceCount() {
return this.instanceCount;
}
/**
* Get a list of metadata for the MD5s which are children of this object.
* @return List<Md5Metadata>
*/
List<Md5Metadata> getMetadata() {
return Collections.unmodifiableList(this.metadataList);
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public String getItemType() {
return getClass().getName();
}
@NbBundle.Messages({"InstanceCountNode.createSheet.noDescription= "})
@Override
protected Sheet createSheet() {
Sheet sheet = new Sheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription();
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), NO_DESCR, this.getInstanceCount()));
return sheet;
}
/**
* ChildFactory which builds CommonFileParentNodes from the
* CommonFilesMetaaData models.
*/
static class Md5NodeFactory extends ChildFactory<String> {
/**
* List of models, each of which is a parent node matching a single md5,
* containing children FileNodes.
*/
private final Map<String, Md5Metadata> metadata;
Md5NodeFactory(List<Md5Metadata> metadata) {
this.metadata = new HashMap<>();
Iterator<Md5Metadata> iterator = metadata.iterator();
while (iterator.hasNext()) {
Md5Metadata md5Metadata = iterator.next();
this.metadata.put(md5Metadata.getMd5(), md5Metadata);
}
}
@Override
protected Node createNodeForKey(String md5) {
Md5Metadata md5Metadata = this.metadata.get(md5);
return new Md5Node(md5Metadata);
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(this.metadata.keySet());
return true;
}
}
}

View File

@ -17,23 +17,21 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.commonfilesearch;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceMetadata;
import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -52,30 +50,50 @@ public class Md5Node extends DisplayableItemNode {
private final int commonFileCount; private final int commonFileCount;
private final String dataSources; private final String dataSources;
@NbBundle.Messages({
"Md5Node.Md5Node.format=MD5: %s"
})
/**
* Create a Match node whose children will all have this object in common.
* @param data the common feature, and the children
*/
public Md5Node(Md5Metadata data) { public Md5Node(Md5Metadata data) {
super(Children.create( super(Children.create(
new FileInstanceNodeFactory(data), true), new FileInstanceNodeFactory(data), true));
Lookups.singleton(data.getMd5()));
this.commonFileCount = data.size(); this.commonFileCount = data.size();
this.dataSources = String.join(", ", data.getDataSources()); this.dataSources = String.join(", ", data.getDataSources());
this.md5Hash = data.getMd5(); this.md5Hash = data.getMd5();
this.setDisplayName(this.md5Hash); this.setDisplayName(String.format(Bundle.Md5Node_Md5Node_format(), this.md5Hash));
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
} }
/**
* How many files are in common? This will be the number of children.
* @return int
*/
int getCommonFileCount() { int getCommonFileCount() {
return this.commonFileCount; return this.commonFileCount;
} }
/**
* Datasources where these matches occur.
* @return string delimited list of sources
*/
String getDataSources() { String getDataSources() {
return this.dataSources; return this.dataSources;
} }
/**
* MD5 which is common to these matches
* @return string md5 hash
*/
public String getMd5() { public String getMd5() {
return this.md5Hash; return this.md5Hash;
} }
@NbBundle.Messages({"Md5Node.createSheet.noDescription= "})
@Override @Override
protected Sheet createSheet() { protected Sheet createSheet() {
Sheet sheet = new Sheet(); Sheet sheet = new Sheet();
@ -85,30 +103,15 @@ public class Md5Node extends DisplayableItemNode {
sheet.put(sheetSet); sheet.put(sheetSet);
} }
Map<String, Object> map = new LinkedHashMap<>(); final String NO_DESCR = Bundle.Md5Node_createSheet_noDescription();
fillPropertyMap(map, this); sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, ""));
final String NO_DESCR = Bundle.AbstractFsContentNode_noDesc_text(); sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, ""));
for (Md5Node.CommonFileParentPropertyType propType : Md5Node.CommonFileParentPropertyType.values()) { sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSources()));
final String propString = propType.toString();
sheetSet.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
}
return sheet; return sheet;
} }
/**
* Fill map with AbstractFile properties
*
* @param map map with preserved ordering, where property names/values are
* put
* @param node The item to get properties for.
*/
static private void fillPropertyMap(Map<String, Object> map, Md5Node node) {
map.put(CommonFileParentPropertyType.File.toString(), node.getMd5());
map.put(CommonFileParentPropertyType.InstanceCount.toString(), node.getCommonFileCount());
map.put(CommonFileParentPropertyType.DataSource.toString(), node.getDataSources());
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) { public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
@ -144,9 +147,7 @@ public class Md5Node extends DisplayableItemNode {
AbstractFile abstractFile = tskDb.findAllFilesWhere(String.format("obj_id in (%s)", file.getObjectId())).get(0); AbstractFile abstractFile = tskDb.findAllFilesWhere(String.format("obj_id in (%s)", file.getObjectId())).get(0);
return new FileInstanceNode(abstractFile, file.getDataSourceName()); return new FileInstanceNode(abstractFile, file.getDataSourceName());
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException | TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to create node for file with obj_id: %s.", new Object[]{file.getObjectId()}), ex);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to create node for file with obj_id: %s.", new Object[]{file.getObjectId()}), ex); LOGGER.log(Level.SEVERE, String.format("Unable to create node for file with obj_id: %s.", new Object[]{file.getObjectId()}), ex);
} }
return null; return null;
@ -159,25 +160,4 @@ public class Md5Node extends DisplayableItemNode {
} }
} }
@NbBundle.Messages({
"CommonFileParentPropertyType.fileColLbl=File",
"CommonFileParentPropertyType.instanceColLbl=Instance Count",
"CommonFileParentPropertyType.dataSourceColLbl=Data Source"})
public enum CommonFileParentPropertyType {
File(Bundle.CommonFileParentPropertyType_fileColLbl()),
InstanceCount(Bundle.CommonFileParentPropertyType_instanceColLbl()),
DataSource(Bundle.CommonFileParentPropertyType_dataSourceColLbl());
final private String displayString;
private CommonFileParentPropertyType(String displayString) {
this.displayString = displayString;
}
@Override
public String toString() {
return displayString;
}
}
} }

View File

@ -20,13 +20,14 @@
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import java.util.Map; import java.util.Map;
import org.sleuthkit.datamodel.TskData.FileKnown;
/** /**
* Provides logic for selecting common files from a single data source. * Provides logic for selecting common files from a single data source.
*/ */
final class SingleDataSource extends CommonFilesMetadataBuilder { final public class SingleDataSource extends CommonFilesMetadataBuilder {
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where md5 in (select md5 from tsk_files where (known != 1 OR known IS NULL) and data_source_obj_id=%s%s) GROUP BY md5 HAVING COUNT(*) > 1) order by md5"; //NON-NLS private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where md5 in (select md5 from tsk_files where (known != "+ FileKnown.KNOWN.getFileKnownValue() + " OR known IS NULL) and data_source_obj_id=%s%s) GROUP BY md5 HAVING COUNT(DISTINCT data_source_obj_id) > 1) order by md5"; //NON-NLS
private final Long selectedDataSourceId; private final Long selectedDataSourceId;
private final String dataSourceName; private final String dataSourceName;
@ -35,10 +36,12 @@ final class SingleDataSource extends CommonFilesMetadataBuilder {
* once in the given data source * once in the given data source
* @param dataSourceId data source id for which common files must appear at least once * @param dataSourceId data source id for which common files must appear at least once
* @param dataSourceIdMap a map of obj_id to datasource name * @param dataSourceIdMap a map of obj_id to datasource name
* @param filterByMediaMimeType match only on files whose mime types can be broadly categorized as media types * @param filterByMediaMimeType match only on files whose mime types can be
* @param filterByDocMimeType match only on files whose mime types can be broadly categorized as document types * broadly categorized as media types
* @param filterByDocMimeType match only on files whose mime types can be
* broadly categorized as document types
*/ */
SingleDataSource(Long dataSourceId, Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) { public SingleDataSource(Long dataSourceId, Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) {
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType); super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
this.selectedDataSourceId = dataSourceId; this.selectedDataSourceId = dataSourceId;
this.dataSourceName = dataSourceIdMap.get(this.selectedDataSourceId); this.dataSourceName = dataSourceIdMap.get(this.selectedDataSourceId);

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