From 08a44050564b803d4e1bcfc83dfccfec066f01ff Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 13 Feb 2020 12:40:34 -0500 Subject: [PATCH 01/24] 6040 add end point for document summarization --- .../autopsy/summarizer/Summarizer.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/summarizer/Summarizer.java diff --git a/Core/src/org/sleuthkit/autopsy/summarizer/Summarizer.java b/Core/src/org/sleuthkit/autopsy/summarizer/Summarizer.java new file mode 100644 index 0000000000..057593bb68 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/summarizer/Summarizer.java @@ -0,0 +1,48 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019-2020 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.summarizer; + +import java.io.IOException; +import org.sleuthkit.datamodel.AbstractFile; + +/** + * Interface for implementation of summarizers for documents. + */ +public interface Summarizer { + + /** + * Get the name of the summarizer for identification purposes. + * + * @return The name of the summarizer. + */ + String getName(); + + /** + * Summarize the provided abstract file into a summary with a size no + * greater than the size specified. + * + * @param file The AbstractFile to summarize. + * @param summarySize The size of the summary to create. + * + * @return The summary as a string. + * + * @throws IOException + */ + String summarize(AbstractFile file, int summarySize) throws IOException; +} From da53229ba436eb0980831ef417ec63a5ea2c069b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 13 Feb 2020 12:43:22 -0500 Subject: [PATCH 02/24] 6040 use summarizer for file discovery documents view --- Core/nbproject/project.xml | 3 +- .../filequery/Bundle.properties-MERGED | 4 +- .../autopsy/filequery/DiscoveryUiUtils.java | 2 + .../autopsy/filequery/FileSearch.java | 61 ++++++++++++++++++- .../autopsy/filequery/ResultsPanel.java | 55 ++++------------- 5 files changed, 78 insertions(+), 47 deletions(-) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index c3f58c1ec6..4db5375971 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -341,6 +341,7 @@ org.sleuthkit.autopsy.modules.vmextractor org.sleuthkit.autopsy.progress org.sleuthkit.autopsy.report + org.sleuthkit.autopsy.summarizer org.sleuthkit.autopsy.textextractors org.sleuthkit.autopsy.textextractors.configs org.sleuthkit.autopsy.texttranslation @@ -804,7 +805,7 @@ ext/jutf7-1.0.0.jar release/modules/ext/jutf7-1.0.0.jar - + ext/DatCon.jar release/modules/ext/DatCon.jar diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED index d438e929eb..f1945cf245 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED @@ -24,6 +24,8 @@ FileGroup.groupSortingAlgorithm.groupSize.text=Group Size FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1}) # {0} - Data source ID FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0}) +FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview. +FileSearch.documentSummary.noPreview=No preview available. FileSearch.FileTagGroupKey.noSets=None # {0} - file name FileSearch.genVideoThumb.progress.text=extracting temporary file {0} @@ -185,8 +187,6 @@ ResultFile.score.taggedFile.description=At least one instance of the file has be # {1} - totalPages ResultsPanel.currentPage.displayValue=Page: {0} of {1} ResultsPanel.currentPageLabel.text=Page: - -ResultsPanel.documentPreviewWorker.noBytes=No bytes read for document, unable to display preview. -ResultsPanel.documentPreviewWorker.noPreview=No preview available. # {0} - selectedPage # {1} - maxPage ResultsPanel.invalidPageNumber.message=The selected page number {0} does not exist. Please select a value from 1 to {1}. diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java index fc2752a659..e566045d5c 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java @@ -95,6 +95,8 @@ final class DiscoveryUiUtils { return comp instanceof JComponent && point.x >= comp.getX() && point.x <= comp.getX() + ICON_SIZE && point.y >= comp.getY() && point.y <= comp.getY() + ICON_SIZE; } + + /** * Method to set the icon and tool tip text for a label to show deleted * status. diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index 8e55eb50e6..b0809492d4 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,11 +25,13 @@ import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.IOException; +import java.io.Reader; import java.nio.file.Paths; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -46,6 +48,7 @@ import org.apache.commons.io.FilenameUtils; import org.netbeans.api.progress.ProgressHandle; import org.opencv.core.Mat; import org.opencv.highgui.VideoCapture; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -71,6 +74,9 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.summarizer.Summarizer; +import org.sleuthkit.autopsy.textextractors.TextExtractor; +import org.sleuthkit.autopsy.textextractors.TextExtractorFactory; /** * Main class to perform the file search. @@ -84,6 +90,8 @@ class FileSearch { private static final Cache>> searchCache = CacheBuilder.newBuilder() .maximumSize(MAXIMUM_CACHE_SIZE) .build(); + private static final int PREVIEW_SIZE = 256; + private static volatile Summarizer summarizerToUse = null; /** * Run the file search and returns the SearchResults object for debugging. @@ -239,6 +247,56 @@ class FileSearch { return page; } + @NbBundle.Messages({"FileSearch.documentSummary.noPreview=No preview available.", + "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."}) + static String summarize(AbstractFile file) { + Summarizer localSummarizer = summarizerToUse; + if (localSummarizer == null) { + synchronized (searchCache) { + if (localSummarizer == null) { + try { + localSummarizer = getLocalSummarizer(); + } catch (IOException ignored) { + //no summarizers being present is not unexpected + } + } + } + } + if (localSummarizer == null) { + return getFirstLines(file); + } else { + try { + return localSummarizer.summarize(file, 40); + } catch (IOException ex) { + return Bundle.FileSearch_documentSummary_noPreview(); + } + } + + } + + private static String getFirstLines(AbstractFile file) { + try (Reader reader = TextExtractorFactory.getExtractor(file, null).getReader()) { + char[] cbuf = new char[PREVIEW_SIZE]; + reader.read(cbuf, 0, PREVIEW_SIZE); + return Arrays.toString(cbuf); + } catch (IOException ex) { + return Bundle.FileSearch_documentSummary_noBytes(); + } catch (TextExtractorFactory.NoTextExtractorFound | TextExtractor.InitReaderException ex) { + return Bundle.FileSearch_documentSummary_noPreview(); + } + } + + private static Summarizer getLocalSummarizer() throws IOException { + Collection summarizers + = Lookup.getDefault().lookupAll(Summarizer.class + ); + if (!summarizers.isEmpty()) { + summarizerToUse = summarizers.iterator().next(); + return summarizerToUse; + } + throw new IOException("No summarizers found"); + } + /** * Run the file search. Caching new results for access at later time. * @@ -615,6 +673,7 @@ class FileSearch { videoThumbnails.add(ImageUtils.getDefaultThumbnail()); videoThumbnails.add(ImageUtils.getDefaultThumbnail()); return videoThumbnails; + } private FileSearch() { diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java index 6ac9a79489..02a9638993 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,6 +28,8 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; @@ -38,14 +40,12 @@ import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionListener; -import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.StringExtract; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -748,7 +748,6 @@ public class ResultsPanel extends javax.swing.JPanel { private class DocumentPreviewWorker extends SwingWorker { private final DocumentWrapper documentWrapper; - private static final int PREVIEW_SIZE = 256; /** * Construct a new DocumentPreviewWorker. @@ -763,53 +762,23 @@ public class ResultsPanel extends javax.swing.JPanel { @Override protected Void doInBackground() throws Exception { - String preview = createPreview(documentWrapper.getResultFile().getFirstInstance()); + String preview = FileSearch.summarize(documentWrapper.getResultFile().getFirstInstance()); if (preview != null) { documentWrapper.setPreview(preview); } return null; } - /** - * Create the string that will be used as the preview for the specified - * AbstractFile. - * - * @param file The AbstractFile to create the preview for. - * - * @return The String which is the preview for the specified - * AbstractFile. - */ - @Messages({"ResultsPanel.documentPreviewWorker.noPreview=No preview available.", - "ResultsPanel.documentPreviewWorker.noBytes=No bytes read for document, unable to display preview."}) - private String createPreview(AbstractFile file) { - byte[] data = new byte[PREVIEW_SIZE]; - int bytesRead = 0; - if (file.getSize() > 0) { - try { - int length = PREVIEW_SIZE > file.getSize() ? (int) file.getSize() : PREVIEW_SIZE; //if the size is less than the int it can be cast to an int - bytesRead = file.read(data, 0, length); // read the data - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error while trying to show the String content.", ex); //NON-NLS - } - } - String text; - if (bytesRead > 0) { - StringExtract stringExtract = new StringExtract(); - final StringExtract.StringExtractUnicodeTable.SCRIPT selScript = StringExtract.StringExtractUnicodeTable.SCRIPT.LATIN_1; - stringExtract.setEnabledScript(selScript); - StringExtract.StringExtractResult res = stringExtract.extract(data, bytesRead, 0); - text = res.getText(); - if (StringUtils.isBlank(text)) { - text = Bundle.ResultsPanel_documentPreviewWorker_noPreview(); - } - } else { - text = Bundle.ResultsPanel_documentPreviewWorker_noBytes(); - } - return text; - } - @Override protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + documentWrapper.setPreview(ex.getMessage()); + logger.log(Level.WARNING, "Document Worker Exception", ex); + } catch (CancellationException ex){ + //ignore we want this to be cancelled sometimes + } documentPreviewViewer.repaint(); } From 314007f94055bbf87fd72bff9112fc7aff9ee144 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 13 Feb 2020 14:28:27 -0500 Subject: [PATCH 03/24] 6040 adjust comments --- .../autopsy/filequery/DiscoveryUiUtils.java | 2 -- .../autopsy/filequery/FileSearch.java | 26 +++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java index e566045d5c..fc2752a659 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java @@ -95,8 +95,6 @@ final class DiscoveryUiUtils { return comp instanceof JComponent && point.x >= comp.getX() && point.x <= comp.getX() + ICON_SIZE && point.y >= comp.getY() && point.y <= comp.getY() + ICON_SIZE; } - - /** * Method to set the icon and tool tip text for a label to show deleted * status. diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index b0809492d4..a4df5adc70 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -247,6 +247,14 @@ class FileSearch { return page; } + /** + * Get a summary for the specified AbstractFile if no summarizers exist get + * the first bit of the file. + * + * @param file The AbstractFile to summarize. + * + * @return The summary or first bit of the specified file as a String. + */ @NbBundle.Messages({"FileSearch.documentSummary.noPreview=No preview available.", "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."}) static String summarize(AbstractFile file) { @@ -263,9 +271,11 @@ class FileSearch { } } if (localSummarizer == null) { + //no summarizer was found just grab the first bit of the file return getFirstLines(file); } else { try { + //a summary of length 40 seems to fit without vertical scroll bars return localSummarizer.summarize(file, 40); } catch (IOException ex) { return Bundle.FileSearch_documentSummary_noPreview(); @@ -274,6 +284,13 @@ class FileSearch { } + /** + * Get the first bit of text from the specified AbstractFile. + * + * @param file The AbstractFile to get text from. + * + * @return The first bit of text from the specified AbstractFile. + */ private static String getFirstLines(AbstractFile file) { try (Reader reader = TextExtractorFactory.getExtractor(file, null).getReader()) { char[] cbuf = new char[PREVIEW_SIZE]; @@ -286,6 +303,13 @@ class FileSearch { } } + /** + * Get the first summarizer found by a lookup of summarizers. + * + * @return The first summarizer found by a lookup of summarizers. + * + * @throws IOException + */ private static Summarizer getLocalSummarizer() throws IOException { Collection summarizers = Lookup.getDefault().lookupAll(Summarizer.class @@ -655,7 +679,6 @@ class FileSearch { int framePos = Integer.valueOf(FilenameUtils.getBaseName(fileName).substring(2)); framePositions[thumbnailNumber] = framePos; thumbnailNumber++; - } thumbnailWrapper.setThumbnails(videoThumbnails, framePositions); } @@ -673,7 +696,6 @@ class FileSearch { videoThumbnails.add(ImageUtils.getDefaultThumbnail()); videoThumbnails.add(ImageUtils.getDefaultThumbnail()); return videoThumbnails; - } private FileSearch() { From 046e35b0d031a0d78df139c4321e29956044eb16 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 13 Feb 2020 16:42:00 -0500 Subject: [PATCH 04/24] 6040 rename summarizer to textsummarizer --- .../autopsy/filequery/FileSearch.java | 18 +++++++++--------- .../TextSummarizer.java} | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) rename Core/src/org/sleuthkit/autopsy/{summarizer/Summarizer.java => textsummarizer/TextSummarizer.java} (86%) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index a4df5adc70..218046f3f4 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -74,9 +74,9 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.summarizer.Summarizer; import org.sleuthkit.autopsy.textextractors.TextExtractor; import org.sleuthkit.autopsy.textextractors.TextExtractorFactory; +import org.sleuthkit.autopsy.textsummarizer.TextSummarizer; /** * Main class to perform the file search. @@ -91,7 +91,7 @@ class FileSearch { .maximumSize(MAXIMUM_CACHE_SIZE) .build(); private static final int PREVIEW_SIZE = 256; - private static volatile Summarizer summarizerToUse = null; + private static volatile TextSummarizer summarizerToUse = null; /** * Run the file search and returns the SearchResults object for debugging. @@ -248,7 +248,7 @@ class FileSearch { } /** - * Get a summary for the specified AbstractFile if no summarizers exist get + * Get a summary for the specified AbstractFile if no TextSummarizers exist get * the first bit of the file. * * @param file The AbstractFile to summarize. @@ -258,7 +258,7 @@ class FileSearch { @NbBundle.Messages({"FileSearch.documentSummary.noPreview=No preview available.", "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."}) static String summarize(AbstractFile file) { - Summarizer localSummarizer = summarizerToUse; + TextSummarizer localSummarizer = summarizerToUse; if (localSummarizer == null) { synchronized (searchCache) { if (localSummarizer == null) { @@ -304,15 +304,15 @@ class FileSearch { } /** - * Get the first summarizer found by a lookup of summarizers. + * Get the first TextSummarizer found by a lookup of TextSummarizers. * - * @return The first summarizer found by a lookup of summarizers. + * @return The first TextSummarizer found by a lookup of TextSummarizers. * * @throws IOException */ - private static Summarizer getLocalSummarizer() throws IOException { - Collection summarizers - = Lookup.getDefault().lookupAll(Summarizer.class + private static TextSummarizer getLocalSummarizer() throws IOException { + Collection summarizers + = Lookup.getDefault().lookupAll(TextSummarizer.class ); if (!summarizers.isEmpty()) { summarizerToUse = summarizers.iterator().next(); diff --git a/Core/src/org/sleuthkit/autopsy/summarizer/Summarizer.java b/Core/src/org/sleuthkit/autopsy/textsummarizer/TextSummarizer.java similarity index 86% rename from Core/src/org/sleuthkit/autopsy/summarizer/Summarizer.java rename to Core/src/org/sleuthkit/autopsy/textsummarizer/TextSummarizer.java index 057593bb68..2d40d7af5b 100644 --- a/Core/src/org/sleuthkit/autopsy/summarizer/Summarizer.java +++ b/Core/src/org/sleuthkit/autopsy/textsummarizer/TextSummarizer.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.summarizer; +package org.sleuthkit.autopsy.textsummarizer; import java.io.IOException; import org.sleuthkit.datamodel.AbstractFile; @@ -24,12 +24,12 @@ import org.sleuthkit.datamodel.AbstractFile; /** * Interface for implementation of summarizers for documents. */ -public interface Summarizer { +public interface TextSummarizer { /** - * Get the name of the summarizer for identification purposes. + * Get the name of the TextSummarizer for identification purposes. * - * @return The name of the summarizer. + * @return The name of the TextSummarizer. */ String getName(); From 3f25a126f1facae30b5048564287773c22440571 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 13 Feb 2020 16:56:56 -0500 Subject: [PATCH 05/24] 6040 fix exporting of renamed package --- Core/nbproject/project.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index f1462f716c..182b92a661 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -343,9 +343,9 @@ org.sleuthkit.autopsy.modules.vmextractor org.sleuthkit.autopsy.progress org.sleuthkit.autopsy.report - org.sleuthkit.autopsy.summarizer org.sleuthkit.autopsy.textextractors org.sleuthkit.autopsy.textextractors.configs + org.sleuthkit.autopsy.textsummarizer org.sleuthkit.autopsy.texttranslation org.sleuthkit.datamodel org.sleuthkit.datamodel.blackboardutils From c15d73f56125c9301363fe5a79f34aa5defbff65 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 18 Feb 2020 15:48:37 -0500 Subject: [PATCH 06/24] 6040 fix comments to make more clear --- .../org/sleuthkit/autopsy/filequery/FileSearch.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index 218046f3f4..ea25c65ce5 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -248,12 +248,12 @@ class FileSearch { } /** - * Get a summary for the specified AbstractFile if no TextSummarizers exist get - * the first bit of the file. + * Get a summary for the specified AbstractFile. If no TextSummarizers exist get + * the beginning of the file. * * @param file The AbstractFile to summarize. * - * @return The summary or first bit of the specified file as a String. + * @return The summary or beginning of the specified file as a String. */ @NbBundle.Messages({"FileSearch.documentSummary.noPreview=No preview available.", "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."}) @@ -271,7 +271,7 @@ class FileSearch { } } if (localSummarizer == null) { - //no summarizer was found just grab the first bit of the file + //no summarizer was found just grab the beginning of the file return getFirstLines(file); } else { try { @@ -285,11 +285,11 @@ class FileSearch { } /** - * Get the first bit of text from the specified AbstractFile. + * Get the beginning of text from the specified AbstractFile. * * @param file The AbstractFile to get text from. * - * @return The first bit of text from the specified AbstractFile. + * @return The beginning of text from the specified AbstractFile. */ private static String getFirstLines(AbstractFile file) { try (Reader reader = TextExtractorFactory.getExtractor(file, null).getReader()) { From cc164739ed3fac131ab6123667a375a9760c357b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 18 Feb 2020 16:35:23 -0500 Subject: [PATCH 07/24] 6040 fix codacy issue --- .../sleuthkit/autopsy/filequery/Bundle.properties-MERGED | 1 + Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED index f1945cf245..de944bf3cf 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED @@ -187,6 +187,7 @@ ResultFile.score.taggedFile.description=At least one instance of the file has be # {1} - totalPages ResultsPanel.currentPage.displayValue=Page: {0} of {1} ResultsPanel.currentPageLabel.text=Page: - +ResultsPanel.documentPreview.text=Document preview creation cancelled. # {0} - selectedPage # {1} - maxPage ResultsPanel.invalidPageNumber.message=The selected page number {0} does not exist. Please select a value from 1 to {1}. diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java index 02a9638993..34cf61e31e 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java @@ -769,6 +769,7 @@ public class ResultsPanel extends javax.swing.JPanel { return null; } + @Messages({"ResultsPanel.documentPreview.text=Document preview creation cancelled."}) @Override protected void done() { try { @@ -776,8 +777,9 @@ public class ResultsPanel extends javax.swing.JPanel { } catch (InterruptedException | ExecutionException ex) { documentWrapper.setPreview(ex.getMessage()); logger.log(Level.WARNING, "Document Worker Exception", ex); - } catch (CancellationException ex){ - //ignore we want this to be cancelled sometimes + } catch (CancellationException ignored) { + documentWrapper.setPreview(Bundle.ResultsPanel_documentPreview_text()); + //we want to do nothing in response to this since we allow it to be cancelled } documentPreviewViewer.repaint(); } From 9093fc4137cb0135375d685c6ce85a23352fb802 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 19 Feb 2020 13:26:21 -0500 Subject: [PATCH 08/24] 6040 fix char[] to String conversion --- Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index ea25c65ce5..c9b4bb7dac 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -295,7 +295,7 @@ class FileSearch { try (Reader reader = TextExtractorFactory.getExtractor(file, null).getReader()) { char[] cbuf = new char[PREVIEW_SIZE]; reader.read(cbuf, 0, PREVIEW_SIZE); - return Arrays.toString(cbuf); + return new String(cbuf); } catch (IOException ex) { return Bundle.FileSearch_documentSummary_noBytes(); } catch (TextExtractorFactory.NoTextExtractorFound | TextExtractor.InitReaderException ex) { From 425c59e63abaed6ebc11ff339bb8001c1ac5d875 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Feb 2020 10:50:49 -0500 Subject: [PATCH 09/24] 6040 inline size and count for doc summary --- .../autopsy/filequery/DocumentPanel.form | 33 ++++++++++++------- .../autopsy/filequery/DocumentPanel.java | 29 +++++++++------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form index 8608d528b3..8f3956d133 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form @@ -27,14 +27,15 @@ - - + + + + - - + @@ -48,15 +49,23 @@ - - - - - - - + + + + + + + + + + + + + + + + - diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java index 8fea944747..2db97be675 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java @@ -104,13 +104,14 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(countLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 530, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 81, Short.MAX_VALUE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 374, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(countLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 139, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(previewScrollPane) + .addComponent(previewScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 649, Short.MAX_VALUE) .addComponent(documentType, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); @@ -121,14 +122,18 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere .addComponent(documentType, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(previewScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(countLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(countLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()))) ); }// //GEN-END:initComponents From 13398f833a96dc6a2a7263c047684de148da1693 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Feb 2020 18:52:29 -0500 Subject: [PATCH 10/24] 6040 add name label to panels to include name of first instance --- .../autopsy/filequery/Bundle.properties | 2 - .../autopsy/filequery/DocumentPanel.form | 53 ++++------------- .../autopsy/filequery/DocumentPanel.java | 52 ++++++---------- .../autopsy/filequery/FileSearch.java | 19 +++--- .../filequery/ImageThumbnailPanel.form | 27 +++++---- .../filequery/ImageThumbnailPanel.java | 59 +++++++++++-------- .../autopsy/filequery/ResultsPanel.java | 6 +- .../filequery/VideoThumbnailPanel.form | 32 +++++----- .../filequery/VideoThumbnailPanel.java | 52 ++++++++-------- 9 files changed, 136 insertions(+), 166 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties index 6a4b6e4047..108b3608fa 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties @@ -65,8 +65,6 @@ FileSearchPanel.stepTwoLabel.text=Step 2: Filter which images to show FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings DiscoveryTopComponent.stepOneLabel.text=Step 1: Pick File Type DiscoveryTopComponent.documentsButton.text=Documents -DocumentPanel.countLabel.toolTipText= DocumentPanel.fileSizeLabel.toolTipText= -DocumentPanel.documentType.text= DocumentPanel.isDeletedLabel.toolTipText= ImageThumbnailPanel.isDeletedLabel.toolTipText= diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form index 8f3956d133..05ed6fc0c8 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form @@ -27,16 +27,14 @@ - - - + - + @@ -46,47 +44,21 @@ - + - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - @@ -130,12 +102,7 @@ - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java index 2db97be675..30e4b928db 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java @@ -23,6 +23,7 @@ import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.MouseEvent; +import java.nio.file.Paths; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListCellRenderer; @@ -52,21 +53,15 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere // //GEN-BEGIN:initComponents private void initComponents() { - countLabel = new javax.swing.JLabel(); isDeletedLabel = new javax.swing.JLabel(); scoreLabel = new javax.swing.JLabel(); fileSizeLabel = new javax.swing.JLabel(); - documentType = new javax.swing.JLabel(); + nameLabel = new javax.swing.JLabel(); javax.swing.JScrollPane previewScrollPane = new javax.swing.JScrollPane(); previewTextArea = new javax.swing.JTextArea(); setBorder(javax.swing.BorderFactory.createEtchedBorder()); - countLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.countLabel.toolTipText")); // NOI18N - countLabel.setMaximumSize(new java.awt.Dimension(159, 12)); - countLabel.setMinimumSize(new java.awt.Dimension(159, 12)); - countLabel.setPreferredSize(new java.awt.Dimension(159, 12)); - isDeletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N isDeletedLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.isDeletedLabel.toolTipText")); // NOI18N isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); @@ -81,8 +76,6 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere fileSizeLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.fileSizeLabel.toolTipText")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(documentType, org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.documentType.text")); // NOI18N - previewScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); previewTextArea.setEditable(false); @@ -104,62 +97,55 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 374, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(countLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 139, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(previewScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 649, Short.MAX_VALUE) - .addComponent(documentType, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(nameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() - .addComponent(documentType, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(previewScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(countLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel countLabel; - private javax.swing.JLabel documentType; private javax.swing.JLabel fileSizeLabel; private javax.swing.JLabel isDeletedLabel; + private javax.swing.JLabel nameLabel; private javax.swing.JTextArea previewTextArea; private javax.swing.JLabel scoreLabel; // End of variables declaration//GEN-END:variables - @Messages({"# {0} - extension", - "DocumentPanel.documentType.extension.text=Extension: {0}"}) + @Messages({"# {0} - otherInstanceCount", + "DocumentPanel.nameLabel.more.text= and {0} more"}) @Override public Component getListCellRendererComponent(JList list, DocumentWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(DiscoveryUiUtils.getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - countLabel.setText(Bundle.ImageThumbnailPanel_countLabel_text(value.getResultFile().getAllInstances().size())); - documentType.setText(Bundle.DocumentPanel_documentType_extension_text(value.getResultFile().getFirstInstance().getNameExtension())); //WJS-TODO fill this in with a document type instead of just DOCUMENT + String nameText = Paths.get(value.getResultFile().getFirstInstance().getParentPath(), value.getResultFile().getFirstInstance().getName()).toString(); + if (value.getResultFile().getAllInstances().size() > 1) { + nameText += Bundle.DocumentPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); + } + nameLabel.setText(nameText); previewTextArea.setText(value.getPreview()); previewTextArea.setCaretPosition(0); DiscoveryUiUtils.setDeletedIcon(value.getResultFile().isDeleted(), isDeletedLabel); DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); - return this; } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index c9b4bb7dac..1f6e65bba9 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -45,6 +45,7 @@ import java.util.logging.Level; import javax.imageio.ImageIO; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.StringUtils; import org.netbeans.api.progress.ProgressHandle; import org.opencv.core.Mat; import org.opencv.highgui.VideoCapture; @@ -248,8 +249,8 @@ class FileSearch { } /** - * Get a summary for the specified AbstractFile. If no TextSummarizers exist get - * the beginning of the file. + * Get a summary for the specified AbstractFile. If no TextSummarizers exist + * get the beginning of the file. * * @param file The AbstractFile to summarize. * @@ -258,6 +259,7 @@ class FileSearch { @NbBundle.Messages({"FileSearch.documentSummary.noPreview=No preview available.", "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."}) static String summarize(AbstractFile file) { + String summary = null; TextSummarizer localSummarizer = summarizerToUse; if (localSummarizer == null) { synchronized (searchCache) { @@ -270,18 +272,19 @@ class FileSearch { } } } - if (localSummarizer == null) { - //no summarizer was found just grab the beginning of the file - return getFirstLines(file); - } else { + if (localSummarizer != null) { try { //a summary of length 40 seems to fit without vertical scroll bars - return localSummarizer.summarize(file, 40); + summary = localSummarizer.summarize(file, 40); } catch (IOException ex) { return Bundle.FileSearch_documentSummary_noPreview(); } } - + if (StringUtils.isBlank(summary)) { + //no summarizer was found or summary was empty just grab the beginning of the file + summary = getFirstLines(file); + } + return summary; } /** diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form index ff120eecdd..e8b19379c1 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form @@ -20,36 +20,36 @@ - + - - - - - + + + + + - + + + - - - + @@ -82,8 +82,11 @@ - + + + + @@ -133,4 +136,4 @@ - \ No newline at end of file + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java index f0c0022905..0a50a2d41c 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java @@ -23,6 +23,7 @@ import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.MouseEvent; +import java.nio.file.Paths; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JList; @@ -36,6 +37,7 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR private static final long serialVersionUID = 1L; private static final Color SELECTION_COLOR = new Color(0, 120, 215); + private static final int MAX_NAME_STRING = 30; /** * Creates new form ImageThumbnailPanel @@ -56,7 +58,7 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR javax.swing.JPanel thumbnailPanel = new javax.swing.JPanel(); thumbnailLabel = new javax.swing.JLabel(); fileSizeLabel = new javax.swing.JLabel(); - countLabel = new javax.swing.JLabel(); + nameLabel = new javax.swing.JLabel(); isDeletedLabel = new javax.swing.JLabel(); scoreLabel = new javax.swing.JLabel(); @@ -68,22 +70,23 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR fileSizeLabel.setToolTipText(""); - countLabel.setToolTipText(""); - countLabel.setMaximumSize(new java.awt.Dimension(159, 12)); - countLabel.setMinimumSize(new java.awt.Dimension(159, 12)); - countLabel.setPreferredSize(new java.awt.Dimension(159, 12)); + org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ImageThumbnailPanel.class, "ImageThumbnailPanel.nameLabel.text")); // NOI18N + nameLabel.setToolTipText(""); + nameLabel.setMaximumSize(new java.awt.Dimension(159, 12)); + nameLabel.setMinimumSize(new java.awt.Dimension(159, 12)); + nameLabel.setPreferredSize(new java.awt.Dimension(159, 12)); isDeletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N isDeletedLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ImageThumbnailPanel.class, "ImageThumbnailPanel.isDeletedLabel.toolTipText")); // NOI18N - isDeletedLabel.setMaximumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - isDeletedLabel.setMinimumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - isDeletedLabel.setPreferredSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N scoreLabel.setToolTipText(""); - scoreLabel.setMaximumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - scoreLabel.setMinimumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - scoreLabel.setPreferredSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); + scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -92,53 +95,60 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(thumbnailPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 201, Short.MAX_VALUE) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() - .addComponent(countLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 163, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(nameLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(thumbnailPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 201, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() + .addComponent(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(thumbnailPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(countLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel countLabel; private javax.swing.JLabel fileSizeLabel; private javax.swing.JLabel isDeletedLabel; + private javax.swing.JLabel nameLabel; private javax.swing.JLabel scoreLabel; private javax.swing.JLabel thumbnailLabel; // End of variables declaration//GEN-END:variables @NbBundle.Messages({ - "# {0} - numberOfInstances", - "ImageThumbnailPanel.countLabel.text=Number of Instances: {0}", + "# {0} - otherInstanceCount", + "ImageThumbnailPanel.nameLabel.more.text= and {0} more", "ImageThumbnailPanel.isDeleted.text=All instances of file are deleted."}) @Override public Component getListCellRendererComponent(JList list, ImageThumbnailWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(DiscoveryUiUtils.getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - countLabel.setText(Bundle.ImageThumbnailPanel_countLabel_text(value.getResultFile().getAllInstances().size())); + String nameText = Paths.get(value.getResultFile().getFirstInstance().getParentPath(), value.getResultFile().getFirstInstance().getName()).toString(); + if (value.getResultFile().getAllInstances().size() > 1) { + nameText += Bundle.ImageThumbnailPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); + } + if (nameText.length() > MAX_NAME_STRING) { + nameText = "..." + nameText.substring(nameText.length() - (MAX_NAME_STRING - 3)); + } + nameLabel.setText(nameText); thumbnailLabel.setIcon(new ImageIcon(value.getThumbnail())); DiscoveryUiUtils.setDeletedIcon(value.getResultFile().isDeleted(), isDeletedLabel); - DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); + DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); return this; @@ -163,5 +173,4 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR return null; } - } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java index 34cf61e31e..dced6bf5da 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java @@ -760,12 +760,14 @@ public class ResultsPanel extends javax.swing.JPanel { documentPreviewViewer.addDocument(documentWrapper); } + @Messages({"ResultsPanel.unableToCreate.text=Unable to create summary."}) @Override protected Void doInBackground() throws Exception { String preview = FileSearch.summarize(documentWrapper.getResultFile().getFirstInstance()); - if (preview != null) { - documentWrapper.setPreview(preview); + if (preview == null) { + preview = Bundle.ResultsPanel_unableToCreate_text(); } + documentWrapper.setPreview(preview); return null; } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form index 4ae16fddf2..7e254689c1 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form @@ -24,38 +24,36 @@ - + - - - + + - + - + + + - - - - - - - - + + + + + - + @@ -67,7 +65,7 @@ - + @@ -102,4 +100,4 @@ - \ No newline at end of file + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java index fdddfa2c62..0ac8ecb2ee 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java @@ -25,6 +25,7 @@ import java.awt.Image; import java.awt.GridBagConstraints; import java.awt.Point; import java.awt.event.MouseEvent; +import java.nio.file.Paths; import java.util.concurrent.TimeUnit; import javax.swing.ImageIcon; import javax.swing.JComponent; @@ -100,7 +101,7 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe imagePanel = new javax.swing.JPanel(); fileSizeLabel = new javax.swing.JLabel(); - countLabel = new javax.swing.JLabel(); + nameLabel = new javax.swing.JLabel(); scoreLabel = new javax.swing.JLabel(); deletedLabel = new javax.swing.JLabel(); @@ -109,14 +110,14 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe imagePanel.setLayout(new java.awt.GridBagLayout()); scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N - scoreLabel.setMaximumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - scoreLabel.setMinimumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - scoreLabel.setPreferredSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); + scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); deletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N - deletedLabel.setMaximumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - deletedLabel.setMinimumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - deletedLabel.setPreferredSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); + deletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + deletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + deletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -127,52 +128,55 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(imagePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 776, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 248, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(countLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 124, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(deletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(nameLabel, 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(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(imagePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(deletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(countLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(deletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel countLabel; private javax.swing.JLabel deletedLabel; private javax.swing.JLabel fileSizeLabel; private javax.swing.JPanel imagePanel; + private javax.swing.JLabel nameLabel; private javax.swing.JLabel scoreLabel; // End of variables declaration//GEN-END:variables @Messages({ - "# {0} - numberOfInstances", - "VideoThumbnailPanel.countLabel.text=Number of Instances: {0}", + "# {0} - otherInstanceCount", + "VideoThumbnailPanel.nameLabel.more.text= and {0} more", "VideoThumbnailPanel.deleted.text=All instances of file are deleted."}) @Override public Component getListCellRendererComponent(JList list, VideoThumbnailsWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - countLabel.setText(Bundle.VideoThumbnailPanel_countLabel_text(value.getResultFile().getAllInstances().size())); + String nameText = Paths.get(value.getResultFile().getFirstInstance().getParentPath(), value.getResultFile().getFirstInstance().getName()).toString(); + if (value.getResultFile().getAllInstances().size() > 1) { + nameText += Bundle.VideoThumbnailPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); + } + nameLabel.setText(nameText); addThumbnails(value); imagePanel.setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); DiscoveryUiUtils.setDeletedIcon(value.getResultFile().isDeleted(), deletedLabel); - DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); + DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); return this; } From b5e84692740498ea305f5e8b92ff80650d1d629e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Feb 2020 19:06:34 -0500 Subject: [PATCH 11/24] 6040 fix missing bundle message and exceptions from other workers --- .../autopsy/filequery/Bundle.properties-MERGED | 15 +++++++-------- .../autopsy/filequery/ImageThumbnailPanel.form | 3 --- .../autopsy/filequery/ImageThumbnailPanel.java | 1 - .../sleuthkit/autopsy/filequery/ResultsPanel.java | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED index de944bf3cf..ea9e846568 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED @@ -14,8 +14,8 @@ DiscoveryUiUtility.megaBytes.text=MB # {1} - units DiscoveryUiUtility.sizeLabel.text=Size: {0} {1} DiscoveryUiUtility.terraBytes.text=TB -# {0} - extension -DocumentPanel.documentType.extension.text=Extension: {0} +# {0} - otherInstanceCount +DocumentPanel.nameLabel.more.text=\ and {0} more DocumentWrapper.previewInitialValue=Preview not generated yet. FileGroup.groupSortingAlgorithm.groupName.text=Group Name FileGroup.groupSortingAlgorithm.groupSize.text=Group Size @@ -175,9 +175,9 @@ FileSorter.SortingMethod.fullPath.displayName=Full Path FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names GroupsListPanel.noResults.message.text=No results were found for the selected filters. GroupsListPanel.noResults.title.text=No results found -# {0} - numberOfInstances -ImageThumbnailPanel.countLabel.text=Number of Instances: {0} ImageThumbnailPanel.isDeleted.text=All instances of file are deleted. +# {0} - otherInstanceCount +ImageThumbnailPanel.nameLabel.more.text=\ and {0} more OpenFileDiscoveryAction.resultsIncomplete.text=Results may be incomplete ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it. ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable. @@ -210,19 +210,18 @@ FileSearchPanel.stepTwoLabel.text=Step 2: Filter which images to show FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings DiscoveryTopComponent.stepOneLabel.text=Step 1: Pick File Type DiscoveryTopComponent.documentsButton.text=Documents -DocumentPanel.countLabel.toolTipText= DocumentPanel.fileSizeLabel.toolTipText= -DocumentPanel.documentType.text= DocumentPanel.isDeletedLabel.toolTipText= ImageThumbnailPanel.isDeletedLabel.toolTipText= +ResultsPanel.unableToCreate.text=Unable to create summary. ResultsPanel.viewFileInDir.name=View File in Directory VideoThumbnailPanel.bytes.text=bytes -# {0} - numberOfInstances -VideoThumbnailPanel.countLabel.text=Number of Instances: {0} VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB VideoThumbnailPanel.kiloBytes.text=KB VideoThumbnailPanel.megaBytes.text=MB +# {0} - otherInstanceCount +VideoThumbnailPanel.nameLabel.more.text=\ and {0} more # {0} - fileSize # {1} - units VideoThumbnailPanel.sizeLabel.text=Size: {0} {1} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form index e8b19379c1..b491a2c6de 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form @@ -84,9 +84,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java index 0a50a2d41c..b7d0e7340f 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java @@ -70,7 +70,6 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR fileSizeLabel.setToolTipText(""); - org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ImageThumbnailPanel.class, "ImageThumbnailPanel.nameLabel.text")); // NOI18N nameLabel.setToolTipText(""); nameLabel.setMaximumSize(new java.awt.Dimension(159, 12)); nameLabel.setMinimumSize(new java.awt.Dimension(159, 12)); diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java index dced6bf5da..4711303123 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java @@ -702,6 +702,13 @@ public class ResultsPanel extends javax.swing.JPanel { @Override protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Video Worker Exception for file: " + thumbnailWrapper.getResultFile().getFirstInstance().getId(), ex); + } catch (CancellationException ignored) { + //we want to do nothing in response to this since we allow it to be cancelled + } videoThumbnailViewer.repaint(); } } @@ -736,6 +743,13 @@ public class ResultsPanel extends javax.swing.JPanel { @Override protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Image Worker Exception for file: " + thumbnailWrapper.getResultFile().getFirstInstance().getId(), ex); + } catch (CancellationException ignored) { + //we want to do nothing in response to this since we allow it to be cancelled + } imageThumbnailViewer.repaint(); } From 7b7291119f9a9d32a7fec57c367bde25e94a33ba Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 21 Feb 2020 11:38:28 -0500 Subject: [PATCH 12/24] 6040 fix paths for name field --- Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java | 2 +- .../org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java | 2 +- .../org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java index 30e4b928db..95a2324ed9 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java @@ -136,7 +136,7 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere @Override public Component getListCellRendererComponent(JList list, DocumentWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(DiscoveryUiUtils.getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - String nameText = Paths.get(value.getResultFile().getFirstInstance().getParentPath(), value.getResultFile().getFirstInstance().getName()).toString(); + String nameText = value.getResultFile().getFirstInstance().getParentPath() + value.getResultFile().getFirstInstance().getName(); if (value.getResultFile().getAllInstances().size() > 1) { nameText += Bundle.DocumentPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java index b7d0e7340f..9ef5572c8d 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java @@ -137,7 +137,7 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR @Override public Component getListCellRendererComponent(JList list, ImageThumbnailWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(DiscoveryUiUtils.getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - String nameText = Paths.get(value.getResultFile().getFirstInstance().getParentPath(), value.getResultFile().getFirstInstance().getName()).toString(); + String nameText = value.getResultFile().getFirstInstance().getParentPath() + value.getResultFile().getFirstInstance().getName(); if (value.getResultFile().getAllInstances().size() > 1) { nameText += Bundle.ImageThumbnailPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java index 0ac8ecb2ee..4c349316d3 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java @@ -168,7 +168,7 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe @Override public Component getListCellRendererComponent(JList list, VideoThumbnailsWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - String nameText = Paths.get(value.getResultFile().getFirstInstance().getParentPath(), value.getResultFile().getFirstInstance().getName()).toString(); + String nameText = value.getResultFile().getFirstInstance().getParentPath() + value.getResultFile().getFirstInstance().getName(); if (value.getResultFile().getAllInstances().size() > 1) { nameText += Bundle.VideoThumbnailPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); } From b611e6b822ae0b4e1f0c13da3bd9d70692a9ff20 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 21 Feb 2020 13:09:37 -0500 Subject: [PATCH 13/24] 6040 fix codacy address comment --- .../org/sleuthkit/autopsy/filequery/DocumentPanel.java | 1 - .../org/sleuthkit/autopsy/filequery/FileSearch.java | 10 +++------- .../autopsy/filequery/ImageThumbnailPanel.java | 1 - .../autopsy/filequery/VideoThumbnailPanel.java | 1 - 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java index 95a2324ed9..849d3843ec 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java @@ -23,7 +23,6 @@ import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.MouseEvent; -import java.nio.file.Paths; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListCellRenderer; diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index 1f6e65bba9..ee5c36c8e3 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -264,11 +264,7 @@ class FileSearch { if (localSummarizer == null) { synchronized (searchCache) { if (localSummarizer == null) { - try { - localSummarizer = getLocalSummarizer(); - } catch (IOException ignored) { - //no summarizers being present is not unexpected - } + localSummarizer = getLocalSummarizer(); } } } @@ -313,7 +309,7 @@ class FileSearch { * * @throws IOException */ - private static TextSummarizer getLocalSummarizer() throws IOException { + private static TextSummarizer getLocalSummarizer() { Collection summarizers = Lookup.getDefault().lookupAll(TextSummarizer.class ); @@ -321,7 +317,7 @@ class FileSearch { summarizerToUse = summarizers.iterator().next(); return summarizerToUse; } - throw new IOException("No summarizers found"); + return null; } /** diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java index 9ef5572c8d..78654296cb 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java @@ -23,7 +23,6 @@ import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.MouseEvent; -import java.nio.file.Paths; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JList; diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java index 4c349316d3..cff5502e73 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java @@ -25,7 +25,6 @@ import java.awt.Image; import java.awt.GridBagConstraints; import java.awt.Point; import java.awt.event.MouseEvent; -import java.nio.file.Paths; import java.util.concurrent.TimeUnit; import javax.swing.ImageIcon; import javax.swing.JComponent; From 7de33d4b35ae2c9c1c307ad293707cdf8447a73e Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Mon, 24 Feb 2020 13:40:09 -0500 Subject: [PATCH 14/24] 6014: Update central repository database creation to make personas tables. --- .../datamodel/CentralRepository.java | 11 +- .../CorrelationAttributeInstance.java | 42 ++- .../centralrepository/datamodel/Persona.java | 87 +++++ .../datamodel/RdbmsCentralRepo.java | 74 ++++ .../datamodel/RdbmsCentralRepoFactory.java | 340 +++++++++++++++++- .../optionspanel/EamDbSettingsDialog.java | 1 - .../CommonAttributeCaseSearchResults.java | 5 +- .../CommonAttributeCountSearchResults.java | 7 +- .../CommonAttributePanel.java | 6 +- .../InterCasePanel.java | 5 +- .../CorrelationCaseChildNodeFactory.java | 4 +- .../InterCaseTestUtils.java | 13 +- 12 files changed, 554 insertions(+), 41 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java index 3e7ac158a9..e357d529e5 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java @@ -802,5 +802,14 @@ public interface CentralRepository { * * @throws CentralRepoException */ - public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException; + public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException; + + + /** + * Returns list of all correlation types. + * + * @return list of Correlation types + * @throws CentralRepoException + */ + public List getCorrelationTypes() throws CentralRepoException; } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java index f13b27787d..a8974f8e5a 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2018 Basis Technology Corp. + * Copyright 2015-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,7 @@ import java.util.List; import java.util.Objects; import java.util.regex.Pattern; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.TskData; /** @@ -220,6 +221,9 @@ public class CorrelationAttributeInstance implements Serializable { public static final int IMEI_TYPE_ID = 7; public static final int IMSI_TYPE_ID = 8; public static final int ICCID_TYPE_ID = 9; + + // An offset to assign Ids for additional correlation types. + public static final int ADDITIONAL_TYPES_BASE_ID = 1000; /** * Load the default correlation types @@ -238,18 +242,30 @@ public class CorrelationAttributeInstance implements Serializable { "CorrelationType.IMSI.displayName=IMSI Number", "CorrelationType.ICCID.displayName=ICCID Number"}) public static List getDefaultCorrelationTypes() throws CentralRepoException { - List DEFAULT_CORRELATION_TYPES = new ArrayList<>(); - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(FILES_TYPE_ID, Bundle.CorrelationType_FILES_displayName(), "file", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(DOMAIN_TYPE_ID, Bundle.CorrelationType_DOMAIN_displayName(), "domain", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(EMAIL_TYPE_ID, Bundle.CorrelationType_EMAIL_displayName(), "email_address", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(PHONE_TYPE_ID, Bundle.CorrelationType_PHONE_displayName(), "phone_number", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(USBID_TYPE_ID, Bundle.CorrelationType_USBID_displayName(), "usb_devices", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(SSID_TYPE_ID, Bundle.CorrelationType_SSID_displayName(), "wireless_networks", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(MAC_TYPE_ID, Bundle.CorrelationType_MAC_displayName(), "mac_address", true, true)); //NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(IMEI_TYPE_ID, Bundle.CorrelationType_IMEI_displayName(), "imei_number", true, true)); //NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(IMSI_TYPE_ID, Bundle.CorrelationType_IMSI_displayName(), "imsi_number", true, true)); //NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(ICCID_TYPE_ID, Bundle.CorrelationType_ICCID_displayName(), "iccid_number", true, true)); //NON-NLS - return DEFAULT_CORRELATION_TYPES; + List defaultCorrelationTypes = new ArrayList<>(); + + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(FILES_TYPE_ID, Bundle.CorrelationType_FILES_displayName(), "file", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(DOMAIN_TYPE_ID, Bundle.CorrelationType_DOMAIN_displayName(), "domain", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(EMAIL_TYPE_ID, Bundle.CorrelationType_EMAIL_displayName(), "email_address", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(PHONE_TYPE_ID, Bundle.CorrelationType_PHONE_displayName(), "phone_number", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(USBID_TYPE_ID, Bundle.CorrelationType_USBID_displayName(), "usb_devices", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(SSID_TYPE_ID, Bundle.CorrelationType_SSID_displayName(), "wireless_networks", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(MAC_TYPE_ID, Bundle.CorrelationType_MAC_displayName(), "mac_address", true, true)); //NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(IMEI_TYPE_ID, Bundle.CorrelationType_IMEI_displayName(), "imei_number", true, true)); //NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(IMSI_TYPE_ID, Bundle.CorrelationType_IMSI_displayName(), "imsi_number", true, true)); //NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(ICCID_TYPE_ID, Bundle.CorrelationType_ICCID_displayName(), "iccid_number", true, true)); //NON-NLS + + // Create Correlation Types for Accounts. + int correlationTypeId = ADDITIONAL_TYPES_BASE_ID; + for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) { + // Skip Phone and Email accounts as there are already Correlation types defined for those. + if (type != Account.Type.EMAIL && type != Account.Type.PHONE) { + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(correlationTypeId, type.getDisplayName(), type.getTypeName().toLowerCase(), true, true)); //NON-NLS + correlationTypeId++; + } + } + + return defaultCorrelationTypes; } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java new file mode 100644 index 0000000000..5fc458353b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java @@ -0,0 +1,87 @@ +/* + * Central Repository + * + * Copyright 2020 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.centralrepository.datamodel; + +/** + * This class abstracts a persona. + * + * An examiner may create a persona from an account. + * + */ +class Persona { + + /** + * Defines level of confidence in assigning a persona to an account. + */ + public enum Confidence { + UNKNOWN(1, "Unknown"), + LOW(2, "Low confidence"), + MEDIUM(3, "Medium confidence"), + HIGH(4, "High confidence"), + DERIVED(5, "Derived directly"); + + private final String name; + private final int level_id; + + Confidence(int level, String name) { + this.name = name; + this.level_id = level; + + } + + @Override + public String toString() { + return name; + } + + public int getLevel() { + return this.level_id; + } + } + + /** + * Defines status of a persona. + */ + public enum PersonaStatus { + + UNKNOWN(1, "Unknown"), + ACTIVE(2, "Active"), + MERGED(3, "Merged"), + SPLIT(4, "Split"), + DELETED(5, "Deleted"); + + private final String description; + private final int status_id; + + PersonaStatus(int status, String description) { + this.status_id = status; + this.description = description; + } + + @Override + public String toString() { + return description; + } + + public int getStatus() { + return this.status_id; + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java index 513fd3f944..fedf0b75c9 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java @@ -1373,6 +1373,9 @@ abstract class RdbmsCentralRepo implements CentralRepository { } synchronized (bulkArtifacts) { + if (bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())) == null) { + bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), new ArrayList<>()); + } bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact); bulkArtifactsCount++; @@ -2845,6 +2848,7 @@ abstract class RdbmsCentralRepo implements CentralRepository { typeId = newCorrelationTypeKnownId(newType); } + typeCache.put(newType.getId(), newType); return typeId; } @@ -3105,6 +3109,45 @@ abstract class RdbmsCentralRepo implements CentralRepository { } } + /** + * Returns a list of all correlation types. It uses the cache to build the + * list. If the cache is empty, it reads from the database and loads up the + * cache. + * + * @return List of correlation types. + * @throws CentralRepoException + */ + @Override + public List getCorrelationTypes() throws CentralRepoException { + + if (typeCache.size() == 0) { + getCorrelationTypesFromCr(); + } + + return new ArrayList<>(typeCache.asMap().values()); + } + + /** + * Gets a Correlation type with the specified name. + * + * @param correlationtypeName Correlation type name + * @return Correlation type matching the given name, null if none matches. + * + * @throws CentralRepoException + */ + public CorrelationAttributeInstance.Type getCorrelationTypeByName(String correlationtypeName) throws CentralRepoException { + List correlationTypesList = getCorrelationTypes(); + + CorrelationAttributeInstance.Type correlationType + = correlationTypesList.stream() + .filter(x -> correlationtypeName.equalsIgnoreCase(x.getDisplayName())) + .findAny() + .orElse(null); + + return null; + } + + /** * Get the EamArtifact.Type that has the given Type.Id from the central repo * @@ -3142,6 +3185,37 @@ abstract class RdbmsCentralRepo implements CentralRepository { } } + /** + * Reads the correlation types from the database and loads them up in the cache. + * + * @throws CentralRepoException If there is an error. + */ + private void getCorrelationTypesFromCr() throws CentralRepoException { + + // clear out the cache + typeCache.invalidateAll(); + + Connection conn = connect(); + PreparedStatement preparedStatement = null; + ResultSet resultSet = null; + + String sql = "SELECT * FROM correlation_types"; + try { + preparedStatement = conn.prepareStatement(sql); + resultSet = preparedStatement.executeQuery(); + while (resultSet.next()) { + CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet); + typeCache.put(aType.getId(), aType); + } + } catch (SQLException ex) { + throw new CentralRepoException("Error getting correlation types.", ex); // NON-NLS + } finally { + CentralRepoDbUtil.closeStatement(preparedStatement); + CentralRepoDbUtil.closeResultSet(resultSet); + CentralRepoDbUtil.closeConnection(conn); + } + } + /** * Convert a ResultSet to a EamCase object * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java index 33b6009dea..3ef09b263c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java @@ -19,12 +19,17 @@ package org.sleuthkit.autopsy.centralrepository.datamodel; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona.Confidence; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona.PersonaStatus; import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo.SOFTWARE_CR_DB_SCHEMA_VERSION; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.Account; /** * Creates the CR schema and populates it with initial data. @@ -132,11 +137,11 @@ public class RdbmsCentralRepoFactory { stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); // Create a separate instance and reference table for each artifact type - List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + List defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes(); String reference_type_dbname; String instance_type_dbname; - for (CorrelationAttributeInstance.Type type : DEFAULT_CORRELATION_TYPES) { + for (CorrelationAttributeInstance.Type type : defaultCorrelationTypes) { reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); @@ -154,6 +159,8 @@ public class RdbmsCentralRepoFactory { stmt.execute(String.format(getReferenceTypeValueKnownstatusIndexTemplate(), reference_type_dbname, reference_type_dbname)); } } + + createPersonaTables(stmt); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS return false; @@ -184,7 +191,11 @@ public class RdbmsCentralRepoFactory { return false; } - boolean result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) && CentralRepoDbUtil.insertDefaultOrganization(conn); + boolean result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) + && CentralRepoDbUtil.insertDefaultOrganization(conn) + && insertDefaultPersonaTablesContent(conn); + + CentralRepoDbUtil.closeConnection(conn); return result; } @@ -413,7 +424,7 @@ public class RdbmsCentralRepoFactory { /** * Get the template for creating an index on the value column of an instance * table. %s will exist in the template where the name of the new table will - * be addedd. + * be added. * * @return a String which is a template for adding an index to the value * column of a _instances table @@ -426,7 +437,7 @@ public class RdbmsCentralRepoFactory { /** * Get the template for creating an index on the known_status column of an * instance table. %s will exist in the template where the name of the new - * table will be addedd. + * table will be added. * * @return a String which is a template for adding an index to the * known_status column of a _instances table @@ -439,7 +450,7 @@ public class RdbmsCentralRepoFactory { /** * Get the template for creating an index on the file_obj_id column of an * instance table. %s will exist in the template where the name of the new - * table will be addedd. + * table will be added. * * @return a String which is a template for adding an index to the * file_obj_id column of a _instances table @@ -525,7 +536,16 @@ public class RdbmsCentralRepoFactory { } } - + private static String getOnConflictDoNothingClause(CentralRepoPlatforms selectedPlatform) { + switch (selectedPlatform) { + case POSTGRESQL: + return "ON CONFLICT DO NOTHING"; + case SQLITE: + return ""; + default: + return ""; + } + } /** * Returns an ephemeral connection to the CR database. * @@ -541,4 +561,310 @@ public class RdbmsCentralRepoFactory { return null; } } + + /** + * Creates the tables for Persona. + * + * @return True if success, False otherwise. + */ + private boolean createPersonaTables(Statement stmt) throws SQLException { + + stmt.execute(getCreateAccountTypesTableStatement(selectedPlatform)); + stmt.execute(getCreateConfidenceTableStatement(selectedPlatform)); + stmt.execute(getCreateExaminersTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonaStatusTableStatement(selectedPlatform)); + stmt.execute(getCreateAliasesTableStatement(selectedPlatform)); + + stmt.execute(getCreateAccountsTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonasTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonaAliasTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonaMetadataTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonaAccountsTableStatement(selectedPlatform)); + + return true; + } + + + /** + * Get the SQL string for creating a new account_types table in a central + * repository. + * + * @return SQL string for creating account_types table + */ + static String getCreateAccountTypesTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS account_types (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "type_name TEXT NOT NULL," + + "display_name TEXT NOT NULL," + + "correlation_type_id " + getBigIntType(selectedPlatform) + " ," + + "CONSTRAINT type_name_unique UNIQUE (type_name)," + + "FOREIGN KEY (correlation_type_id) REFERENCES correlation_types(id)" + + ")"; + } + + /** + * Get the SQL String for creating a new confidence table in a central + * repository. + * + * @return SQL string for creating confidence table + */ + static String getCreateConfidenceTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS confidence (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "confidence_id integer NOT NULL," + + "description TEXT," + + "CONSTRAINT level_unique UNIQUE (confidence_id)" + + ")"; + } + + /** + * Get the SQL String for creating a new examiners table in a central + * repository. + * + * @return SQL string for creating examiners table + */ + static String getCreateExaminersTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS examiners (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "login_name TEXT NOT NULL," + + "display_name TEXT," + + "CONSTRAINT login_name_unique UNIQUE(login_name)" + + ")"; + } + + /** + * Get the SQL String for creating a new persona_status table in a central + * repository. + * + * @return SQL string for creating persona_status table + */ + static String getCreatePersonaStatusTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS persona_status (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "status_id integer NOT NULL," + + "status TEXT NOT NULL," + + "CONSTRAINT status_unique UNIQUE(status_id)" + + ")"; + } + + /** + * Get the SQL String for creating a new aliases table in a central + * repository. + * + * @return SQL string for creating aliases table + */ + static String getCreateAliasesTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS aliases (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "alias TEXT NOT NULL," + + "CONSTRAINT alias_unique UNIQUE(alias)" + + ")"; + } + + /** + * Get the SQL String for creating a new accounts table in a central + * repository. + * + * @return SQL string for creating accounts table + */ + static String getCreateAccountsTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS accounts (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "account_type_id integer NOT NULL," + + "account_unique_identifier TEXT NOT NULL," + + "CONSTRAINT account_unique UNIQUE(account_type_id, account_unique_identifier)," + + "FOREIGN KEY (account_type_id) REFERENCES account_types(id)" + + ")"; + } + + /** + * Get the SQL String for creating a new personas table in a central + * repository. + * + * @return SQL string for creating personas table + */ + static String getCreatePersonasTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS personas (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "uuid TEXT NOT NULL," + + "comment TEXT NOT NULL," + + "name TEXT NOT NULL," + + "created_date " + getBigIntType(selectedPlatform) + " ," + + "modified_date " + getBigIntType(selectedPlatform) + " ," + + "status_id integer NOT NULL," + + "CONSTRAINT uuid_unique UNIQUE(uuid)," + + "FOREIGN KEY (status_id) REFERENCES persona_status(status_id)" + + ")"; + } + + /** + * Get the SQL String for creating a new persona_alias table in a central + * repository. + * + * @return SQL string for creating persona_alias table + */ + static String getCreatePersonaAliasTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS persona_alias (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "persona_id " + getBigIntType(selectedPlatform) + " ," + + "alias_id " + getBigIntType(selectedPlatform) + " ," + + "justification TEXT NOT NULL," + + "confidence_id integer NOT NULL," + + "date_added " + getBigIntType(selectedPlatform) + " ," + + "examiner_id integer NOT NULL," + + "FOREIGN KEY (persona_id) REFERENCES personas(id)," + + "FOREIGN KEY (alias_id) REFERENCES aliases(id)," + + "FOREIGN KEY (confidence_id) REFERENCES confidence(confidence_id)," + + "FOREIGN KEY (examiner_id) REFERENCES examiners(id)" + + ")"; + } + + /** + * Get the SQL String for creating a new persona_metadata table in a central + * repository. + * + * @return SQL string for creating persona_metadata table + */ + static String getCreatePersonaMetadataTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS persona_metadata (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "persona_id " + getBigIntType(selectedPlatform) + " ," + + "name TEXT NOT NULL," + + "value TEXT NOT NULL," + + "justification TEXT NOT NULL," + + "confidence_id integer NOT NULL," + + "date_added " + getBigIntType(selectedPlatform) + " ," + + "examiner_id integer NOT NULL," + + "CONSTRAINT unique_metadata UNIQUE(persona_id, name)," + + "FOREIGN KEY (persona_id) REFERENCES personas(id)," + + "FOREIGN KEY (confidence_id) REFERENCES confidence(confidence_id)," + + "FOREIGN KEY (examiner_id) REFERENCES examiners(id)" + + ")"; + } + + /** + * Get the SQL String for creating a new persona_accounts table in a central + * repository. + * + * @return SQL string for creating persona_accounts table + */ + static String getCreatePersonaAccountsTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS persona_accounts (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "persona_id " + getBigIntType(selectedPlatform) + " ," + + "account_id " + getBigIntType(selectedPlatform) + " ," + + "justification TEXT NOT NULL," + + "confidence_id integer NOT NULL," + + "date_added " + getBigIntType(selectedPlatform) + " ," + + "examiner_id integer NOT NULL," + + "FOREIGN KEY (persona_id) REFERENCES personas(id)," + + "FOREIGN KEY (account_id) REFERENCES accounts(id)," + + "FOREIGN KEY (confidence_id) REFERENCES confidence(confidence_id)," + + "FOREIGN KEY (examiner_id) REFERENCES examiners(id)" + + ")"; + } + + + /** + * Inserts the default content in persona related tables. + * + * @param conn Database connection to use. + * + * @return True if success, false otherwise. + */ + private boolean insertDefaultPersonaTablesContent(Connection conn) { + + Statement stmt = null; + try { + stmt = conn.createStatement(); + + // populate the confidence table + for (Confidence confidence : Persona.Confidence.values()) { + String sqlString = "INSERT INTO confidence (confidence_id, description) VALUES ( " + confidence.getLevel() + ", '" + confidence.toString() + "')" //NON-NLS + + getOnConflictDoNothingClause(selectedPlatform); + stmt.execute(sqlString); + } + + // populate the persona_status table + for (PersonaStatus status : Persona.PersonaStatus.values()) { + String sqlString = "INSERT INTO persona_status (status_id, status) VALUES ( " + status.getStatus() + ", '" + status.toString() + "')" //NON-NLS + + getOnConflictDoNothingClause(selectedPlatform); + stmt.execute(sqlString); + } + + // Populate the account_types table + for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) { + int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type); + if (correlationTypeId > 0) { + String sqlString = String.format("INSERT INTO account_types (type_name, display_name, correlation_type_id) VALUES ('%s', '%s', %d)" + getOnConflictDoNothingClause(selectedPlatform), + type.getTypeName(), type.getDisplayName(), correlationTypeId); + stmt.execute(sqlString); + } + } + + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in Persona tables."), ex); + return false; + } finally { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException ex2) { + LOGGER.log(Level.SEVERE, "Error closing statement.", ex2); + } + } + } + + return true; + } + + /** + * Returns the correlation type id for the given account type, + * from the correlation_types table. + * + * @param conn Connection to use for database query. + * @param accountType Account type to look for. + * ' + * @return correlation type id. + */ + private int getCorrelationTypeIdForAccountType(Connection conn, Account.Type accountType) { + + int typeId = -1; + if (accountType == Account.Type.EMAIL) { + typeId = CorrelationAttributeInstance.EMAIL_TYPE_ID; + } else if (accountType == Account.Type.PHONE) { + typeId = CorrelationAttributeInstance.PHONE_TYPE_ID; + } else { + ResultSet resultSet = null; + + PreparedStatement preparedStatementQuery = null; + String querySql = "SELECT * FROM correlation_types WHERE display_name=?"; + try { + preparedStatementQuery = conn.prepareStatement(querySql); + preparedStatementQuery.setString(1, accountType.getDisplayName()); + + resultSet = preparedStatementQuery.executeQuery(); + if (resultSet.next()) { + typeId = resultSet.getInt("id"); + } + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to get correlation typeId for account type %s.", accountType.getTypeName()), ex); + } finally { + CentralRepoDbUtil.closeStatement(preparedStatementQuery); + CentralRepoDbUtil.closeResultSet(resultSet); + } + } + + return typeId; + } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java index 5c5ba6072b..519a7b2453 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java @@ -460,7 +460,6 @@ public class EamDbSettingsDialog extends JDialog { if (!result) { // Remove the incomplete database if (dbCreated) { - // RAMAN TBD: migrate deleteDatabase() to RdbmsCentralRepoFactory dbSettingsPostgres.deleteDatabase(); } diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCaseSearchResults.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCaseSearchResults.java index 0f87533504..e096638434 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCaseSearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCaseSearchResults.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -123,8 +123,7 @@ final public class CommonAttributeCaseSearchResults { if (currentCaseDataSourceMap == null) { //there are no results return filteredCaseNameToDataSourcesTree; } - CorrelationAttributeInstance.Type attributeType = CorrelationAttributeInstance - .getDefaultCorrelationTypes() + CorrelationAttributeInstance.Type attributeType = CentralRepository.getInstance().getCorrelationTypes() .stream() .filter(filterType -> filterType.getId() == resultTypeId) .findFirst().get(); diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCountSearchResults.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCountSearchResults.java index 18e7195f34..85923e53b6 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCountSearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCountSearchResults.java @@ -128,14 +128,13 @@ final public class CommonAttributeCountSearchResults { return; } - CorrelationAttributeInstance.Type attributeType = CorrelationAttributeInstance - .getDefaultCorrelationTypes() + CentralRepository eamDb = CentralRepository.getInstance(); + CorrelationAttributeInstance.Type attributeType = eamDb.getCorrelationTypes() .stream() .filter(filterType -> filterType.getId() == this.resultTypeId) .findFirst().get(); - CentralRepository eamDb = CentralRepository.getInstance(); - + Map> itemsToRemove = new HashMap<>(); //Call countUniqueDataSources once to reduce the number of DB queries needed to get //the frequencyPercentage diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributePanel.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributePanel.java index f56f9dd9a8..43d834e39d 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributePanel.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -255,7 +255,7 @@ final class CommonAttributePanel extends javax.swing.JDialog implements Observer filterByDocuments = interCasePanel.documentsCheckboxIsSelected(); } if (corType == null) { - corType = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(0); + corType = CentralRepository.getInstance().getCorrelationTypes().get(0); } if (caseId == InterCasePanel.NO_CASE_SELECTED) { builder = new AllInterCaseCommonAttributeSearcher(filterByMedia, filterByDocuments, corType, percentageThreshold); @@ -366,7 +366,7 @@ final class CommonAttributePanel extends javax.swing.JDialog implements Observer filterByDocuments = interCasePanel.documentsCheckboxIsSelected(); } if (corType == null) { - corType = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(0); + corType = CentralRepository.getInstance().getCorrelationTypes().get(0); } if (caseId == InterCasePanel.NO_CASE_SELECTED) { builder = new AllInterCaseCommonAttributeSearcher(filterByMedia, filterByDocuments, corType, percentageThreshold); diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java index 88d60db3be..a2c1c01529 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,6 +31,7 @@ import java.util.logging.Level; import javax.swing.ComboBoxModel; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -117,7 +118,7 @@ public final class InterCasePanel extends javax.swing.JPanel { void setupCorrelationTypeFilter() { this.correlationTypeFilters = new HashMap<>(); try { - List types = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + List types = CentralRepository.getInstance().getCorrelationTypes(); for (CorrelationAttributeInstance.Type type : types) { correlationTypeFilters.put(type.getDisplayName(), type); this.correlationTypeComboBox.addItem(type.getDisplayName()); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java index 5105f1628d..49617c9dfb 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -111,7 +111,7 @@ final class CorrelationCaseChildNodeFactory extends ChildFactory(); - List correcationTypeList = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + List correcationTypeList = CentralRepository.getInstance().getCorrelationTypes(); correcationTypeList.forEach((type) -> { correlationTypeMap.put(type.getId(), type); }); diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseTestUtils.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseTestUtils.java index 69dcdc71b9..65b47bcb3b 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseTestUtils.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseTestUtils.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -62,6 +62,7 @@ import org.sleuthkit.autopsy.modules.photoreccarver.PhotoRecCarverIngestModuleFa import org.sleuthkit.autopsy.modules.vmextractor.VMExtractorIngestModuleFactory; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepoFactory; /** * Utilities for testing intercase correlation feature. @@ -220,7 +221,7 @@ class InterCaseTestUtils { this.kitchenShink = new IngestJobSettings(InterCaseTestUtils.class.getCanonicalName(), IngestType.ALL_MODULES, kitchenSink); try { - Collection types = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + Collection types = CentralRepository.getInstance().getCorrelationTypes(); //TODO use ids instead of strings FILE_TYPE = types.stream().filter(type -> type.getDisplayName().equals("Files")).findAny().get(); @@ -248,7 +249,7 @@ class InterCaseTestUtils { CentralRepository.getInstance().shutdownConnections(); } FileUtils.deleteDirectory(CENTRAL_REPO_DIRECTORY_PATH.toFile()); - } catch (IOException | CentralRepoExceptionex) { + } catch (IOException | CentralRepoException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex.getMessage()); } @@ -297,8 +298,10 @@ class InterCaseTestUtils { crSettings.createDbDirectory(); } - crSettings.initializeDatabaseSchema(); - crSettings.insertDefaultDatabaseContent(); + RdbmsCentralRepoFactory centralRepoSchemaFactory = new RdbmsCentralRepoFactory(CentralRepoPlatforms.SQLITE, crSettings); + centralRepoSchemaFactory.initializeDatabaseSchema(); + centralRepoSchemaFactory.insertDefaultDatabaseContent(); + crSettings.saveSettings(); CentralRepoPlatforms.setSelectedPlatform(CentralRepoPlatforms.SQLITE.name()); CentralRepoPlatforms.saveSelectedPlatform(); From 29c3cb6c25720abe750f3a323587a0316953116b Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Mon, 24 Feb 2020 14:16:37 -0500 Subject: [PATCH 15/24] Addressed Codacy comment. --- .../autopsy/centralrepository/datamodel/CentralRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java index e357d529e5..fe54161762 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java @@ -811,5 +811,5 @@ public interface CentralRepository { * @return list of Correlation types * @throws CentralRepoException */ - public List getCorrelationTypes() throws CentralRepoException; + List getCorrelationTypes() throws CentralRepoException; } From c8bf39e715490170196add63610ae8ad7508ff35 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 24 Feb 2020 16:00:31 -0500 Subject: [PATCH 16/24] Skeleton for creating correlation attrs for account artifacts --- .../DataContentViewerOtherCases.java | 4 +- .../datamodel/CorrelationAttributeUtil.java | 115 ++++++++++-------- .../eventlisteners/CaseEventListener.java | 4 +- .../eventlisteners/IngestEventsListener.java | 4 +- .../AnnotationsContentViewer.java | 4 +- .../autopsy/datamodel/GetSCOTask.java | 2 +- 6 files changed, 74 insertions(+), 59 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index a28a013220..027a4ad7df 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2017-2019 Basis Technology Corp. + * Copyright 2017-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -464,7 +464,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // correlate on blackboard artifact attributes if they exist and supported BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node); if (bbArtifact != null && CentralRepository.isEnabled()) { - ret.addAll(CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false)); + ret.addAll(CorrelationAttributeUtil.makeAttrsForArtifact(bbArtifact)); } // we can correlate based on the MD5 if it is enabled diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 07eb454ac5..9ac0dddf9e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2020 Basis Technology Corp. + * Copyright 2017-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -48,55 +48,61 @@ public class CorrelationAttributeUtil { } /** - * Static factory method to examine a BlackboardArtifact to determine if it - * has contents that can be used for Correlation. If so, return a - * EamArtifact with a single EamArtifactInstance within. If not, return - * null. + * Examines an artifact and makes zero to many correlation attribute + * instances from its attributes. * - * @param artifact BlackboardArtifact to examine - * @param checkEnabled If true, only create a CorrelationAttribute if it is - * enabled + * IMPORTANT: The correlation attribute instances are NOT added to the + * central repository by this method. * - * @return List of EamArtifacts + * @param artifact An artifact. + * + * @return A list, possibly empty, of correlation attribute instances for + * the artifact. */ - public static List makeInstancesFromBlackboardArtifact(BlackboardArtifact artifact, - boolean checkEnabled) { - List eamArtifacts = new ArrayList<>(); + public static List makeAttrsForArtifact(BlackboardArtifact artifact) { + List correlationAttrs = new ArrayList<>(); try { - BlackboardArtifact artifactForInstance = null; + /* + * If the artifact is an interesting artifact hit, examine the + * interesting artifact, not the hit "meta-artifact." + */ + BlackboardArtifact artToExamine = null; if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) { - // Get the associated artifactForInstance - BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); - if (attribute != null) { - artifactForInstance = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); + BlackboardAttribute assocArtifactAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); + if (assocArtifactAttr != null) { + artToExamine = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong()); } } else { - artifactForInstance = artifact; + artToExamine = artifact; } - if (artifactForInstance != null) { - int artifactTypeID = artifactForInstance.getArtifactTypeID(); + + /* + * + */ + if (artToExamine != null) { + int artifactTypeID = artToExamine.getArtifactTypeID(); if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - BlackboardAttribute setNameAttr = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); - if (setNameAttr != null - && CorrelationAttributeUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); + BlackboardAttribute setNameAttr = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) { + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); } + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { - String value = null; - if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); - } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); - } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); + if (null != artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { + value = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); + } else if (null != artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { + value = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); + } else if (null != artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { + value = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); } // Remove all non-numeric symbols to semi-normalize phone numbers, preserving leading "+" character if (value != null) { @@ -108,44 +114,53 @@ public class CorrelationAttributeUtil { // Only add the correlation attribute if the resulting phone number large enough to be of use // (these 3-5 digit numbers can be valid, but are not useful for correlation) if (value.length() > 5) { - CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artifactForInstance, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); + CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artToExamine, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); if (inst != null) { - eamArtifacts.add(inst); + correlationAttrs.add(inst); } } } + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID); + + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + // RJCTODO: Make a correlation attribute by switching on account type } } } catch (CentralRepoException ex) { logger.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS - return eamArtifacts; + return correlationAttrs; } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS - return null; + return correlationAttrs; } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS - return null; + return correlationAttrs; } - return eamArtifacts; + return correlationAttrs; } /** @@ -166,7 +181,7 @@ public class CorrelationAttributeUtil { * @throws CentralRepoException * @throws TskCoreException */ - private static void addCorrelationAttributeToList(List eamArtifacts, BlackboardArtifact artifact, ATTRIBUTE_TYPE bbAttributeType, int typeId) throws CentralRepoException, TskCoreException { + private static void makeCorrAttrFromArtifactAttr(List eamArtifacts, BlackboardArtifact artifact, ATTRIBUTE_TYPE bbAttributeType, int typeId) throws CentralRepoException, TskCoreException { BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(bbAttributeType)); if (attribute != null) { String value = attribute.getValueString(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index c5f6ebdbe2..2775d5fe4f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -297,7 +297,7 @@ final class CaseEventListener implements PropertyChangeListener { return; } - List convertedArtifacts = CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbArtifact, true); + List convertedArtifacts = CorrelationAttributeUtil.makeAttrsForArtifact(bbArtifact); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { eamArtifact.setComment(comment); try { @@ -370,7 +370,7 @@ final class CaseEventListener implements PropertyChangeListener { if (!hasTagWithConflictingKnownStatus) { //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed //with the initial set of correlation attributes this should be a single correlation attribute - List convertedArtifacts = CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbTag.getArtifact(), true); + List convertedArtifacts = CorrelationAttributeUtil.makeAttrsForArtifact(bbTag.getArtifact()); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 803f20b8c4..7ee644cbec 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2019 Basis Technology Corp. + * Copyright 2017-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -456,7 +456,7 @@ public class IngestEventsListener { for (BlackboardArtifact bbArtifact : bbArtifacts) { // eamArtifact will be null OR a EamArtifact containing one EamArtifactInstance. - List convertedArtifacts = CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbArtifact, true); + List convertedArtifacts = CorrelationAttributeUtil.makeAttrsForArtifact(bbArtifact); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { try { // Only do something with this artifact if it's unique within the job diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 9116ff9b45..9a320f97b7 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -198,7 +198,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data startSection(html, "Central Repository Comments"); List instancesList = new ArrayList<>(); if (artifact != null) { - instancesList.addAll(CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(artifact, false)); + instancesList.addAll(CorrelationAttributeUtil.makeAttrsForArtifact(artifact)); } try { List artifactTypes = CentralRepository.getInstance().getDefinedCorrelationTypes(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index 5f6f6f1c72..93d5694762 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -97,7 +97,7 @@ class GetSCOTask implements Runnable { logger.log(Level.WARNING, "Unable to get correlation type or value to determine value for O column for artifact", ex); } } else { - List listOfPossibleAttributes = CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false); + List listOfPossibleAttributes = CorrelationAttributeUtil.makeAttrsForArtifact(bbArtifact); if (listOfPossibleAttributes.size() > 1) { //Don't display anything if there is more than 1 correlation property for an artifact but let the user know description = Bundle.GetSCOTask_occurrences_multipleProperties(); From b1050b96700190e731dc3eaa23b5bf2503b19a85 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 24 Feb 2020 16:14:16 -0500 Subject: [PATCH 17/24] Skeleton for creating correlation attrs for account artifacts --- .../datamodel/CorrelationAttributeUtil.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 9ac0dddf9e..b241495b64 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -77,16 +77,16 @@ public class CorrelationAttributeUtil { } /* - * + * */ if (artToExamine != null) { - int artifactTypeID = artToExamine.getArtifactTypeID(); + int artifactTypeID = artToExamine.getArtifactTypeID(); if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { BlackboardAttribute setNameAttr = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) { makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); } - + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() @@ -147,7 +147,7 @@ public class CorrelationAttributeUtil { makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - // RJCTODO: Make a correlation attribute by switching on account type + makeAttributeFromAccountArtifact(correlationAttrs, artToExamine); } } } catch (CentralRepoException ex) { @@ -163,6 +163,21 @@ public class CorrelationAttributeUtil { return correlationAttrs; } + /** + * Makes a correlation attribute instance for an account artifact. + * + * IMPORTANT: The correlation attribute instance is NOT added to the central + * repository by this method. + * + * @param acctArtifact An account artifact. + */ + private static CorrelationAttributeInstance makeAttributeFromAccountArtifact(List correlationAttrs, BlackboardArtifact acctArtifact) { + // TODO: Convert TSK_ACCOUNT_TYPE attribute to correlation attribute type + // TODO: Extract TSK_ID as value + // return makeCorrelationAttributeInstanceUsingTypeValue(acctArtifact, null, ""); + return null; + } + /** * Add a CorrelationAttributeInstance of the specified type to the provided * list if the artifactForInstance has an Attribute of the given type with a From 75e55dc7d4e96dd4b329413ba046fb12f05c5e73 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 24 Feb 2020 16:36:05 -0500 Subject: [PATCH 18/24] Skeleton for creating correlation attrs for account artifacts --- .../datamodel/CorrelationAttributeUtil.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index b241495b64..ab1a381720 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -151,13 +151,13 @@ public class CorrelationAttributeUtil { } } } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error getting defined correlation types", ex); // NON-NLS return correlationAttrs; } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error getting querying case database for artifact attribute", ex); // NON-NLS return correlationAttrs; } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS return correlationAttrs; } return correlationAttrs; From b78aa977c2672d9c492d144a22d6c4923ba3fb58 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Tue, 25 Feb 2020 14:46:33 -0500 Subject: [PATCH 19/24] 6014: Create accounts & persona tables - Added an account_id column to X_instances tables. --- .../datamodel/RdbmsCentralRepoFactory.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java index 3ef09b263c..f61fb42062 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java @@ -136,6 +136,10 @@ public class RdbmsCentralRepoFactory { stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + // Create account_types and accounts tab;es which are referred by X_instances tables + stmt.execute(getCreateAccountTypesTableStatement(selectedPlatform)); + stmt.execute(getCreateAccountsTableStatement(selectedPlatform)); + // Create a separate instance and reference table for each artifact type List defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes(); @@ -364,12 +368,14 @@ public class RdbmsCentralRepoFactory { + getNumericPrimaryKeyClause("id", selectedPlatform) + "case_id integer NOT NULL," + "data_source_id integer NOT NULL," + + "account_id " + getBigIntType(selectedPlatform) + " DEFAULT NULL," + "value text NOT NULL," + "file_path text NOT NULL," + "known_status integer NOT NULL," + "comment text," + "file_obj_id " + getBigIntType(selectedPlatform) + " ," + "CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path)" + getOnConflictIgnoreClause(selectedPlatform) + "," + + "foreign key (account_id) references accounts(id)," + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)"; } @@ -569,13 +575,11 @@ public class RdbmsCentralRepoFactory { */ private boolean createPersonaTables(Statement stmt) throws SQLException { - stmt.execute(getCreateAccountTypesTableStatement(selectedPlatform)); stmt.execute(getCreateConfidenceTableStatement(selectedPlatform)); stmt.execute(getCreateExaminersTableStatement(selectedPlatform)); stmt.execute(getCreatePersonaStatusTableStatement(selectedPlatform)); stmt.execute(getCreateAliasesTableStatement(selectedPlatform)); - stmt.execute(getCreateAccountsTableStatement(selectedPlatform)); stmt.execute(getCreatePersonasTableStatement(selectedPlatform)); stmt.execute(getCreatePersonaAliasTableStatement(selectedPlatform)); stmt.execute(getCreatePersonaMetadataTableStatement(selectedPlatform)); From 61cfc91c8708c5e2cab8fb21789a1fb633796daf Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 25 Feb 2020 19:50:43 -0500 Subject: [PATCH 20/24] Partial clean up of CorrelationAttributeUtil.java --- .../AddEditCentralRepoCommentAction.java | 4 +- .../DataContentViewerOtherCases.java | 2 +- .../datamodel/CorrelationAttributeUtil.java | 399 +++++++++++------- .../eventlisteners/CaseEventListener.java | 25 +- .../eventlisteners/IngestEventsListener.java | 2 +- .../AnnotationsContentViewer.java | 2 +- .../datamodel/AbstractAbstractFileNode.java | 2 +- .../datamodel/BlackboardArtifactNode.java | 4 +- .../autopsy/datamodel/GetSCOTask.java | 2 +- 9 files changed, 264 insertions(+), 178 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index dae8bbe312..5427b7b77a 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -61,10 +61,10 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { */ public AddEditCentralRepoCommentAction(AbstractFile file) { fileId = file.getId(); - correlationAttributeInstance = CorrelationAttributeUtil.getInstanceFromContent(file); + correlationAttributeInstance = CorrelationAttributeUtil.getCorrAttrForFile(file); if (correlationAttributeInstance == null) { addToDatabase = true; - correlationAttributeInstance = CorrelationAttributeUtil.makeInstanceFromContent(file); + correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttrFromFile(file); } if (file.getSize() == 0) { putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentEmptyFile()); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 027a4ad7df..881e60236e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -464,7 +464,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // correlate on blackboard artifact attributes if they exist and supported BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node); if (bbArtifact != null && CentralRepository.isEnabled()) { - ret.addAll(CorrelationAttributeUtil.makeAttrsForArtifact(bbArtifact)); + ret.addAll(CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact)); } // we can correlate based on the MD5 if it is enabled diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index ab1a381720..a93354901b 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -30,131 +30,110 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** - * Utility class for correlation attributes in the central repository + * Utility class for working with correlation attributes in the central + * repository. */ public class CorrelationAttributeUtil { private static final Logger logger = Logger.getLogger(CorrelationAttributeUtil.class.getName()); - @Messages({"EamArtifactUtil.emailaddresses.text=Email Addresses"}) - public static String getEmailAddressAttrString() { - return Bundle.EamArtifactUtil_emailaddresses_text(); + /** + * Gets a string that is expected to be the same string that is stored in + * the correlation_types table in the central repository as the display name + * for the email address correlation attribute type. This string is + * duplicated in the CorrelationAttributeInstance class. + * + * TODO (Jira-6088): We should not have multiple deifnitions of this string. + * + * @return The display name of the email address correlation attribute type. + */ + @Messages({"CorrelationAttributeUtil.emailaddresses.text=Email Addresses"}) + private static String getEmailAddressAttrDisplayName() { + return Bundle.CorrelationAttributeUtil_emailaddresses_text(); } /** - * Examines an artifact and makes zero to many correlation attribute - * instances from its attributes. + * Makes zero to many correlation attribute instances from the attributes of + * an artifact. * * IMPORTANT: The correlation attribute instances are NOT added to the * central repository by this method. * + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * * @param artifact An artifact. * * @return A list, possibly empty, of correlation attribute instances for * the artifact. */ - public static List makeAttrsForArtifact(BlackboardArtifact artifact) { + public static List makeCorrAttrsFromArtifact(BlackboardArtifact artifact) { List correlationAttrs = new ArrayList<>(); try { - /* - * If the artifact is an interesting artifact hit, examine the - * interesting artifact, not the hit "meta-artifact." - */ - BlackboardArtifact artToExamine = null; - if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) { - BlackboardAttribute assocArtifactAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); - if (assocArtifactAttr != null) { - artToExamine = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong()); - } - } else { - artToExamine = artifact; - } - - /* - * - */ - if (artToExamine != null) { - int artifactTypeID = artToExamine.getArtifactTypeID(); + BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact); + if (sourceArtifact != null) { + int artifactTypeID = sourceArtifact.getArtifactTypeID(); if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - BlackboardAttribute setNameAttr = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); - if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) { - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); + BlackboardAttribute setNameAttr = sourceArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) { + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); } } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { - String value = null; - if (null != artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { - value = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); - } else if (null != artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { - value = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); - } else if (null != artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { - value = artToExamine.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); - } - // Remove all non-numeric symbols to semi-normalize phone numbers, preserving leading "+" character - if (value != null) { - String newValue = value.replaceAll("\\D", ""); - if (value.startsWith("+")) { - newValue = "+" + newValue; - } - value = newValue; - // Only add the correlation attribute if the resulting phone number large enough to be of use - // (these 3-5 digit numbers can be valid, but are not useful for correlation) - if (value.length() > 5) { - CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artToExamine, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); - if (inst != null) { - correlationAttrs.add(inst); - } - } - } + makeCorrAttrFromArtifactPhoneAttr(sourceArtifact); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, artToExamine, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - makeAttributeFromAccountArtifact(correlationAttrs, artToExamine); + makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact); } } } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error getting defined correlation types", ex); // NON-NLS + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", artifact), ex); // NON-NLS return correlationAttrs; } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting querying case database for artifact attribute", ex); // NON-NLS + logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", artifact), ex); // NON-NLS return correlationAttrs; } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS @@ -163,73 +142,168 @@ public class CorrelationAttributeUtil { return correlationAttrs; } + /** + * Gets the associated artifact of a "meta-artifact" such as an interesting + * artifact hit artifact. + * + * @param artifact An artifact. + * + * @return The associated artifact if the input artifact is a + * "meta-artifact", otherwise the input artifact. + * + * @throws NoCurrentCaseException If there is no open case. + * @throws TskCoreException If there is an error querying thew case + * database. + */ + private static BlackboardArtifact getCorrAttrSourceArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException { + BlackboardArtifact sourceArtifact = null; + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) { + BlackboardAttribute assocArtifactAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); + if (assocArtifactAttr != null) { + sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong()); + } + } else { + sourceArtifact = artifact; + } + return sourceArtifact; + } + + /** + * Make a correlation attribute instance from a phone number attribute of an + * artifact. + * + * @param artifact An artifact with a phone number attribute. + * + * @return The correlation instance artifact or null, if the phone number is + * not a valid correlation attribute. + * + * @throws TskCoreException If there is an error querying the case + * database. + * @throws CentralRepoException If there is an error querying the central + * repository. + */ + private static CorrelationAttributeInstance makeCorrAttrFromArtifactPhoneAttr(BlackboardArtifact artifact) throws TskCoreException, CentralRepoException { + CorrelationAttributeInstance corrAttr = null; + + /* + * Extract the phone number from the artifact attribute. + */ + String value = null; + if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { + value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); + } else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { + value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); + } else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { + value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); + } + + /* + * Normalize the phone number. + */ + if (value != null) { + String newValue = value.replaceAll("\\D", ""); + if (value.startsWith("+")) { + newValue = "+" + newValue; + } + value = newValue; + + /* + * Validate the phone number. Three to five digit phone numbers may + * be valid, but they are too short to use as correlation + * attributes. + */ + if (value.length() > 5) { + corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); + } + } + + return corrAttr; + } + /** * Makes a correlation attribute instance for an account artifact. * * IMPORTANT: The correlation attribute instance is NOT added to the central * repository by this method. * - * @param acctArtifact An account artifact. + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * + * @param corrAttrInstances A list of correlation attribute instances. + * @param acctArtifact An account artifact. + * + * @return The correlation attribute instance. */ - private static CorrelationAttributeInstance makeAttributeFromAccountArtifact(List correlationAttrs, BlackboardArtifact acctArtifact) { - // TODO: Convert TSK_ACCOUNT_TYPE attribute to correlation attribute type - // TODO: Extract TSK_ID as value - // return makeCorrelationAttributeInstanceUsingTypeValue(acctArtifact, null, ""); - return null; + private static void makeCorrAttrFromAcctArtifact(List corrAttrInstances, BlackboardArtifact acctArtifact) { + // RAMAN TODO: Convert TSK_ACCOUNT_TYPE attribute to correlation attribute type + // RAMAN TODO: Extract TSK_ID as value +// CorrelationAttributeInstance corrAttr = makeCorrAttr(acctArtifact, corrType, corrAttrValue); +// if (corrAttr != null) { +// corrAttrInstances.add(corrAttr); +// } } /** - * Add a CorrelationAttributeInstance of the specified type to the provided - * list if the artifactForInstance has an Attribute of the given type with a - * non empty value. + * Makes a correlation attribute instance from a specified attribute of an + * artifact. The correlation attribute instance is added to an input list. * - * @param eamArtifacts the list of CorrelationAttributeInstance objects - * which should be added to - * @param artifact the blackboard artifactForInstance which we are - * creating a CorrelationAttributeInstance for - * @param bbAttributeType the type of BlackboardAttribute we expect to exist - * for a CorrelationAttributeInstance of this type - * generated from this Blackboard Artifact - * @param typeId the integer type id of the - * CorrelationAttributeInstance type + * @param corrAttrInstances A list of correlation attribute instances. + * @param artifact An artifact. + * @param artAttrType The type of the atrribute of the artifact that + * is to be made into a correlatin attribute + * instance. + * @param typeId The type ID for the desired correlation + * attribute instance. * - * @throws CentralRepoException - * @throws TskCoreException + * @throws CentralRepoException If there is an error querying the central + * repository. + * @throws TskCoreException If there is an error querying the case + * database. */ - private static void makeCorrAttrFromArtifactAttr(List eamArtifacts, BlackboardArtifact artifact, ATTRIBUTE_TYPE bbAttributeType, int typeId) throws CentralRepoException, TskCoreException { - BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(bbAttributeType)); + private static void makeCorrAttrFromArtifactAttr(List corrAttrInstances, BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId) throws CentralRepoException, TskCoreException { + BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(artAttrType)); if (attribute != null) { String value = attribute.getValueString(); if ((null != value) && (value.isEmpty() == false)) { - CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artifact, CentralRepository.getInstance().getCorrelationTypeById(typeId), value); + CorrelationAttributeInstance inst = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(typeId), value); if (inst != null) { - eamArtifacts.add(inst); + corrAttrInstances.add(inst); } } } } /** - * Uses the determined type and vallue, then looks up instance details to - * create proper CorrelationAttributeInstance. + * Makes a correlation attribute instance of a given type from an artifact. * - * @param bbArtifact the blackboard artifactForInstance - * @param correlationType the given type - * @param value the artifactForInstance value + * @param artifact The artifact. + * @param correlationType the correlation attribute type. + * @param value The correlation attribute value. * - * @return CorrelationAttributeInstance from details, or null if validation - * failed or another error occurred + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * + * @return The correlation attribute instance or null, if an error occurred. */ - private static CorrelationAttributeInstance makeCorrelationAttributeInstanceUsingTypeValue(BlackboardArtifact bbArtifact, CorrelationAttributeInstance.Type correlationType, String value) { + private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value) { try { Case currentCase = Case.getCurrentCaseThrows(); - AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID()); + AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(artifact.getObjectID()); if (null == bbSourceFile) { logger.log(Level.SEVERE, "Error creating artifact instance. Abstract File was null."); // NON-NLS return null; } - // make an instance for the BB source file CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); return new CorrelationAttributeInstance( correlationType, @@ -242,31 +316,34 @@ public class CorrelationAttributeUtil { bbSourceFile.getId()); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting AbstractFile for artifact: " + bbArtifact.toString(), ex); // NON-NLS + logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", artifact), ex); // NON-NLS return null; } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.WARNING, "Error creating artifact instance for artifact: " + bbArtifact.toString(), ex); // NON-NLS + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", artifact), ex); // NON-NLS return null; } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS return null; } } /** - * Retrieve CorrelationAttribute from the given Content. + * Gets the correlation attribute instance for a file. * - * @param content The content object + * @param file The file. * - * @return The new CorrelationAttribute, or null if retrieval failed. + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * + * @return The correlation attribute instance or null, if no such + * correlation attribute instance was found or an error occurred. */ - public static CorrelationAttributeInstance getInstanceFromContent(Content content) { - - if (!(content instanceof AbstractFile)) { - return null; - } - - final AbstractFile file = (AbstractFile) content; + public static CorrelationAttributeInstance getCorrAttrForFile(AbstractFile file) { if (!isSupportedAbstractFileType(file)) { return null; @@ -284,11 +361,14 @@ public class CorrelationAttributeUtil { return null; } correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource()); - } catch (TskCoreException | CentralRepoException ex) { - logger.log(Level.SEVERE, "Error retrieving correlation attribute.", ex); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", file), ex); // NON-NLS + return null; + } catch (CentralRepoException ex) { + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS return null; } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Case is closed.", ex); + logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS return null; } @@ -296,20 +376,22 @@ public class CorrelationAttributeUtil { try { correlationAttributeInstance = CentralRepository.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, file.getId()); } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.WARNING, String.format( - "Correlation attribute could not be retrieved for '%s' (id=%d): ", - content.getName(), content.getId()), ex); + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS return null; } - //if there was no correlation attribute found for the item using object_id then check for attributes added with schema 1,1 which lack object_id + + /* + * If no correlation attribute instance was found when querying by file + * object ID, try searching by file path instead. This is necessary + * because file object IDs were not stored in the central repository in + * early versions of its schema. + */ if (correlationAttributeInstance == null && file.getMd5Hash() != null) { String filePath = (file.getParentPath() + file.getName()).toLowerCase(); try { correlationAttributeInstance = CentralRepository.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, file.getMd5Hash(), filePath); } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.WARNING, String.format( - "Correlation attribute could not be retrieved for '%s' (id=%d): ", - content.getName(), content.getId()), ex); + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS return null; } } @@ -318,32 +400,31 @@ public class CorrelationAttributeUtil { } /** - * Create an EamArtifact from the given Content. Will return null if an - * artifactForInstance can not be created - this is not necessarily an error - * case, it just means an artifactForInstance can't be made. If creation - * fails due to an error (and not that the file is the wrong type or it has - * no hash), the error will be logged before returning. + * Makes a correlation attribute instance for a file. * - * Does not add the artifactForInstance to the database. + * IMPORTANT: The correlation attribute instance is NOT added to the central + * repository by this method. * - * @param content The content object + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. * - * @return The new EamArtifact or null if creation failed + * @param file The file. + * + * @return The correlation attribute instance or null, if an error occurred. */ - public static CorrelationAttributeInstance makeInstanceFromContent(Content content) { + public static CorrelationAttributeInstance makeCorrAttrFromFile(AbstractFile file) { - if (!(content instanceof AbstractFile)) { + if (!isSupportedAbstractFileType(file)) { return null; } - final AbstractFile af = (AbstractFile) content; - - if (!isSupportedAbstractFileType(af)) { - return null; - } - - // We need a hash to make the artifactForInstance - String md5 = af.getMd5Hash(); + // We need a hash to make the correlation artifact instance. + String md5 = file.getMd5Hash(); if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) { return null; } @@ -354,31 +435,33 @@ public class CorrelationAttributeUtil { CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); return new CorrelationAttributeInstance( filesType, - af.getMd5Hash(), + file.getMd5Hash(), correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, af.getDataSource()), - af.getParentPath() + af.getName(), + CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource()), + file.getParentPath() + file.getName(), "", TskData.FileKnown.UNKNOWN, - af.getId()); + file.getId()); - } catch (TskCoreException | CentralRepoException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.SEVERE, "Error making correlation attribute.", ex); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS + return null; + } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS return null; } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Case is closed.", ex); + logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS return null; } } /** - * Check whether the given abstract file should be processed for the central - * repository. + * Checks whether or not a file is of a type that can be added to the + * central repository as a correlation attribute instance. * - * @param file The file to test + * @param file A file. * - * @return true if the file should be added to the central repo, false - * otherwise + * @return True or false. */ public static boolean isSupportedAbstractFileType(AbstractFile file) { if (file == null) { @@ -405,9 +488,9 @@ public class CorrelationAttributeUtil { } /** - * Constructs a new EamArtifactUtil + * Prevent instantiation of this utility class. */ private CorrelationAttributeUtil() { - //empty constructor } + } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 2775d5fe4f..26c5271d76 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -197,7 +197,7 @@ final class CaseEventListener implements PropertyChangeListener { } } - final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeInstanceFromContent(af); + final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile(af); if (eamArtifact != null) { // send update to Central Repository db @@ -297,7 +297,7 @@ final class CaseEventListener implements PropertyChangeListener { return; } - List convertedArtifacts = CorrelationAttributeUtil.makeAttrsForArtifact(bbArtifact); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { eamArtifact.setComment(comment); try { @@ -370,7 +370,7 @@ final class CaseEventListener implements PropertyChangeListener { if (!hasTagWithConflictingKnownStatus) { //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed //with the initial set of correlation attributes this should be a single correlation attribute - List convertedArtifacts = CorrelationAttributeUtil.makeAttrsForArtifact(bbTag.getArtifact()); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbTag.getArtifact()); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); } @@ -406,9 +406,12 @@ final class CaseEventListener implements PropertyChangeListener { } //if the file will have no tags with a status which would prevent the current status from being changed if (!hasTagWithConflictingKnownStatus) { - final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeInstanceFromContent(contentTag.getContent()); - if (eamArtifact != null) { - CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); + Content taggedContent = contentTag.getContent(); + if (taggedContent instanceof AbstractFile) { + final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile((AbstractFile)taggedContent); + if (eamArtifact != null) { + CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); + } } } } @@ -455,7 +458,7 @@ final class CaseEventListener implements PropertyChangeListener { } } catch (CentralRepoException ex) { LOGGER.log(Level.SEVERE, "Error adding new data source to the central repository", ex); //NON-NLS - } + } } // DATA_SOURCE_ADDED } @@ -495,7 +498,7 @@ final class CaseEventListener implements PropertyChangeListener { } } // CURRENT_CASE } - + private final class DataSourceNameChangedTask implements Runnable { private final CentralRepository dbManager; @@ -508,12 +511,12 @@ final class CaseEventListener implements PropertyChangeListener { @Override public void run() { - + final DataSourceNameChangedEvent dataSourceNameChangedEvent = (DataSourceNameChangedEvent) event; Content dataSource = dataSourceNameChangedEvent.getDataSource(); String newName = (String) event.getNewValue(); - - if (! StringUtils.isEmpty(newName)) { + + if (!StringUtils.isEmpty(newName)) { if (!CentralRepository.isEnabled()) { return; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 7ee644cbec..e79f339c70 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -456,7 +456,7 @@ public class IngestEventsListener { for (BlackboardArtifact bbArtifact : bbArtifacts) { // eamArtifact will be null OR a EamArtifact containing one EamArtifactInstance. - List convertedArtifacts = CorrelationAttributeUtil.makeAttrsForArtifact(bbArtifact); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { try { // Only do something with this artifact if it's unique within the job diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 9a320f97b7..3c967db3fd 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -198,7 +198,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data startSection(html, "Central Repository Comments"); List instancesList = new ArrayList<>(); if (artifact != null) { - instancesList.addAll(CorrelationAttributeUtil.makeAttrsForArtifact(artifact)); + instancesList.addAll(CorrelationAttributeUtil.makeCorrAttrsFromArtifact(artifact)); } try { List artifactTypes = CentralRepository.getInstance().getDefinedCorrelationTypes(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 9bb2f8c358..441c5c6958 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -549,7 +549,7 @@ public abstract class AbstractAbstractFileNode extends A protected CorrelationAttributeInstance getCorrelationAttributeInstance() { CorrelationAttributeInstance attribute = null; if (CentralRepository.isEnabled() && !UserPreferences.getHideSCOColumns()) { - attribute = CorrelationAttributeUtil.getInstanceFromContent(content); + attribute = CorrelationAttributeUtil.getCorrAttrForFile(content); } return attribute; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 7c2b8c92ad..099d91449f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -605,8 +605,8 @@ public class BlackboardArtifactNode extends AbstractContentNode listOfPossibleAttributes = CorrelationAttributeUtil.makeAttrsForArtifact(bbArtifact); + List listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact); if (listOfPossibleAttributes.size() > 1) { //Don't display anything if there is more than 1 correlation property for an artifact but let the user know description = Bundle.GetSCOTask_occurrences_multipleProperties(); From 97a838653178f76167749a88aaac6dc4bdc49880 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 25 Feb 2020 20:04:30 -0500 Subject: [PATCH 21/24] Partial clean up of CorrelationAttributeUtil.java --- .../centralrepository/AddEditCentralRepoCommentAction.java | 2 +- .../centralrepository/datamodel/CorrelationAttributeUtil.java | 2 +- .../centralrepository/eventlisteners/CaseEventListener.java | 3 +-- .../sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java | 2 +- .../sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index 5427b7b77a..5f47487f94 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index a93354901b..814169ef85 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -169,7 +169,7 @@ public class CorrelationAttributeUtil { } /** - * Make a correlation attribute instance from a phone number attribute of an + * Makes a correlation attribute instance from a phone number attribute of an * artifact. * * @param artifact An artifact with a phone number attribute. diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 26c5271d76..1df0e10dc6 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2018 Basis Technology Corp. + * Copyright 2017-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -52,7 +52,6 @@ import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 441c5c6958..a60964aa19 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2012-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 099d91449f..b58bb915d0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2012-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From 0c42694ec9830e7c1819083325d5cbcf66fd709d Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 26 Feb 2020 10:11:56 -0500 Subject: [PATCH 22/24] Added suppress deprecation warning to GeoFilterPanel --- Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index e1c4e0773e..cca9382e51 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -52,6 +52,7 @@ class GeoFilterPanel extends javax.swing.JPanel { private final CheckBoxListPanel checkboxPanel; // Make sure to update if + @SuppressWarnings("deprecation") private static final BlackboardArtifact.ARTIFACT_TYPE[] GPS_ARTIFACT_TYPES = { BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION, From 50789bceac9ef572f739e4c3a6d45a117d5af0a1 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 26 Feb 2020 10:30:29 -0500 Subject: [PATCH 23/24] Updated properties files --- .../sleuthkit/autopsy/geolocation/Bundle.properties-MERGED | 2 ++ .../sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED index 8e7439fb2f..e5bf351edb 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED @@ -30,6 +30,8 @@ GeoTopComponent_no_waypoints_returned_mgs=Applied filter failed to find waypoint GeoTopComponent_no_waypoints_returned_Title=No Waypoints Found GLTopComponent_initilzation_error=An error occurred during waypoint initilization. Geolocation data maybe incomplete. GLTopComponent_name=Geolocation +GLTopComponent_No_dataSource_message=There are no data sources with Geolocation artifacts found. +GLTopComponent_No_dataSource_Title=No Geolocation artifacts found HidingPane_default_title=Filters MapPanel_connection_failure_message=Failed to connect to new geolocation map tile source. MapPanel_connection_failure_message_title=Connection Failure diff --git a/Core/src/org/sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED index 23f2a02775..bf61ad9be0 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED @@ -1,6 +1,6 @@ DATExtractor_process_message=Processing DJI DAT file: %s DATFileExtractor_Extractor_Name=DAT File Extractor -DroneIngestModule_Description=Description -DroneIngestModule_Name=Drone +DroneIngestModule_Description=Analyzes files generated by drones. +DroneIngestModule_Name=Drone Analyzer # {0} - AbstractFileName DroneIngestModule_process_start=Started {0} From 088cfaae6a79d7c9e381877d46cc91ba1a348bce Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Wed, 26 Feb 2020 13:02:23 -0500 Subject: [PATCH 24/24] Addressed review comments and Codacy comments. --- .../datamodel/RdbmsCentralRepo.java | 17 +- .../datamodel/RdbmsCentralRepoFactory.java | 191 +++++++++--------- 2 files changed, 96 insertions(+), 112 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java index fedf0b75c9..abbae1c867 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java @@ -3194,26 +3194,19 @@ abstract class RdbmsCentralRepo implements CentralRepository { // clear out the cache typeCache.invalidateAll(); - - Connection conn = connect(); - PreparedStatement preparedStatement = null; - ResultSet resultSet = null; String sql = "SELECT * FROM correlation_types"; - try { - preparedStatement = conn.prepareStatement(sql); - resultSet = preparedStatement.executeQuery(); + try ( Connection conn = connect(); + PreparedStatement preparedStatement = conn.prepareStatement(sql); + ResultSet resultSet = preparedStatement.executeQuery();) { + while (resultSet.next()) { CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet); typeCache.put(aType.getId(), aType); } } catch (SQLException ex) { throw new CentralRepoException("Error getting correlation types.", ex); // NON-NLS - } finally { - CentralRepoDbUtil.closeStatement(preparedStatement); - CentralRepoDbUtil.closeResultSet(resultSet); - CentralRepoDbUtil.closeConnection(conn); - } + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java index f61fb42062..963809c5d7 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java @@ -81,7 +81,7 @@ public class RdbmsCentralRepoFactory { * connectionPool object directly. */ public boolean initializeDatabaseSchema() { - + String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate(selectedPlatform); String instancesCaseIdIdx = getAddCaseIdIndexTemplate(); @@ -92,95 +92,88 @@ public class RdbmsCentralRepoFactory { // NOTE: the db_info table currenly only has 1 row, so having an index // provides no benefit. - Connection conn = null; - Statement stmt = null; - try { - conn = this.getEphemeralConnection(); + try (Connection conn = this.getEphemeralConnection();) { + if (null == conn) { LOGGER.log(Level.SEVERE, "Cannot initialize CR database, don't have a valid connection."); // NON-NLS return false; } - - stmt = conn.createStatement(); - // these setting PRAGMAs are SQLIte spcific - if (selectedPlatform == CentralRepoPlatforms.SQLITE) { - stmt.execute(PRAGMA_JOURNAL_WAL); - stmt.execute(PRAGMA_SYNC_OFF); - stmt.execute(PRAGMA_READ_UNCOMMITTED_TRUE); - stmt.execute(PRAGMA_ENCODING_UTF8); - stmt.execute(PRAGMA_PAGE_SIZE_4096); - stmt.execute(PRAGMA_FOREIGN_KEYS_ON); - } + try (Statement stmt = conn.createStatement();) { - // Create Organizations table - stmt.execute(getCreateOrganizationsTableStatement(selectedPlatform)); - - // Create Cases table and indexes - stmt.execute(getCreateCasesTableStatement(selectedPlatform)); - stmt.execute(getCasesOrgIdIndexStatement()); - stmt.execute(getCasesCaseUidIndexStatement()); - - stmt.execute(getCreateDataSourcesTableStatement(selectedPlatform)); - stmt.execute(getAddDataSourcesNameIndexStatement()); - stmt.execute(getAddDataSourcesObjectIdIndexStatement()); - - stmt.execute(getCreateReferenceSetsTableStatement(selectedPlatform)); - stmt.execute(getReferenceSetsOrgIdIndexTemplate()); - - stmt.execute(getCreateCorrelationTypesTableStatement(selectedPlatform)); - - stmt.execute(getCreateDbInfoTableStatement(selectedPlatform)); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); - - // Create account_types and accounts tab;es which are referred by X_instances tables - stmt.execute(getCreateAccountTypesTableStatement(selectedPlatform)); - stmt.execute(getCreateAccountsTableStatement(selectedPlatform)); - - // Create a separate instance and reference table for each artifact type - List defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes(); - - String reference_type_dbname; - String instance_type_dbname; - for (CorrelationAttributeInstance.Type type : defaultCorrelationTypes) { - reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); - instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); - - stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname)); - - // FUTURE: allow more than the FILES type - if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { - stmt.execute(String.format(getReferenceTypesTableTemplate(selectedPlatform), reference_type_dbname, reference_type_dbname)); - stmt.execute(String.format(getReferenceTypeValueIndexTemplate(), reference_type_dbname, reference_type_dbname)); - stmt.execute(String.format(getReferenceTypeValueKnownstatusIndexTemplate(), reference_type_dbname, reference_type_dbname)); + // these setting PRAGMAs are SQLIte spcific + if (selectedPlatform == CentralRepoPlatforms.SQLITE) { + stmt.execute(PRAGMA_JOURNAL_WAL); + stmt.execute(PRAGMA_SYNC_OFF); + stmt.execute(PRAGMA_READ_UNCOMMITTED_TRUE); + stmt.execute(PRAGMA_ENCODING_UTF8); + stmt.execute(PRAGMA_PAGE_SIZE_4096); + stmt.execute(PRAGMA_FOREIGN_KEYS_ON); } + + // Create Organizations table + stmt.execute(getCreateOrganizationsTableStatement(selectedPlatform)); + + // Create Cases table and indexes + stmt.execute(getCreateCasesTableStatement(selectedPlatform)); + stmt.execute(getCasesOrgIdIndexStatement()); + stmt.execute(getCasesCaseUidIndexStatement()); + + stmt.execute(getCreateDataSourcesTableStatement(selectedPlatform)); + stmt.execute(getAddDataSourcesNameIndexStatement()); + stmt.execute(getAddDataSourcesObjectIdIndexStatement()); + + stmt.execute(getCreateReferenceSetsTableStatement(selectedPlatform)); + stmt.execute(getReferenceSetsOrgIdIndexTemplate()); + + stmt.execute(getCreateCorrelationTypesTableStatement(selectedPlatform)); + + stmt.execute(getCreateDbInfoTableStatement(selectedPlatform)); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + + // Create account_types and accounts tab;es which are referred by X_instances tables + stmt.execute(getCreateAccountTypesTableStatement(selectedPlatform)); + stmt.execute(getCreateAccountsTableStatement(selectedPlatform)); + + // Create a separate instance and reference table for each artifact type + List defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + + String reference_type_dbname; + String instance_type_dbname; + for (CorrelationAttributeInstance.Type type : defaultCorrelationTypes) { + reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); + instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); + + stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname)); + + // FUTURE: allow more than the FILES type + if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { + stmt.execute(String.format(getReferenceTypesTableTemplate(selectedPlatform), reference_type_dbname, reference_type_dbname)); + stmt.execute(String.format(getReferenceTypeValueIndexTemplate(), reference_type_dbname, reference_type_dbname)); + stmt.execute(String.format(getReferenceTypeValueKnownstatusIndexTemplate(), reference_type_dbname, reference_type_dbname)); + } + } + createPersonaTables(stmt); + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS + return false; + } catch (CentralRepoException ex) { + LOGGER.log(Level.SEVERE, "Error getting default correlation types. Likely due to one or more Type's with an invalid db table name."); // NON-NLS + return false; } - - createPersonaTables(stmt); } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS + LOGGER.log(Level.SEVERE, "Error connecting to database.", ex); // NON-NLS return false; - } catch (CentralRepoException ex) { - LOGGER.log(Level.SEVERE, "Error getting default correlation types. Likely due to one or more Type's with an invalid db table name."); // NON-NLS - return false; - } finally { - if (stmt != null) { - try { - stmt.close(); - } catch (SQLException ex2) { - LOGGER.log(Level.SEVERE, "Error closing statement.", ex2); - } - } - CentralRepoDbUtil.closeConnection(conn); } + return true; } @@ -190,17 +183,22 @@ public class RdbmsCentralRepoFactory { * @return True if success, False otherwise. */ public boolean insertDefaultDatabaseContent() { - Connection conn = this.getEphemeralConnection(); - if (null == conn) { + + boolean result; + try (Connection conn = this.getEphemeralConnection();) { + if (null == conn) { + return false; + } + + result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) + && CentralRepoDbUtil.insertDefaultOrganization(conn) + && insertDefaultPersonaTablesContent(conn); + + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in CR tables."), ex); return false; } - boolean result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) - && CentralRepoDbUtil.insertDefaultOrganization(conn) - && insertDefaultPersonaTablesContent(conn); - - - CentralRepoDbUtil.closeConnection(conn); return result; } @@ -849,24 +847,17 @@ public class RdbmsCentralRepoFactory { } else if (accountType == Account.Type.PHONE) { typeId = CorrelationAttributeInstance.PHONE_TYPE_ID; } else { - ResultSet resultSet = null; - - PreparedStatement preparedStatementQuery = null; String querySql = "SELECT * FROM correlation_types WHERE display_name=?"; - try { - preparedStatementQuery = conn.prepareStatement(querySql); + try ( PreparedStatement preparedStatementQuery = conn.prepareStatement(querySql)) { preparedStatementQuery.setString(1, accountType.getDisplayName()); - - resultSet = preparedStatementQuery.executeQuery(); - if (resultSet.next()) { - typeId = resultSet.getInt("id"); + try (ResultSet resultSet = preparedStatementQuery.executeQuery();) { + if (resultSet.next()) { + typeId = resultSet.getInt("id"); + } } } catch (SQLException ex) { LOGGER.log(Level.SEVERE, String.format("Failed to get correlation typeId for account type %s.", accountType.getTypeName()), ex); - } finally { - CentralRepoDbUtil.closeStatement(preparedStatementQuery); - CentralRepoDbUtil.closeResultSet(resultSet); - } + } } return typeId;