From 47ca246dcb6a6a3ac794f060136c0faef7b1a790 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 27 Jul 2016 07:53:09 -0400 Subject: [PATCH 01/19] Preliminary encoding working --- .../SevenZipExtractor.java | 8 ++- .../embeddedfileextractor/xorTest.java | 53 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/xorTest.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index b4d8109988..1db31c4348 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -29,6 +29,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.Base64; import java.util.List; import java.util.logging.Level; import net.sf.sevenzipjbinding.ArchiveFormat; @@ -624,8 +625,11 @@ class SevenZipExtractor { UnpackStream(String localAbsPath) { this.localAbsPath = localAbsPath; try { - output = new BufferedOutputStream(new FileOutputStream(localAbsPath)); - } catch (FileNotFoundException ex) { + //output = Base64.getEncoder().wrap( + // new BufferedOutputStream(new FileOutputStream(localAbsPath))); + output = new xorTest(new BufferedOutputStream(new FileOutputStream(localAbsPath))); + //output = new BufferedOutputStream(new FileOutputStream(localAbsPath)); + } catch (IOException ex) { logger.log(Level.SEVERE, "Error writing extracted file: " + localAbsPath, ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/xorTest.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/xorTest.java new file mode 100644 index 0000000000..cbbeeee25a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/xorTest.java @@ -0,0 +1,53 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.modules.embeddedfileextractor; + +import java.io.BufferedOutputStream; +import java.io.OutputStream; +import java.io.IOException; +/** + * + */ +public class xorTest extends BufferedOutputStream{ + final private String HEADER = "XOR_AUTOPSY_HEADER_xxxxxxxxxxxxx"; + final private int HEADER_LENGTH = HEADER.length(); + + public xorTest(OutputStream out) throws IOException{ + super(out); + writeHeader(); + } + + public xorTest(OutputStream out, int size) throws IOException{ + super(out, size); + writeHeader(); + } + + private void writeHeader() throws IOException{ + write(HEADER.getBytes(), 0, HEADER_LENGTH); + } + + private byte encode(byte b){ + return ((byte)(b ^ 0xa5)); + } + + @Override + public void write(int b) throws IOException{ + super.write((int)encode((byte)b)); + } + + @Override + public void write(byte[] b, + int off, + int len) + throws IOException{ + byte[] encodedData = b.clone(); // Could be more efficient + for(int i = 0;i < b.length;i++){ + encodedData[i] = encode(b[i]); + } + + super.write(encodedData, off, len); + } +} From 19370091dd10d8dfc3a13a4a49839bafcb681cb1 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 27 Jul 2016 10:53:27 -0400 Subject: [PATCH 02/19] Add encoding to ImageExtractor --- .../autopsy/modules/embeddedfileextractor/ImageExtractor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index dd7ae145fe..29cb2059e6 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -591,7 +591,8 @@ class ImageExtractor { * specified location. */ private void writeExtractedImage(String outputPath, byte[] data) { - try (FileOutputStream fos = new FileOutputStream(outputPath)) { + //try (FileOutputStream fos = new FileOutputStream(outputPath)) { + try (xorTest fos = new xorTest(new FileOutputStream(outputPath))) { fos.write(data); } catch (IOException ex) { logger.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS From 8ab324518813ae2994e7c8bcd8c5673ecf4f5c67 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 3 Aug 2016 07:48:54 -0400 Subject: [PATCH 03/19] Cleanup --- .../embeddedfileextractor/ImageExtractor.java | 4 +- .../SevenZipExtractor.java | 8 +-- .../embeddedfileextractor/xorTest.java | 53 ------------------- 3 files changed, 4 insertions(+), 61 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/xorTest.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index 29cb2059e6..7e6b3fbeff 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -46,6 +46,7 @@ import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.EncodedFileStream; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; @@ -591,8 +592,7 @@ class ImageExtractor { * specified location. */ private void writeExtractedImage(String outputPath, byte[] data) { - //try (FileOutputStream fos = new FileOutputStream(outputPath)) { - try (xorTest fos = new xorTest(new FileOutputStream(outputPath))) { + try (EncodedFileStream fos = new EncodedFileStream(new FileOutputStream(outputPath))) { fos.write(data); } catch (IOException ex) { logger.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 1db31c4348..1bc95f2e84 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.modules.embeddedfileextractor; import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -29,7 +28,6 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.Date; -import java.util.Base64; import java.util.List; import java.util.logging.Level; import net.sf.sevenzipjbinding.ArchiveFormat; @@ -61,6 +59,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DerivedFile; +import org.sleuthkit.datamodel.EncodedFileStream; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -625,10 +624,7 @@ class SevenZipExtractor { UnpackStream(String localAbsPath) { this.localAbsPath = localAbsPath; try { - //output = Base64.getEncoder().wrap( - // new BufferedOutputStream(new FileOutputStream(localAbsPath))); - output = new xorTest(new BufferedOutputStream(new FileOutputStream(localAbsPath))); - //output = new BufferedOutputStream(new FileOutputStream(localAbsPath)); + output = new EncodedFileStream(new FileOutputStream(localAbsPath)); } catch (IOException ex) { logger.log(Level.SEVERE, "Error writing extracted file: " + localAbsPath, ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/xorTest.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/xorTest.java deleted file mode 100644 index cbbeeee25a..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/xorTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.modules.embeddedfileextractor; - -import java.io.BufferedOutputStream; -import java.io.OutputStream; -import java.io.IOException; -/** - * - */ -public class xorTest extends BufferedOutputStream{ - final private String HEADER = "XOR_AUTOPSY_HEADER_xxxxxxxxxxxxx"; - final private int HEADER_LENGTH = HEADER.length(); - - public xorTest(OutputStream out) throws IOException{ - super(out); - writeHeader(); - } - - public xorTest(OutputStream out, int size) throws IOException{ - super(out, size); - writeHeader(); - } - - private void writeHeader() throws IOException{ - write(HEADER.getBytes(), 0, HEADER_LENGTH); - } - - private byte encode(byte b){ - return ((byte)(b ^ 0xa5)); - } - - @Override - public void write(int b) throws IOException{ - super.write((int)encode((byte)b)); - } - - @Override - public void write(byte[] b, - int off, - int len) - throws IOException{ - byte[] encodedData = b.clone(); // Could be more efficient - for(int i = 0;i < b.length;i++){ - encodedData[i] = encode(b[i]); - } - - super.write(encodedData, off, len); - } -} From e7d258d70588966d0750c80d8bdfdd183784b22b Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 5 Aug 2016 09:40:48 -0400 Subject: [PATCH 04/19] First pass at storing encoding in the database --- .../casemodule/SingleUserCaseConverter.java | 5 +- .../casemodule/services/FileManager.java | 82 ++++++++++++++++++- .../embeddedfileextractor/ImageExtractor.java | 7 +- .../SevenZipExtractor.java | 8 +- 4 files changed, 89 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index 95d94d1f23..f5e29f758d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -489,9 +489,10 @@ public class SingleUserCaseConverter { if (value > biggestPK) { biggestPK = value; } - outputStatement.executeUpdate("INSERT INTO tsk_files_path (obj_id, path) VALUES (" //NON-NLS + outputStatement.executeUpdate("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (" //NON-NLS + value + ", '" - + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(2)) + "')"); //NON-NLS + + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(2)) + ", " + + inputResultSet.getInt(3)+ "')"); //NON-NLS } catch (SQLException ex) { if (ex.getErrorCode() != 0) { // 0 if the entry already exists throw new SQLException(ex); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index 2787924d93..c72b624f64 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -44,6 +44,7 @@ import org.sleuthkit.datamodel.LocalFilesDataSource; import org.sleuthkit.datamodel.TskDataException; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.datamodel.CarvingResult; +import org.sleuthkit.datamodel.TskData; /** * A manager that provides methods for retrieving files from the current case @@ -302,6 +303,7 @@ public class FileManager implements Closeable { * currently unused. * @param otherDetails Other details of the derivation method or tool, * currently unused. + * @param encodingType Type of encoding used on the file * * @return A DerivedFile object representing the derived file. * @@ -314,13 +316,14 @@ public class FileManager implements Closeable { long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parentFile, - String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException { + String rederiveDetails, String toolName, String toolVersion, String otherDetails, + TskData.EncodingType encodingType) throws TskCoreException { if (null == caseDb) { throw new TskCoreException("File manager has been closed"); } return caseDb.addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime, - isFile, parentFile, rederiveDetails, toolName, toolVersion, otherDetails); + isFile, parentFile, rederiveDetails, toolName, toolVersion, otherDetails, encodingType); } /** @@ -491,6 +494,7 @@ public class FileManager implements Closeable { * @param localFile The local/logical file or directory. * @param addProgressUpdater notifier to receive progress notifications on * folders added, or null if not used + * @param encodingType Type of encoding used when storing the file * * @returns File object of file added or new virtualdirectory for the * directory. @@ -502,7 +506,8 @@ public class FileManager implements Closeable { * @throws TskCoreException If there is a problem completing a database * operation. */ - private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, FileAddProgressUpdater progressUpdater) throws TskCoreException { + private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, + TskData.EncodingType encodingType, FileAddProgressUpdater progressUpdater) throws TskCoreException { if (localFile.isDirectory()) { /* * Add the directory as a virtual directory. @@ -524,7 +529,7 @@ public class FileManager implements Closeable { } else { return caseDb.addLocalFile(localFile.getName(), localFile.getAbsolutePath(), localFile.length(), 0, 0, 0, 0, - localFile.isFile(), parentDirectory, trans); + localFile.isFile(), encodingType, parentDirectory, trans); } } @@ -619,5 +624,74 @@ public class FileManager implements Closeable { } return caseDb.addCarvedFiles(filesToAdd); } + + /** + * Adds a derived file to the case. + * + * @param fileName The name of the file. + * @param localPath The local path of the file, relative to the case + * folder and including the file name. + * @param size The size of the file in bytes. + * @param ctime The change time of the file. + * @param crtime The create time of the file + * @param atime The accessed time of the file. + * @param mtime The modified time of the file. + * @param isFile True if a file, false if a directory. + * @param parentFile The parent file from which the file was derived. + * @param rederiveDetails The details needed to re-derive file (will be + * specific to the derivation method), currently + * unused. + * @param toolName The name of the derivation method or tool, + * currently unused. + * @param toolVersion The version of the derivation method or tool, + * currently unused. + * @param otherDetails Other details of the derivation method or tool, + * currently unused. + * + * @return A DerivedFile object representing the derived file. + * + * @throws TskCoreException if there is a problem adding the file to the + * case database. + * + * @Deprecated Use the version with explicit EncodingType instead + */ + @Deprecated + public synchronized DerivedFile addDerivedFile(String fileName, + String localPath, + long size, + long ctime, long crtime, long atime, long mtime, + boolean isFile, + AbstractFile parentFile, + String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException { + return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, parentFile, + rederiveDetails, toolName, toolVersion, otherDetails, TskData.EncodingType.NONE); + } + + /** + * Adds a file or directory of logical/local files data source to the case + * database, recursively adding the contents of directories. + * + * @param trans A case database transaction. + * @param parentDirectory The root virtual direcotry of the data source. + * @param localFile The local/logical file or directory. + * @param addProgressUpdater notifier to receive progress notifications on + * folders added, or null if not used + * + * @returns File object of file added or new virtualdirectory for the + * directory. + * @param progressUpdater Called after each file/directory is added to + * the case database. + * + * @return An AbstractFile representation of the local/logical file. + * + * @throws TskCoreException If there is a problem completing a database + * operation. + * + * @Deprecated Use the version with explicit EncodingType instead + */ + @Deprecated + private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, FileAddProgressUpdater progressUpdater) throws TskCoreException { + return addLocalFile(trans, parentDirectory, localFile, TskData.EncodingType.NONE, progressUpdater); + } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index 7e6b3fbeff..efc5ec6504 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -46,9 +46,10 @@ import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.EncodedFileStream; +import org.sleuthkit.datamodel.EncodedFileOutputStream; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; class ImageExtractor { @@ -186,7 +187,7 @@ class ImageExtractor { try { listOfExtractedImageAbstractFiles.add(fileManager.addDerivedFile(extractedImage.getFileName(), extractedImage.getLocalPath(), extractedImage.getSize(), extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(), - true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null)); + true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1)); } catch (TskCoreException ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS } @@ -592,7 +593,7 @@ class ImageExtractor { * specified location. */ private void writeExtractedImage(String outputPath, byte[] data) { - try (EncodedFileStream fos = new EncodedFileStream(new FileOutputStream(outputPath))) { + try (EncodedFileOutputStream fos = new EncodedFileOutputStream(new FileOutputStream(outputPath), TskData.EncodingType.XOR1)) { fos.write(data); } catch (IOException ex) { logger.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 1bc95f2e84..f22ffff16b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.modules.embeddedfileextractor; -import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -59,7 +58,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DerivedFile; -import org.sleuthkit.datamodel.EncodedFileStream; +import org.sleuthkit.datamodel.EncodedFileOutputStream; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -624,7 +623,7 @@ class SevenZipExtractor { UnpackStream(String localAbsPath) { this.localAbsPath = localAbsPath; try { - output = new EncodedFileStream(new FileOutputStream(localAbsPath)); + output = new EncodedFileOutputStream(new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1); } catch (IOException ex) { logger.log(Level.SEVERE, "Error writing extracted file: " + localAbsPath, ex); //NON-NLS } @@ -869,7 +868,8 @@ class SevenZipExtractor { try { DerivedFile df = fileManager.addDerivedFile(fileName, node.getLocalRelPath(), node.getSize(), node.getCtime(), node.getCrtime(), node.getAtime(), node.getMtime(), - node.isIsFile(), node.getParent().getFile(), "", EmbeddedFileExtractorModuleFactory.getModuleName(), "", ""); + node.isIsFile(), node.getParent().getFile(), "", EmbeddedFileExtractorModuleFactory.getModuleName(), + "", "", TskData.EncodingType.XOR1); node.setFile(df); } catch (TskCoreException ex) { From 382b8c91109c8a7bce8de293f0d5c153a3c0d846 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 5 Aug 2016 16:07:05 -0400 Subject: [PATCH 05/19] Added encoding for email attachments --- .../autopsy/casemodule/services/FileManager.java | 2 +- .../embeddedfileextractor/SevenZipExtractor.java | 1 - .../autopsy/thunderbirdparser/EmailMessage.java | 12 ++++++++++++ .../autopsy/thunderbirdparser/MboxParser.java | 9 ++++++--- .../ThunderbirdMboxFileIngestModule.java | 3 ++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index c72b624f64..e10e3d7ad5 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -407,7 +407,7 @@ public class FileManager implements Closeable { VirtualDirectory rootDirectory = dataSource.getRootDirectory(); List filesAdded = new ArrayList<>(); for (java.io.File localFile : localFiles) { - AbstractFile fileAdded = addLocalFile(trans, rootDirectory, localFile, progressUpdater); + AbstractFile fileAdded = addLocalFile(trans, rootDirectory, localFile, TskData.EncodingType.NONE, progressUpdater); if (null != fileAdded) { filesAdded.add(fileAdded); } else { diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index f22ffff16b..e6923d9674 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -148,7 +148,6 @@ class SevenZipExtractor { return true; } } - return false; } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EmailMessage.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EmailMessage.java index 65039be614..a2b83ead3b 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EmailMessage.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EmailMessage.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.thunderbirdparser; import java.util.ArrayList; import java.util.Date; import java.util.List; +import org.sleuthkit.datamodel.TskData; /** * A Record to hold generic information about email messages, regardless of the @@ -191,6 +192,8 @@ class EmailMessage { private long aTime = 0L; private long mTime = 0L; + + private TskData.EncodingType encodingType = TskData.EncodingType.NONE; String getName() { return name; @@ -275,5 +278,14 @@ class EmailMessage { this.mTime = mTime.getTime() / 1000; } } + + void setEncodingType(TskData.EncodingType encodingType){ + this.encodingType = encodingType; + } + + TskData.EncodingType getEncodingType(){ + return encodingType; + } + } } diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MboxParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MboxParser.java index 56aea2f826..351c830280 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MboxParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MboxParser.java @@ -57,6 +57,8 @@ import org.apache.tika.parser.txt.CharsetDetector; import org.apache.tika.parser.txt.CharsetMatch; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.EncodedFileOutputStream; /** * A parser that extracts information about email messages and attachments from @@ -285,11 +287,11 @@ class MboxParser { String uniqueFilename = fileID + "-" + index + "-" + email.getSentDate() + "-" + filename; String outPath = outputDirPath + uniqueFilename; - FileOutputStream fos; + EncodedFileOutputStream fos; BinaryBody bb; try { - fos = new FileOutputStream(outPath); - } catch (FileNotFoundException ex) { + fos = new EncodedFileOutputStream(new FileOutputStream(outPath), TskData.EncodingType.XOR1); + } catch (IOException ex) { addErrorMessage( NbBundle.getMessage(this.getClass(), "MboxParser.handleAttch.errMsg.failedToCreateOnDisk", outPath)); @@ -322,6 +324,7 @@ class MboxParser { attach.setLocalPath(ThunderbirdMboxFileIngestModule.getRelModuleOutputPath() + File.separator + uniqueFilename); attach.setSize(new File(outPath).length()); + attach.setEncodingType(TskData.EncodingType.XOR1); email.addAttachment(attach); } diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java index 8fbcafec8e..2f687ead94 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java @@ -331,11 +331,12 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { long cTime = attach.getcTime(); String relPath = attach.getLocalPath(); long size = attach.getSize(); + TskData.EncodingType encodingType = attach.getEncodingType(); try { DerivedFile df = fileManager.addDerivedFile(filename, relPath, size, cTime, crTime, aTime, mTime, true, abstractFile, "", - EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleVersion(), ""); + EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleVersion(), "", encodingType); files.add(df); } catch (TskCoreException ex) { postErrorMessage( From cde9dc7c2ae1eb323b3f3b9c380b3817db665e01 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 9 Aug 2016 13:19:44 -0400 Subject: [PATCH 06/19] Update addDerivedFile call. --- .../autopsy/externalresults/ExternalResultsImporter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsImporter.java b/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsImporter.java index 24255057d0..9fc6b4927f 100644 --- a/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsImporter.java +++ b/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsImporter.java @@ -44,6 +44,7 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskDataException; /** @@ -101,7 +102,8 @@ public final class ExternalResultsImporter { DerivedFile derivedFile = fileManager.addDerivedFile(localFile.getName(), relativePath, localFile.length(), 0, 0, 0, 0, // Do not currently have file times for derived files from external processes. true, parentFile, - "", "", "", ""); // Not currently providing derivation info for derived files from external processes. + "", "", "", "", // Not currently providing derivation info for derived files from external processes. + TskData.EncodingType.NONE); // Don't allow external encoded files IngestServices.getInstance().fireModuleContentEvent(new ModuleContentEvent(derivedFile)); } else { String errorMessage = NbBundle.getMessage(this.getClass(), From bc73e91fa476a35a4fce5b4fb386959a1961437e Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 23 Aug 2016 09:28:48 -0400 Subject: [PATCH 07/19] Added encoding for attachments in PstParser.java --- .../org/sleuthkit/autopsy/thunderbirdparser/PstParser.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java index 5d91dd1c9b..68859233eb 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java @@ -37,7 +37,9 @@ import org.sleuthkit.autopsy.ingest.IngestMonitor; import org.sleuthkit.autopsy.ingest.IngestServices; import static org.sleuthkit.autopsy.thunderbirdparser.ThunderbirdMboxFileIngestModule.getRelModuleOutputPath; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.EncodedFileOutputStream; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * Parser for extracting emails from pst/ost Mircosoft Outlook data files. @@ -260,7 +262,8 @@ class PstParser { * @throws PSTException */ private void saveAttachmentToDisk(PSTAttachment attach, String outPath) throws IOException, PSTException { - try (InputStream attachmentStream = attach.getFileInputStream(); FileOutputStream out = new FileOutputStream(outPath)) { + try (InputStream attachmentStream = attach.getFileInputStream(); + EncodedFileOutputStream out = new EncodedFileOutputStream(new FileOutputStream(outPath), TskData.EncodingType.XOR1)) { // 8176 is the block size used internally and should give the best performance int bufferSize = 8176; byte[] buffer = new byte[bufferSize]; From fc811d9cf8ab948380a9626c8484dce2e3e44982 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 23 Aug 2016 12:55:27 -0400 Subject: [PATCH 08/19] Fixed encoding type for PstParser.java --- .../src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java index 68859233eb..c3b31512be 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java @@ -236,6 +236,7 @@ class PstParser { attachment.setmTime(mTime); attachment.setLocalPath(relPath); attachment.setSize(attach.getFilesize()); + attachment.setEncodingType(TskData.EncodingType.XOR1); email.addAttachment(attachment); } catch (PSTException | IOException | NullPointerException ex) { /** From 56ba457f90715c37eabb69ee5098346a420df502 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 7 Sep 2016 14:06:27 -0400 Subject: [PATCH 09/19] Fix for SingleUserCaseConverter --- .../casemodule/SingleUserCaseConverter.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index f5e29f758d..e39f0d5ebb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -26,6 +26,7 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.text.SimpleDateFormat; @@ -39,6 +40,7 @@ import org.sleuthkit.autopsy.core.UserPreferencesException; import org.sleuthkit.datamodel.CaseDbConnectionInfo; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.autopsy.coreutils.NetworkUtils; +import org.sleuthkit.datamodel.TskData; /** * Import a case from single-user to multi-user. @@ -489,10 +491,18 @@ public class SingleUserCaseConverter { if (value > biggestPK) { biggestPK = value; } + + // If the entry contains an encoding type, copy it. Otherwise use NONE. + // The test on column count can be removed if we upgrade the database before conversion. + int encoding = TskData.EncodingType.NONE.getType(); + ResultSetMetaData rsMetaData = inputResultSet.getMetaData(); + if(rsMetaData.getColumnCount() == 3){ + encoding = inputResultSet.getInt(3); + } outputStatement.executeUpdate("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (" //NON-NLS + value + ", '" - + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(2)) + ", " - + inputResultSet.getInt(3)+ "')"); //NON-NLS + + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(2)) + "', " + + encoding + ")"); //NON-NLS } catch (SQLException ex) { if (ex.getErrorCode() != 0) { // 0 if the entry already exists throw new SQLException(ex); From 7993d6dadd27b5e09bcaa1250f7f9d991748e2d4 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Thu, 8 Sep 2016 14:07:37 -0400 Subject: [PATCH 10/19] Modified toolbar/case button actions to use annotations, added image/video button --- .../autopsy/casemodule/AddImageAction.java | 8 ++++ .../autopsy/casemodule/CaseCloseAction.java | 8 ++++ Core/src/org/sleuthkit/autopsy/core/layer.xml | 34 ++++++++------ .../autopsy/report/ReportWizardAction.java | 3 +- .../autopsy/timeline/OpenTimelineAction.java | 2 +- .../autopsy/imagegallery/Bundle.properties | 1 + .../imagegallery/actions/Bundle.properties | 1 + .../imagegallery/actions/OpenAction.java | 44 ++++++++++++------ .../actions/btn_icon_image_gallery_26.png | Bin 0 -> 2169 bytes .../sleuthkit/autopsy/keywordsearch/layer.xml | 4 +- 10 files changed, 72 insertions(+), 33 deletions(-) create mode 100755 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/Bundle.properties create mode 100755 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/btn_icon_image_gallery_26.png diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index ae57423b5b..f6a102338e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -34,6 +34,10 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.DialogDisplayer; import org.openide.WizardDescriptor; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; import org.openide.util.ChangeSupport; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; @@ -53,6 +57,10 @@ import org.sleuthkit.datamodel.Image; */ // TODO: need annotation because there's a "Lookup.getDefault().lookup(AddImageAction.class)" // used in AddImageWizardPanel1 (among other places). It really shouldn't be done like that. +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.casemodule.AddImageAction") +@ActionRegistration(displayName = "#CTL_AddImage", lazy = false) +@ActionReferences(value = { + @ActionReference(path = "Toolbars/Case", position = 100)}) @ServiceProvider(service = AddImageAction.class) public final class AddImageAction extends CallableSystemAction implements Presenter.Toolbar { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java index c9a0504c59..86cc38c251 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java @@ -36,11 +36,19 @@ import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.windows.WindowManager; import java.awt.Cursor; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; /** * The action to close the current Case. This class should be disabled on * creation and it will be enabled on new case creation or case opened. */ +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.casemodule.CaseCloseAction") +@ActionRegistration(displayName = "#CTL_CaseCloseAct", lazy = false) +@ActionReferences(value = { + @ActionReference(path = "Toolbars/Case", position = 104)}) public final class CaseCloseAction extends CallableSystemAction implements Presenter.Toolbar { JButton toolbarButton = new JButton(); diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index cd72a061f9..ee084e73e2 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -212,13 +212,13 @@ - + - + @@ -364,34 +364,40 @@ - - - - - - - - + + + + + + - + diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index e0a5eb6788..574459fe11 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -47,7 +47,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.report.ReportWizardAction") @ActionRegistration(displayName = "#CTL_ReportWizardAction", lazy = false) @ActionReferences(value = { - @ActionReference(path = "Menu/Tools", position = 80)}) + @ActionReference(path = "Menu/Tools", position = 103), + @ActionReference(path = "Toolbars/Case", position = 103)}) public final class ReportWizardAction extends CallableSystemAction implements Presenter.Toolbar, ActionListener { private final JButton toolbarButton = new JButton(); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java index 66e98c3567..04fd16c71d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java @@ -46,7 +46,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline") @ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false) @ActionReferences(value = { - @ActionReference(path = "Menu/Tools", position = 100), + @ActionReference(path = "Menu/Tools", position = 102), @ActionReference(path = "Toolbars/Case", position = 102)}) public final class OpenTimelineAction extends CallableSystemAction implements Presenter.Toolbar { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties index f53aec5a85..1df8a62921 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties @@ -11,3 +11,4 @@ ImageGalleryOptionsPanel.descriptionLabel.text=To minimize its startup tim ImageGalleryOptionsPanel.furtherDescriptionArea.text=If Image Gallery is disabled, only the fact that an update is needed is recorded. If Image Gallery is enabled after ingest, it will do one bulk update based on the results from ingest. If Image Gallery is disabled, you will be prompted to enable it when attempting to open its window. ImageGalleryOptionsPanel.unavailableDuringInjestLabel.text=This setting is unavailable during ingest. ImageGalleryOptionsPanel.groupCategorizationWarningBox.text=Don't show a warning when overwriting categories, by acting on an entire group. +CTL_OpenAction=Open Image/Video \ No newline at end of file diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/Bundle.properties b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/Bundle.properties new file mode 100755 index 0000000000..b1b078c67d --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/Bundle.properties @@ -0,0 +1 @@ +CTL_AddImage=View Images/Videos \ No newline at end of file diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java index a8085acbfd..a8f37ddf39 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java @@ -19,14 +19,17 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.awt.Component; +import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JOptionPane; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; +import org.openide.util.actions.Presenter; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.Installer; @@ -35,32 +38,33 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -@ActionID(category = "Tools", - id = "org.sleuthkit.autopsy.imagegallery.OpenAction") -@ActionReference(path = "Menu/Tools" /* , position = 333 */) -@ActionRegistration( // iconBase = "org/sleuthkit/autopsy/imagegallery/images/lightbulb.png", - lazy = false, - displayName = "#CTL_OpenAction") +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.imagegallery.OpenAction") +@ActionReferences(value = { + @ActionReference(path = "Menu/Tools", position = 101), + @ActionReference(path = "Toolbars/Case", position = 101) +}) +@ActionRegistration(displayName = "#CTL_OpenAction", lazy = false) @Messages({"CTL_OpenAction=View Images/Videos", "OpenAction.stale.confDlg.msg=The image / video database may be out of date. " + "Do you want to update and listen for further ingest results?\n" + "Choosing 'yes' will update the database and enable listening to future ingests.", "OpenAction.stale.confDlg.title=Image Gallery"}) -public final class OpenAction extends CallableSystemAction { +public final class OpenAction extends CallableSystemAction implements Presenter.Toolbar { private static final String VIEW_IMAGES_VIDEOS = Bundle.CTL_OpenAction(); - private static final boolean fxInited = Installer.isJavaFxInited(); - private static final Logger LOGGER = Logger.getLogger(OpenAction.class.getName()); - + private JButton toolbarButton = new JButton(); + public OpenAction() { super(); + toolbarButton.addActionListener(actionEvent -> performAction()); + this.setEnabled(true); } @Override public boolean isEnabled() { - return Case.isCaseOpen() && fxInited && Case.getCurrentCase().hasData(); + return Case.isCaseOpen() && fxInited;// && Case.getCurrentCase().hasData(); } /** Returns the toolbar component of this action @@ -68,13 +72,23 @@ public final class OpenAction extends CallableSystemAction { * @return component the toolbar button */ @Override public Component getToolbarPresenter() { - JButton toolbarButton = new JButton(this); - toolbarButton.setText(VIEW_IMAGES_VIDEOS); - toolbarButton.addActionListener(this); - + ImageIcon icon = new ImageIcon(getClass().getResource("btn_icon_image_gallery_26.png")); //NON-NLS + toolbarButton.setIcon(icon); + toolbarButton.setText(this.getName()); return toolbarButton; } + /** + * Set this action to be enabled/disabled + * + * @param value whether to enable this action or not + */ + @Override + public void setEnabled(boolean value) { + super.setEnabled(value); + toolbarButton.setEnabled(value); + } + @Override @SuppressWarnings("fallthrough") public void performAction() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/btn_icon_image_gallery_26.png b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/btn_icon_image_gallery_26.png new file mode 100755 index 0000000000000000000000000000000000000000..eea6d5083537a19c24f1191a1021791992666e83 GIT binary patch literal 2169 zcmZ{lXEYlO7sq3dM^NKMP_)#j6|158Sh06#k=lfkmxjD+}1^~eOXMde|vCw--A2XOW01$Bn0EkTh0FLQW>@ollt_lFGdIA7CF984{ zR9=(4E`7l2ZD|UnlO9J#%@63{K$*Fq>DxyCB!i(`E`~0$g_&C$vrV&zazNw<@H@kF z<&HVjz|pLeoYk8mHY%9d7P)rI$?5(c^375S)~wd|dzSB)EQF{S8=qORu|BVA_ocKF zRd$t@WRA~Lo+lEJ+7`=NqL4Wh7w1G__T_4yOBA!LH3fCwxG`~K!fnFMZ6sX6rOU^V z%Y8Avj+8R>EOL{yBzCALb#^fQbD`Ju1L|RhtnIN%>)|XmJHGioUd&oLf=hWIp&@QuyI6z0oWQAmZEAU;^J030hX;cz zIUvV<&8*FvH`7}UAUY(E!_*+=uptAjxwH$)Me zlc8Z_ITH=0jSI^g|4C4NuX*$|SNaKySZq_o-fC+=(f2&P@xWBxZrcT4=NA$|z{Al< zH{6|>qXK>t5mSjiXSbl5D9v7CQsp znx>{?uwRjwasOJblEQvH*UjvaM4%;`xL3Vd`IWL^bm17zd$3e2)5TR0rhFv%%C6?n z*c!XZP2l#9nK5W0i|?jBhb7nf4}9A?;L$;@6+Bqa`}{gkDF*w#Z*UIy_!OMsYoW`B zqdc~0?B5$`3X23cH)m}=O{6;1-zyFfX|tOznHpw~vt!`XudJv*t$dSl$1Y@c1mqYK z$YKUPa>%(BnaP;nH_lEv*XCWGC@MYV0KZ962lfO4gA8jBj6E0uc{^y9?0Wb;NJNF} zcr{b_90i!bdxoqgH~cM(>o}9kB&BqRTivbJpRUf>d&)N-&RLa|SjcztaOc?z>@wyd z&8^ep{F|46Kjfo!B2AH4E-BBR4uG6+ZGh@VMYI6_!l z`iQ;>D3-;{_A$1dO>h#mUs`#pqE0q?N+DN6Ah>L`WOY1C5Pk*`JL^+)NP+WE)@5Q`Qi)aG3|!C@mqgUb@{hxQ;8T_$4pm0-rY(4 zVrMEn#*UA50$aaBkIrh*e#8+_`VwMB*sFVa6I9$&`DsMk;N5Y_nOfF*ZB&tr}vCKS$(&Qm0 zz}>l11`)<_NjrlXuW+%7=hb1{_lagWzb+b8$dz;~MQB}|th!=zd`C@#|T(U*#7_Z$Vm&gfc2ui%i+gzG=o+Ak#~3p$2S zP~ZHs1~9++Kq+h~>kZeVes%-lk=Jpu@G$(~Hjj$ait*tkCjUUbi^IjIA3D z(AW6%VuuRy`3aRHkL6?r);C(hg$y@NBB`XCQNuR-mf zdzZ;Ev(Df$Va`$&_&^GOsYJ)Fu6-qq6uy@7$f4Bc5u+qKBSYEu|1Mr%VtmCp96jan z=fuaH&u7cp-q(rLdJ8RtS6Y+^7{+!;l^C(78A6tLsUdoq)I$91Vt?*=%e{@UY61N$ z1b5fN7DojcZ2o~|$v1*gBKK*eR_BwGX0G&N0YdNH0 znJz7!YSQhimd(W)|KZ2RzG;!YMACr~JDAUK91r7eBL;8q8(*LZi!itI;9*O3is~*| zz+GJl$kOaNUmk!X%}m~5VAt=X75nqsNFtHujNG^nLb#aZFI}*E0SlCZE@Iu4OEhS3 zAKV~CxUo$rO6Z({=_h-amdbb&{SC{689RshdW9i$d_oa)0Mt~$T1u*#N@~{}Rkd|A swRAMVN~#( + ======================================================= --> @@ -31,7 +31,7 @@ ====================================================== --> - + From b9c3cd2c7358114d6356895950412e9cbb1eaf3e Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Thu, 8 Sep 2016 14:44:59 -0400 Subject: [PATCH 11/19] Added case listener to OpenAction to allow it to enable and disable itself --- Core/src/org/sleuthkit/autopsy/core/layer.xml | 2 +- .../imagegallery/actions/OpenAction.java | 79 +++++++++++-------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index ee084e73e2..36c3e09c1e 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -397,7 +397,7 @@ --> - + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java index a8f37ddf39..1b182d0900 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java @@ -1,24 +1,26 @@ /* - * Autopsy Forensic Browser - * - * Copyright 2013 Basis Technology Corp. - * Contact: carrier sleuthkit 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. - */ +* Autopsy Forensic Browser +* +* Copyright 2013 Basis Technology Corp. +* Contact: carrier sleuthkit 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.imagegallery.actions; import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JOptionPane; @@ -45,28 +47,35 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; }) @ActionRegistration(displayName = "#CTL_OpenAction", lazy = false) @Messages({"CTL_OpenAction=View Images/Videos", - "OpenAction.stale.confDlg.msg=The image / video database may be out of date. " + - "Do you want to update and listen for further ingest results?\n" + - "Choosing 'yes' will update the database and enable listening to future ingests.", - "OpenAction.stale.confDlg.title=Image Gallery"}) + "OpenAction.stale.confDlg.msg=The image / video database may be out of date. " + + "Do you want to update and listen for further ingest results?\n" + + "Choosing 'yes' will update the database and enable listening to future ingests.", + "OpenAction.stale.confDlg.title=Image Gallery"}) public final class OpenAction extends CallableSystemAction implements Presenter.Toolbar { - + private static final String VIEW_IMAGES_VIDEOS = Bundle.CTL_OpenAction(); private static final boolean fxInited = Installer.isJavaFxInited(); private static final Logger LOGGER = Logger.getLogger(OpenAction.class.getName()); private JButton toolbarButton = new JButton(); + private final PropertyChangeListener pcl; public OpenAction() { super(); toolbarButton.addActionListener(actionEvent -> performAction()); - this.setEnabled(true); + pcl = (PropertyChangeEvent evt) -> { + if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) { + setEnabled(Case.isCaseOpen()); + } + }; + Case.addPropertyChangeListener(pcl); + this.setEnabled(false); } - + @Override public boolean isEnabled() { - return Case.isCaseOpen() && fxInited;// && Case.getCurrentCase().hasData(); + return Case.isCaseOpen() && fxInited && Case.getCurrentCase().hasData(); } - + /** Returns the toolbar component of this action * * @return component the toolbar button */ @@ -77,7 +86,7 @@ public final class OpenAction extends CallableSystemAction implements Presenter. toolbarButton.setText(this.getName()); return toolbarButton; } - + /** * Set this action to be enabled/disabled * @@ -88,26 +97,26 @@ public final class OpenAction extends CallableSystemAction implements Presenter. super.setEnabled(value); toolbarButton.setEnabled(value); } - + @Override @SuppressWarnings("fallthrough") public void performAction() { - + //check case if (!Case.isCaseOpen()) { return; } final Case currentCase = Case.getCurrentCase(); - + if (ImageGalleryModule.isDrawableDBStale(currentCase)) { //drawable db is stale, ask what to do int answer = JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), Bundle.OpenAction_stale_confDlg_msg(), Bundle.OpenAction_stale_confDlg_title(), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); - + switch (answer) { case JOptionPane.YES_OPTION: ImageGalleryController.getDefault().setListeningEnabled(true); - //fall through + //fall through case JOptionPane.NO_OPTION: ImageGalleryTopComponent.openTopComponent(); break; @@ -119,17 +128,17 @@ public final class OpenAction extends CallableSystemAction implements Presenter. ImageGalleryTopComponent.openTopComponent(); } } - + @Override public String getName() { return VIEW_IMAGES_VIDEOS; } - + @Override public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } - + @Override public boolean asynchronous() { return false; // run on edt From 45e8db8b87f1a8d03490e4d849a544919b4519a2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 8 Sep 2016 15:12:46 -0400 Subject: [PATCH 12/19] 1970: move hashdb for tagged files from viking to autopsy --- .../taggedhashes/AddTaggedHashesToHashDb.java | 132 +++++++ .../AddTaggedHashesToHashDbConfigPanel.form | 148 ++++++++ .../AddTaggedHashesToHashDbConfigPanel.java | 326 ++++++++++++++++++ .../report/taggedhashes/Bundle.properties | 7 + 4 files changed, 613 insertions(+) create mode 100755 Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form create mode 100755 Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/taggedhashes/Bundle.properties diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java new file mode 100755 index 0000000000..3348fdcafd --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java @@ -0,0 +1,132 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit 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.report.taggedhashes; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.report.GeneralReportModule; +import org.sleuthkit.autopsy.report.ReportProgressPanel; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this class plug in to the reporting infrastructure to provide a + * convenient way to add content hashes to hash set databases. + */ +@ServiceProvider(service = GeneralReportModule.class) +public class AddTaggedHashesToHashDb implements GeneralReportModule { + + private AddTaggedHashesToHashDbConfigPanel configPanel; + + public AddTaggedHashesToHashDb() { + } + + @Override + public String getName() { + return "Add Tagged Hashes"; + } + + @Override + public String getDescription() { + return "Adds hashes of tagged files to a hash database."; + } + + @Override + public String getRelativeFilePath() { + return ""; + } + + @Override + public void generateReport(String reportPath, ReportProgressPanel progressPanel) { + progressPanel.setIndeterminate(true); + progressPanel.start(); + progressPanel.updateStatusLabel("Adding hashes..."); + + HashDb hashSet = configPanel.getSelectedHashDatabase(); + if (hashSet != null) { + progressPanel.updateStatusLabel("Adding hashes to " + hashSet.getHashSetName() + " hash set..."); + + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + List tagNames = configPanel.getSelectedTagNames(); + ArrayList failedExports = new ArrayList<>(); + for (TagName tagName : tagNames) { + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + break; + } + + progressPanel.updateStatusLabel("Adding " + tagName.getDisplayName() + " hashes to " + hashSet.getHashSetName() + " hash set..."); + try { + List tags = tagsManager.getContentTagsByTagName(tagName); + for (ContentTag tag : tags) { + // TODO: Currently only AbstractFiles have md5 hashes. Here only files matter. + Content content = tag.getContent(); + if (content instanceof AbstractFile) { + if (null != ((AbstractFile) content).getMd5Hash()) { + try { + hashSet.addHashes(tag.getContent(), Case.getCurrentCase().getName()); + } catch (TskCoreException ex) { + Logger.getLogger(AddTaggedHashesToHashDb.class.getName()).log(Level.SEVERE, "Error adding hash for obj_id = " + tag.getContent().getId() + " to hash database " + hashSet.getHashSetName(), ex); + failedExports.add(tag.getContent().getName()); + } + } else { + JOptionPane.showMessageDialog(null, "Unable to add the " + (tags.size() > 1 ? "files" : "file") + " to the hash database. Hashes have not been calculated. Please configure and run an appropriate ingest module.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + break; + } + } + } + } catch (TskCoreException ex) { + Logger.getLogger(AddTaggedHashesToHashDb.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); + JOptionPane.showMessageDialog(null, "Error getting selected tags for case.", "Hash Export Error", JOptionPane.ERROR_MESSAGE); + } + } + if (!failedExports.isEmpty()) { + StringBuilder errorMessage = new StringBuilder("Failed to export hashes for the following files: "); + for (int i = 0; i < failedExports.size(); ++i) { + errorMessage.append(failedExports.get(i)); + if (failedExports.size() > 1 && i < failedExports.size() - 1) { + errorMessage.append(","); + } + if (i == failedExports.size() - 1) { + errorMessage.append("."); + } + } + JOptionPane.showMessageDialog(null, errorMessage.toString(), "Hash Export Error", JOptionPane.ERROR_MESSAGE); + } + } + progressPanel.setIndeterminate(false); + progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE); + } + + @Override + public JPanel getConfigurationPanel() { + configPanel = new AddTaggedHashesToHashDbConfigPanel(); + return configPanel; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form new file mode 100755 index 0000000000..377dad7826 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form @@ -0,0 +1,148 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java new file mode 100755 index 0000000000..93dad76f89 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -0,0 +1,326 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit 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.report.taggedhashes; + +import java.awt.Component; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.ListCellRenderer; +import javax.swing.ListModel; +import javax.swing.event.ListDataListener; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; +import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this class are used to configure the report module plug in that + * provides a convenient way to add content hashes to hash set databases. + */ +class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + private final static String NO_DATABASES_TEXT = "No updateable hash sets"; + private List tagNames; + private final Map tagNameSelections = new LinkedHashMap<>(); + private final TagNamesListModel tagsNamesListModel = new TagNamesListModel(); + private final TagsNamesListCellRenderer tagsNamesRenderer = new TagsNamesListCellRenderer(); + private final Map hashSets = new HashMap<>(); + private HashDb selectedHashSet = null; + + AddTaggedHashesToHashDbConfigPanel() { + initComponents(); + customizeComponents(); + } + + private void customizeComponents() { + populateTagNameComponents(); + populateHashSetComponents(); + } + + private void populateTagNameComponents() { + // Get the tag names in use for the current case. + try { + tagNames = Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(); + } catch (TskCoreException ex) { + Logger.getLogger(AddTaggedHashesToHashDbConfigPanel.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + JOptionPane.showMessageDialog(null, "Error getting tag names for case.", "Tag Names Not Found", JOptionPane.ERROR_MESSAGE); + } + + // Mark the tag names as unselected. Note that tagNameSelections is a + // LinkedHashMap so that order is preserved and the tagNames and tagNameSelections + // containers are "parallel" containers. + for (TagName tagName : tagNames) { + tagNameSelections.put(tagName.getDisplayName(), Boolean.FALSE); + } + + // Set up the tag names JList component to be a collection of check boxes + // for selecting tag names. The mouse click listener updates tagNameSelections + // to reflect user choices. + tagNamesListBox.setModel(tagsNamesListModel); + tagNamesListBox.setCellRenderer(tagsNamesRenderer); + tagNamesListBox.setVisibleRowCount(-1); + tagNamesListBox.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent evt) { + JList list = (JList) evt.getSource(); + int index = list.locationToIndex(evt.getPoint()); + String value = tagsNamesListModel.getElementAt(index); + tagNameSelections.put(value, !tagNameSelections.get(value)); + list.repaint(); + } + }); + } + + private void populateHashSetComponents() { + // Clear the components because this method is called both during construction + // and when the user changes the hash set configuration. + hashSets.clear(); + hashSetsComboBox.removeAllItems(); + + // Get the updateable hash databases and add their hash set names to the + // JComboBox component. + List updateableHashSets = HashDbManager.getInstance().getUpdateableHashSets(); + if (!updateableHashSets.isEmpty()) { + for (HashDb hashDb : updateableHashSets) { + hashSets.put(hashDb.getHashSetName(), hashDb); + hashSetsComboBox.addItem(hashDb.getHashSetName()); + } + hashSetsComboBox.setEnabled(true); + } else { + hashSetsComboBox.addItem(NO_DATABASES_TEXT); + hashSetsComboBox.setEnabled(false); + } + } + + /** + * Gets the subset of the tag names in use selected by the user. + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + */ + List getSelectedTagNames() { + List selectedTagNames = new ArrayList<>(); + for (TagName tagName : tagNames) { + if (tagNameSelections.get(tagName.getDisplayName())) { + selectedTagNames.add(tagName); + } + } + return selectedTagNames; + } + + /** + * Gets the hash set database selected by the user. + * + * @return A HashDb object representing the database or null. + */ + HashDb getSelectedHashDatabase() { + return selectedHashSet; + } + + // This class is a list model for the tag names JList component. + private class TagNamesListModel implements ListModel { + + @Override + public int getSize() { + return tagNames.size(); + } + + @Override + public String getElementAt(int index) { + return tagNames.get(index).getDisplayName(); + } + + @Override + public void addListDataListener(ListDataListener l) { + } + + @Override + public void removeListDataListener(ListDataListener l) { + } + } + + // This class renders the items in the tag names JList component as JCheckbox components. + private class TagsNamesListCellRenderer extends JCheckBox implements ListCellRenderer { + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent(JList list, String value, int index, boolean isSelected, boolean cellHasFocus) { + if (value != null) { + setEnabled(list.isEnabled()); + setSelected(tagNameSelections.get(value)); + setFont(list.getFont()); + setBackground(list.getBackground()); + setForeground(list.getForeground()); + setText(value); + return this; + } + return new JLabel(); + } + } + + /** + * 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jScrollPane1 = new javax.swing.JScrollPane(); + tagNamesListBox = new javax.swing.JList<>(); + selectAllButton = new javax.swing.JButton(); + deselectAllButton = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + hashSetsComboBox = new javax.swing.JComboBox<>(); + configureHashDatabasesButton = new javax.swing.JButton(); + jLabel2 = new javax.swing.JLabel(); + + jScrollPane1.setViewportView(tagNamesListBox); + + org.openide.awt.Mnemonics.setLocalizedText(selectAllButton, org.openide.util.NbBundle.getMessage(AddTaggedHashesToHashDbConfigPanel.class, "AddTaggedHashesToHashDbConfigPanel.selectAllButton.text")); // NOI18N + selectAllButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectAllButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(deselectAllButton, org.openide.util.NbBundle.getMessage(AddTaggedHashesToHashDbConfigPanel.class, "AddTaggedHashesToHashDbConfigPanel.deselectAllButton.text")); // NOI18N + deselectAllButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deselectAllButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(AddTaggedHashesToHashDbConfigPanel.class, "AddTaggedHashesToHashDbConfigPanel.jLabel1.text")); // NOI18N + + hashSetsComboBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + hashSetsComboBoxActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(configureHashDatabasesButton, org.openide.util.NbBundle.getMessage(AddTaggedHashesToHashDbConfigPanel.class, "AddTaggedHashesToHashDbConfigPanel.configureHashDatabasesButton.text")); // NOI18N + configureHashDatabasesButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + configureHashDatabasesButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(AddTaggedHashesToHashDbConfigPanel.class, "AddTaggedHashesToHashDbConfigPanel.jLabel2.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2) + .addComponent(jLabel1) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addGroup(layout.createSequentialGroup() + .addComponent(hashSetsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 159, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(configureHashDatabasesButton))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(deselectAllButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(selectAllButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(selectAllButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deselectAllButton)) + .addComponent(jScrollPane1)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabel2) + .addGap(4, 4, 4) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(hashSetsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(configureHashDatabasesButton)) + .addContainerGap()) + ); + }// //GEN-END:initComponents + + private void selectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAllButtonActionPerformed + for (TagName tagName : tagNames) { + tagNameSelections.put(tagName.getDisplayName(), Boolean.TRUE); + } + tagNamesListBox.repaint(); + }//GEN-LAST:event_selectAllButtonActionPerformed + + private void hashSetsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashSetsComboBoxActionPerformed + String key = (String)hashSetsComboBox.getSelectedItem(); + selectedHashSet = hashSets.get(key); + }//GEN-LAST:event_hashSetsComboBoxActionPerformed + + private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed + for (TagName tagName : tagNames) { + tagNameSelections.put(tagName.getDisplayName(), Boolean.FALSE); + } + tagNamesListBox.repaint(); + }//GEN-LAST:event_deselectAllButtonActionPerformed + + private void configureHashDatabasesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_configureHashDatabasesButtonActionPerformed + HashLookupSettingsPanel configPanel = new HashLookupSettingsPanel(); + configPanel.load(); + if (JOptionPane.showConfirmDialog(null, configPanel, "Hash Set Configuration", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { + configPanel.store(); + populateHashSetComponents(); + } else { + configPanel.cancel(); + populateHashSetComponents(); + } + }//GEN-LAST:event_configureHashDatabasesButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton configureHashDatabasesButton; + private javax.swing.JButton deselectAllButton; + private javax.swing.JComboBox hashSetsComboBox; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton selectAllButton; + private javax.swing.JList tagNamesListBox; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/Bundle.properties new file mode 100755 index 0000000000..82da454a0c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/Bundle.properties @@ -0,0 +1,7 @@ +HashDbConfigDialog.okButton.text=OK +HashDbConfigDialog.cancelButton.text=Cancel +AddTaggedHashesToHashDbConfigPanel.selectAllButton.text=Select All +AddTaggedHashesToHashDbConfigPanel.jLabel2.text=Export to hash set: +AddTaggedHashesToHashDbConfigPanel.configureHashDatabasesButton.text=Configure Hash Sets... +AddTaggedHashesToHashDbConfigPanel.jLabel1.text=Export hashes of files tagged as: +AddTaggedHashesToHashDbConfigPanel.deselectAllButton.text=Deselect All From 2c81619dfb3c27af574fd863bb6df084ef160faf Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 9 Sep 2016 08:31:08 -0400 Subject: [PATCH 13/19] 1971: move custom aritfacts generator ingest module test fixture to Autopsy --- .../CustomArtifactsCreatorIngestModule.java | 115 ++++++++++++++++++ ...omArtifactsCreatorIngestModuleFactory.java | 64 ++++++++++ 2 files changed, 179 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModule.java create mode 100644 Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModuleFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModule.java b/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModule.java new file mode 100644 index 0000000000..b3dafaa1d6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModule.java @@ -0,0 +1,115 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit 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.report.testfixtures; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import javax.xml.bind.DatatypeConverter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.Blackboard; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter; +import org.sleuthkit.autopsy.ingest.IngestJobContext; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.TskCoreException; +import org.openide.util.NbBundle; + +/** + * A file ingest module that associates custom artifacts and attributes with + * files for test purposes. + */ +@NbBundle.Messages({ + "ErrorCreatingCustomBlackBoardType=Error creating custom blackboard type." +}) +final class CustomArtifactsCreatorIngestModule extends FileIngestModuleAdapter { + + private static final Logger logger = Logger.getLogger(CustomArtifactsCreatorIngestModule.class.getName()); + private static final String moduleName = CustomArtifactsCreatorIngestModuleFactory.getModuleName(); + private static final String ARTIFACT_TYPE_NAME = "AUT_ARTIFACT"; + private static final String ARTIFACT_DISPLAY_NAME = "Autopsy Artifact"; + private static final String INT_ATTR_TYPE_NAME = "AUT_INT_ATTRIBUTE"; + private static final String INT_ATTR_DISPLAY_NAME = "Autopsy Integer"; + private static final String DOUBLE_ATTR_TYPE_NAME = "AUT_DOUBLE_ATTRIBUTE"; + private static final String DOUBLE_ATTR_DISPLAY_NAME = "Autopsy Double"; + private static final String LONG_ATTR_TYPE_NAME = "AUT_LONG_ATTRIBUTE"; + private static final String LONG_ATTR_DISPLAY_NAME = "Autopsy Long"; + private static final String DATETIME_ATTR_TYPE_NAME = "AUT_DATETIME_ATTRIBUTE"; + private static final String DATETIME_ATTR_DISPLAY_NAME = "Autopsy Datetime"; + private static final String BYTES_ATTR_TYPE_NAME = "AUT_BYTES_ATTRIBUTE"; + private static final String BYTES_ATTR_DISPLAY_NAME = "Autopsy Bytes"; + private static final String STRING_ATTR_TYPE_NAME = "AUT_STRING_ATTRIBUTE"; + private static final String STRING_ATTR_DISPLAY_NAME = "Autopsy String"; + private BlackboardArtifact.Type artifactType; + private BlackboardAttribute.Type intAttrType; + private BlackboardAttribute.Type doubleAttrType; + private BlackboardAttribute.Type longAttributeType; + private BlackboardAttribute.Type dateTimeAttrType; + private BlackboardAttribute.Type bytesAttrType; + private BlackboardAttribute.Type stringAttrType; + + @Override + public void startUp(IngestJobContext context) throws IngestModuleException { + Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); + try { + artifactType = blackboard.getOrAddArtifactType(ARTIFACT_TYPE_NAME, ARTIFACT_DISPLAY_NAME); + intAttrType = blackboard.getOrAddAttributeType(INT_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER, INT_ATTR_DISPLAY_NAME); + doubleAttrType = blackboard.getOrAddAttributeType(DOUBLE_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE, DOUBLE_ATTR_DISPLAY_NAME); + longAttributeType = blackboard.getOrAddAttributeType(LONG_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG, LONG_ATTR_DISPLAY_NAME); + dateTimeAttrType = blackboard.getOrAddAttributeType(DATETIME_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME, DATETIME_ATTR_DISPLAY_NAME); + bytesAttrType = blackboard.getOrAddAttributeType(BYTES_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE, BYTES_ATTR_DISPLAY_NAME); + stringAttrType = blackboard.getOrAddAttributeType(STRING_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, STRING_ATTR_DISPLAY_NAME); + } catch (Blackboard.BlackboardException ex) { + throw new IngestModuleException(Bundle.ErrorCreatingCustomBlackBoardType(), ex); + } + } + + @Override + public ProcessResult process(AbstractFile file) { + /* + * Skip directories and virtual files. + */ + if (file.isDir() || file.isVirtual()) { + return ProcessResult.OK; + } + + /* + * Add a custom artifact with one custom attribute of each value type. + */ + try { + BlackboardArtifact artifact = file.newArtifact(artifactType.getTypeID()); + List attributes = new ArrayList<>(); + attributes.add(new BlackboardAttribute(intAttrType, moduleName, 0)); + attributes.add(new BlackboardAttribute(doubleAttrType, moduleName, 0.0)); + attributes.add(new BlackboardAttribute(longAttributeType, moduleName, 0L)); + attributes.add(new BlackboardAttribute(dateTimeAttrType, moduleName, 60L)); + attributes.add(new BlackboardAttribute(bytesAttrType, moduleName, DatatypeConverter.parseHexBinary("ABCD"))); + attributes.add(new BlackboardAttribute(stringAttrType, moduleName, "Zero")); + artifact.addAttributes(attributes); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed to process file (obj_id = %d)", file.getId()), ex); + return ProcessResult.ERROR; + } + + return ProcessResult.OK; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModuleFactory.java new file mode 100644 index 0000000000..766a3260dd --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModuleFactory.java @@ -0,0 +1,64 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit 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.report.testfixtures; + +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.ingest.FileIngestModule; +import org.sleuthkit.autopsy.ingest.IngestModuleFactory; +import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; + +/** + * A factory for file ingest modules that associates custom artifacts and + * attributes with files for test purposes. Uncomment the service provider + * annotation to activate this test fixture. + */ +//@ServiceProvider(service = IngestModuleFactory.class) +public final class CustomArtifactsCreatorIngestModuleFactory extends IngestModuleFactoryAdapter { + + @Override + public String getModuleDisplayName() { + return getModuleName(); + } + + @Override + public String getModuleDescription() { + return "Associates custom artifacts and attributes with files for test purposes."; + } + + @Override + public String getModuleVersionNumber() { + return Version.getVersion(); + } + + @Override + public boolean isFileIngestModuleFactory() { + return true; + } + + @Override + public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { + return new CustomArtifactsCreatorIngestModule(); + } + + static String getModuleName() { + return "Custom Artifacts Creator"; + } +} From daeb19754d34413fa320990b091b5c0dd15f2966 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 14 Sep 2016 10:13:45 -0400 Subject: [PATCH 14/19] Improved error reporting in beginIngestJob --- Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 4ddd67ac6f..d2bc1a9820 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -486,6 +486,8 @@ public class IngestManager { /** * Starts an ingest job that will process a collection of data sources. + * This is intended to be used in an auto-ingest context and will fail + * if no ingest modules are enabled. * * @param dataSources The data sources to process. * @param settings The settings for the ingest job. @@ -499,8 +501,9 @@ public class IngestManager { if (job.hasIngestPipeline()) { return this.startIngestJob(job); // Start job } + return new IngestJobStartResult(null, new IngestManagerException("No ingest pipeline created, likely due to no ingest modules being enabled."), null); } - return new IngestJobStartResult(null, new IngestManagerException("Job creation is not enabled."), null); + return new IngestJobStartResult(null, new IngestManagerException("No case open"), null); } /** From e36019654fda2d73f852b6112ecee3177f351fdd Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 14 Sep 2016 13:43:11 -0400 Subject: [PATCH 15/19] Added tool name user preferences field --- .../autopsy/core/UserPreferences.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 0cfaddf97b..195b0f5e6f 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -65,6 +65,7 @@ public final class UserPreferences { private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60; private static final String DEFAULT_PORT_STRING = "61616"; private static final int DEFAULT_PORT_INT = 61616; + private static final String TOOL_NAME = "ToolName"; // Prevent instantiation. private UserPreferences() { @@ -284,6 +285,23 @@ public final class UserPreferences { preferences.putBoolean(PROCESS_TIME_OUT_ENABLED, enabled); } + /** + * Get the display name for this program + * @return Name for the tool + */ + public static String getToolName(){ + return preferences.get(TOOL_NAME, "Autopsy"); + } + + /** + * Set the display name for this program + * + * @param name Display name + */ + public static void setToolName(String name){ + preferences.put(TOOL_NAME, name); + } + /** * Provides ability to convert text to hex text. From 5f34221183a081caf6610ec923491da92a55b908 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 14 Sep 2016 17:31:34 -0400 Subject: [PATCH 16/19] Resurrected functionality that used to let users create an interesting file hit when custom file types were found. --- .../modules/filetypeid/AddFileTypePanel.form | 82 +++++++++++++++---- .../modules/filetypeid/AddFileTypePanel.java | 82 +++++++++++++++---- .../modules/filetypeid/Bundle.properties | 5 +- .../autopsy/modules/filetypeid/FileType.java | 38 +++++++++ .../modules/filetypeid/FileTypeDetector.java | 32 ++++++++ 5 files changed, 207 insertions(+), 32 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypePanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypePanel.form index d4dc408210..f8e456c728 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypePanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypePanel.form @@ -19,28 +19,39 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -65,6 +76,13 @@ + + + + + + + @@ -159,5 +177,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypePanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypePanel.java index cedd760146..15c6dfcaeb 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypePanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypePanel.java @@ -85,7 +85,9 @@ class AddFileTypePanel extends javax.swing.JPanel { * type is given. */ @Messages({"AddMimeTypePanel.emptySigList.message=Must have at least one signature.", - "AddMimeTypePanel.emptySigList.title=Invalid Signature List"}) + "AddMimeTypePanel.emptySigList.title=Invalid Signature List", + "AddMimeTypePanel.emptySetName.message=Interesting files set name is required if alert is requested.", + "AddMimeTypePanel.emptySetName.title=Missing Interesting Files Set Name"}) FileType getFileType() { String typeName = mimeTypeTextField.getText(); if (typeName.isEmpty()) { @@ -108,8 +110,20 @@ class AddFileTypePanel extends javax.swing.JPanel { for (int i = 0; i < this.signaturesListModel.getSize(); i++) { sigList.add(this.signaturesListModel.elementAt(i)); } - return new FileType(typeName, sigList); + String setName = ""; + if (this.postHitCheckBox.isSelected()) { + if (this.setNameTextField.getText().isEmpty()) { + JOptionPane.showMessageDialog(null, + Bundle.AddMimeTypePanel_emptySetName_message(), + Bundle.AddMimeTypePanel_emptySetName_title(), + JOptionPane.ERROR_MESSAGE); + + return null; + } + setName = this.setNameTextField.getText(); + } + return new FileType(typeName, sigList, this.postHitCheckBox.isSelected(), setName); } /** @@ -163,6 +177,9 @@ class AddFileTypePanel extends javax.swing.JPanel { mimeTypeTextField = new javax.swing.JTextField(); addSigButton = new javax.swing.JButton(); jLabel1 = new javax.swing.JLabel(); + postHitCheckBox = new javax.swing.JCheckBox(); + setNameLabel = new javax.swing.JLabel(); + setNameTextField = new javax.swing.JTextField(); editSigButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(editSigButton, org.openide.util.NbBundle.getMessage(AddFileTypePanel.class, "AddFileTypePanel.editSigButton.text")); // NOI18N @@ -203,6 +220,19 @@ class AddFileTypePanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(AddFileTypePanel.class, "AddFileTypePanel.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(postHitCheckBox, org.openide.util.NbBundle.getMessage(AddFileTypePanel.class, "AddFileTypePanel.postHitCheckBox.text")); // NOI18N + postHitCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + postHitCheckBoxActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(setNameLabel, org.openide.util.NbBundle.getMessage(AddFileTypePanel.class, "AddFileTypePanel.setNameLabel.text")); // NOI18N + setNameLabel.setEnabled(postHitCheckBox.isSelected()); + + setNameTextField.setText(org.openide.util.NbBundle.getMessage(AddFileTypePanel.class, "AddFileTypePanel.setNameTextField.text")); // NOI18N + setNameTextField.setEnabled(postHitCheckBox.isSelected()); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -211,22 +241,30 @@ class AddFileTypePanel extends javax.swing.JPanel { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(jLabel1) - .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(mimeTypeLabel) + .addGap(18, 18, 18) + .addComponent(mimeTypeTextField)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(addSigButton) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(addSigButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(editSigButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(deleteSigButton)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 393, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addGap(28, 28, 28) + .addComponent(setNameLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(editSigButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(deleteSigButton)) - .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 393, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(setNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 144, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addGroup(layout.createSequentialGroup() - .addComponent(mimeTypeLabel) - .addGap(18, 18, 18) - .addComponent(mimeTypeTextField))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addComponent(postHitCheckBox)) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( @@ -245,7 +283,13 @@ class AddFileTypePanel extends javax.swing.JPanel { .addComponent(addSigButton) .addComponent(editSigButton) .addComponent(deleteSigButton)) - .addContainerGap()) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(postHitCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(setNameLabel) + .addComponent(setNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -280,6 +324,13 @@ class AddFileTypePanel extends javax.swing.JPanel { } }//GEN-LAST:event_addSigButtonActionPerformed + private void postHitCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_postHitCheckBoxActionPerformed + if (evt.getSource().equals(postHitCheckBox)) { + this.setNameLabel.setEnabled(postHitCheckBox.isSelected()); + this.setNameTextField.setEnabled(postHitCheckBox.isSelected()); + } + }//GEN-LAST:event_postHitCheckBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addSigButton; @@ -289,6 +340,9 @@ class AddFileTypePanel extends javax.swing.JPanel { private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel mimeTypeLabel; private javax.swing.JTextField mimeTypeTextField; + private javax.swing.JCheckBox postHitCheckBox; + private javax.swing.JLabel setNameLabel; + private javax.swing.JTextField setNameTextField; private javax.swing.JList signatureList; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 2e4e6187f6..4dfed1d15b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -24,7 +24,7 @@ FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message=Offset must be a FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title=Invalid Offset FileTypeIdGlobalSettingsPanel.JOptionPane.invalidRawSignatureBytes.message=The signature has one or more invalid hexadecimal digits. FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title=Invalid Signature -FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.message=Interesting files set name is required if alert is requests. +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.message= FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.title=Missing Interesting Files Set Name FileTypeIdGlobalSettingsPanel.JOptionPane.storeFailed.title=Save Failed FileTypeIdGlobalSettingsPanel.JOptionPane.loadFailed.title=Load Failed @@ -50,3 +50,6 @@ AddFileTypePanel.deleteSigButton.text=Delete Signature AddFileTypePanel.jLabel1.text=Signatures AddFileTypePanel.editSigButton.text=Edit Signature AddFileTypePanel.addSigButton.text=Add Signature +AddFileTypePanel.postHitCheckBox.text=Alert as an "Interesting File" when found +AddFileTypePanel.setNameLabel.text=Set Name +AddFileTypePanel.setNameTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index c8765461a4..e0645bff40 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -43,6 +43,8 @@ class FileType implements Serializable { private static final long serialVersionUID = 1L; private final String mimeType; private final List signatures; + private final boolean createInterestingFileHit; + private final String interestingFilesSetName; /** * Creates a representation of a file type characterized by file signatures. @@ -53,11 +55,27 @@ class FileType implements Serializable { * @throws IllegalArgumentException If an empty list of signatures is given. */ FileType(String mimeType, List signatures) throws IllegalArgumentException { + this(mimeType, signatures, false, ""); + } + + /** + * Creates a representation of a file type characterized by file signatures. + * + * @param mimeType The mime type to associate with this file type. + * @param signatures The signatures that characterize this file type. + * @param createInterestingFileHit Create interesting file hit for file type? + * @param setName Name of the interesting file set in which to create hit. + * + * @throws IllegalArgumentException If an empty list of signatures is given. + */ + FileType(String mimeType, List signatures, boolean createInterestingFileHit, String setName) throws IllegalArgumentException { if (signatures.isEmpty()) { throw new IllegalArgumentException("Must have at least one signature."); } this.mimeType = mimeType; this.signatures = new ArrayList<>(signatures); + this.createInterestingFileHit = createInterestingFileHit; + this.interestingFilesSetName = setName; } /** @@ -69,6 +87,26 @@ class FileType implements Serializable { return mimeType; } + /** + * Gets the name of the interesting files set associated with this file + * type. + * + * @return The interesting files set name. + */ + String getInterestingFilesSetName() { + return interestingFilesSetName; + } + + /** + * Should an interesting files hit be created for this file type? + * + * @return true if an interesting files hit should be created, otherwise + * false + */ + boolean createInterestingFileHit() { + return createInterestingFileHit; + } + /** * Gets the signatures associated with this file type. * diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index 487335d828..f0b8e068c1 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -21,10 +21,15 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.util.ArrayList; import java.util.List; import java.util.SortedSet; +import java.util.logging.Level; import org.apache.tika.Tika; import org.apache.tika.mime.MediaType; import org.apache.tika.mime.MimeTypes; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.Blackboard; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -38,6 +43,7 @@ import org.sleuthkit.datamodel.TskData; */ public class FileTypeDetector { + private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName()); private static final Tika tika = new Tika(); private static final int BUFFER_SIZE = 64 * 1024; private final byte buffer[] = new byte[BUFFER_SIZE]; @@ -304,6 +310,32 @@ public class FileTypeDetector { private String detectUserDefinedType(AbstractFile file) throws TskCoreException { for (FileType fileType : userDefinedFileTypes) { if (fileType.matches(file)) { + if (fileType.createInterestingFileHit()) { + BlackboardArtifact artifact; + artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getInterestingFilesSetName()); + artifact.addAttribute(setNameAttribute); + + /* + * Use the MIME type as the category attribute, i.e., the + * rule that determined this file belongs to the interesting + * files set. + */ + BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()); + artifact.addAttribute(ruleNameAttribute); + + /* + * Index the artifact for keyword search. + */ + try { + Case.getCurrentCase().getServices().getBlackboard().indexArtifact(artifact); + } catch (Blackboard.BlackboardException ex) { + logger.log(Level.SEVERE, String.format("Unable to index blackboard artifact %d", artifact.getArtifactID()), ex); //NON-NLS + MessageNotifyUtil.Notify.error( + NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), artifact.getDisplayName()); + } + } + return fileType.getMimeType(); } } From 058c229c6795257134a314112c1aec6ef17929f2 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 15 Sep 2016 09:04:06 -0400 Subject: [PATCH 17/19] Changed "ToolName" to "AppName" --- .../org/sleuthkit/autopsy/core/UserPreferences.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 195b0f5e6f..784556e7a4 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -65,7 +65,7 @@ public final class UserPreferences { private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60; private static final String DEFAULT_PORT_STRING = "61616"; private static final int DEFAULT_PORT_INT = 61616; - private static final String TOOL_NAME = "ToolName"; + private static final String APP_NAME = "AppName"; // Prevent instantiation. private UserPreferences() { @@ -287,10 +287,10 @@ public final class UserPreferences { /** * Get the display name for this program - * @return Name for the tool + * @return Name of this program */ - public static String getToolName(){ - return preferences.get(TOOL_NAME, "Autopsy"); + public static String getAppName(){ + return preferences.get(APP_NAME, "Autopsy"); } /** @@ -298,8 +298,8 @@ public final class UserPreferences { * * @param name Display name */ - public static void setToolName(String name){ - preferences.put(TOOL_NAME, name); + public static void setAppName(String name){ + preferences.put(APP_NAME, name); } From 4c36a1d3538d35647311842f48cbda98ee23b7ec Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Thu, 15 Sep 2016 11:29:17 -0400 Subject: [PATCH 18/19] Modified exception throwing and moved logging to upper levels --- .../modules/stix/STIXReportModule.java | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index 3cc97c3e10..697d58c2e7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -171,7 +171,7 @@ public class STIXReportModule implements GeneralReportModule { } try { processFile(file.getAbsolutePath(), progressPanel, output); - } catch (TskCoreException ex) { + } catch (TskCoreException | JAXBException ex) { logger.log(Level.SEVERE, String.format("Unable to process STIX file %s", file), ex); //NON-NLS MessageNotifyUtil.Notify.show("STIXReportModule", //NON-NLS ex.getLocalizedMessage(), @@ -213,10 +213,11 @@ public class STIXReportModule implements GeneralReportModule { * @param stixFile - Name of the file * @param progressPanel - Progress panel (for updating) * + * @throws JAXBException * @throws TskCoreException */ private void processFile(String stixFile, ReportProgressPanel progressPanel, BufferedWriter output) throws - TskCoreException { + JAXBException, TskCoreException { // Load the STIX file STIXPackage stix; @@ -244,23 +245,18 @@ public class STIXReportModule implements GeneralReportModule { * * @return Unmarshalled file contents * - * @throws TskCoreException + * @throws JAXBException */ - private STIXPackage loadSTIXFile(String stixFileName) throws TskCoreException { - try { - // Create STIXPackage object from xml. - File file = new File(stixFileName); - JAXBContext jaxbContext = JAXBContext.newInstance("org.mitre.stix.stix_1:org.mitre.stix.common_1:org.mitre.stix.indicator_2:" //NON-NLS - + "org.mitre.cybox.objects:org.mitre.cybox.cybox_2:org.mitre.cybox.common_2"); //NON-NLS - Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); - STIXPackage stix = (STIXPackage) jaxbUnmarshaller.unmarshal(file); - return stix; - } catch (JAXBException ex) { - logger.log(Level.SEVERE, String.format("Unable to load STIX file %s", stixFileName), ex.getLocalizedMessage()); //NON-NLS - throw new TskCoreException("Error loading STIX file (" + ex.toString() + ")"); //NON-NLS - } + private STIXPackage loadSTIXFile(String stixFileName) throws JAXBException { + // Create STIXPackage object from xml. + File file = new File(stixFileName); + JAXBContext jaxbContext = JAXBContext.newInstance("org.mitre.stix.stix_1:org.mitre.stix.common_1:org.mitre.stix.indicator_2:" //NON-NLS + + "org.mitre.cybox.objects:org.mitre.cybox.cybox_2:org.mitre.cybox.common_2"); //NON-NLS + Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); + STIXPackage stix = (STIXPackage) jaxbUnmarshaller.unmarshal(file); + return stix; } - + /** * Do the initial processing of the list of observables. For each * observable, save it in a map using the ID as key. From 01bb69b065cf002c8d32d3328edf0def55183cb9 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Thu, 15 Sep 2016 11:34:37 -0400 Subject: [PATCH 19/19] Removed invalid characters from tag path name --- .../org/sleuthkit/autopsy/report/ReportHTML.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 54fa7b6b7e..0f8360231b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -1,4 +1,4 @@ - /* +/* * * Autopsy Forensic Browser * @@ -719,8 +719,7 @@ class ReportHTML implements TableReportModule { */ public String saveContent(AbstractFile file, String dirName) { // clean up the dir name passed in - String dirName2 = dirName.replace("/", "_"); - dirName2 = dirName2.replace("\\", "_"); + String dirName2 = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(dirName); // Make a folder for the local file with the same tagName as the tag. StringBuilder localFilePath = new StringBuilder(); // full path @@ -840,13 +839,13 @@ class ReportHTML implements TableReportModule { StringBuilder index = new StringBuilder(); final String reportTitle = reportBranding.getReportTitle(); String iconPath = reportBranding.getAgencyLogoPath(); - if (iconPath == null){ + if (iconPath == null) { // use default Autopsy icon if custom icon is not set iconPath = "favicon.ico"; } index.append("\n").append(reportTitle).append(" ").append( NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.title", currentCase.getName())).append( - "\n"); //NON-NLS + "\n"); //NON-NLS index.append("\n"); //NON-NLS index.append("\n"); //NON-NLS @@ -1045,10 +1044,10 @@ class ReportHTML implements TableReportModule { .append("").append(caseName).append("\n"); //NON-NLS NON-NLS summary.append("").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.caseNum")) //NON-NLS .append("").append(!caseNumber.isEmpty() ? caseNumber : NbBundle //NON-NLS - .getMessage(this.getClass(), "ReportHTML.writeSum.noCaseNum")).append("\n"); //NON-NLS + .getMessage(this.getClass(), "ReportHTML.writeSum.noCaseNum")).append("\n"); //NON-NLS summary.append("").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.examiner")).append("") //NON-NLS .append(!examiner.isEmpty() ? examiner : NbBundle - .getMessage(this.getClass(), "ReportHTML.writeSum.noExaminer")) + .getMessage(this.getClass(), "ReportHTML.writeSum.noExaminer")) .append("\n"); //NON-NLS summary.append("").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.numImages")) //NON-NLS .append("").append(imagecount).append("\n"); //NON-NLS