mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into 6896-testing
This commit is contained in:
commit
1866fd461c
@ -232,7 +232,8 @@
|
|||||||
<build-prerequisite/>
|
<build-prerequisite/>
|
||||||
<compile-dependency/>
|
<compile-dependency/>
|
||||||
<run-dependency>
|
<run-dependency>
|
||||||
<specification-version>1.0</specification-version>
|
<release-version>1</release-version>
|
||||||
|
<specification-version>23</specification-version>
|
||||||
</run-dependency>
|
</run-dependency>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -62,6 +62,7 @@ public final class UserPreferences {
|
|||||||
private static final String MESSAGE_SERVICE_HOST = "MessageServiceHost"; //NON-NLS
|
private static final String MESSAGE_SERVICE_HOST = "MessageServiceHost"; //NON-NLS
|
||||||
private static final String MESSAGE_SERVICE_PORT = "MessageServicePort"; //NON-NLS
|
private static final String MESSAGE_SERVICE_PORT = "MessageServicePort"; //NON-NLS
|
||||||
public static final String TEXT_TRANSLATOR_NAME = "TextTranslatorName";
|
public static final String TEXT_TRANSLATOR_NAME = "TextTranslatorName";
|
||||||
|
public static final String OCR_TRANSLATION_ENABLED = "OcrTranslationEnabled";
|
||||||
public static final String PROCESS_TIME_OUT_ENABLED = "ProcessTimeOutEnabled"; //NON-NLS
|
public static final String PROCESS_TIME_OUT_ENABLED = "ProcessTimeOutEnabled"; //NON-NLS
|
||||||
public static final String PROCESS_TIME_OUT_HOURS = "ProcessTimeOutHours"; //NON-NLS
|
public static final String PROCESS_TIME_OUT_HOURS = "ProcessTimeOutHours"; //NON-NLS
|
||||||
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
|
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
|
||||||
@ -348,6 +349,14 @@ public final class UserPreferences {
|
|||||||
return preferences.get(TEXT_TRANSLATOR_NAME, null);
|
return preferences.get(TEXT_TRANSLATOR_NAME, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setUseOcrInTranslation(boolean enableOcr) {
|
||||||
|
preferences.putBoolean(OCR_TRANSLATION_ENABLED, enableOcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getUseOcrInTranslation() {
|
||||||
|
return preferences.getBoolean(OCR_TRANSLATION_ENABLED, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persists message service connection info.
|
* Persists message service connection info.
|
||||||
*
|
*
|
||||||
|
@ -27,6 +27,7 @@ import javax.swing.text.ViewFactory;
|
|||||||
import javax.swing.text.html.HTMLEditorKit;
|
import javax.swing.text.html.HTMLEditorKit;
|
||||||
import javax.swing.text.html.InlineView;
|
import javax.swing.text.html.InlineView;
|
||||||
import javax.swing.text.html.ParagraphView;
|
import javax.swing.text.html.ParagraphView;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JTextPane extension that auto wraps input text using an HTMLEditorKit trick.
|
* JTextPane extension that auto wraps input text using an HTMLEditorKit trick.
|
||||||
@ -98,6 +99,6 @@ public class AutoWrappingJTextPane extends JTextPane {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setText(String text) {
|
public void setText(String text) {
|
||||||
super.setText("<pre>" + text + "</pre>");
|
super.setText("<pre>" + EscapeUtil.escapeHtml(text) + "</pre>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,12 @@ package org.sleuthkit.autopsy.modules.embeddedfileextractor;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.spi.IIORegistry;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -123,6 +128,51 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda
|
|||||||
throw new IngestModuleException(Bundle.EmbeddedFileExtractorIngestModule_UnableToGetMSOfficeExtractor_errMsg(), ex);
|
throw new IngestModuleException(Bundle.EmbeddedFileExtractorIngestModule_UnableToGetMSOfficeExtractor_errMsg(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Java's Image I/O API so that image reading and writing
|
||||||
|
* (needed for image extraction) happens consistently through the
|
||||||
|
* same providers. See JIRA-6951 for more details.
|
||||||
|
*/
|
||||||
|
initializeImageIO();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the ImageIO API and sorts the providers for
|
||||||
|
* deterministic image reading and writing.
|
||||||
|
*/
|
||||||
|
private void initializeImageIO() {
|
||||||
|
ImageIO.scanForPlugins();
|
||||||
|
|
||||||
|
// Sift through each registry category and sort category providers by
|
||||||
|
// their canonical class name.
|
||||||
|
IIORegistry pluginRegistry = IIORegistry.getDefaultInstance();
|
||||||
|
Iterator<Class<?>> categories = pluginRegistry.getCategories();
|
||||||
|
while(categories.hasNext()) {
|
||||||
|
sortPluginsInCategory(pluginRegistry, categories.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts all ImageIO SPI providers by their class name.
|
||||||
|
*/
|
||||||
|
private <T> void sortPluginsInCategory(IIORegistry pluginRegistry, Class<T> category) {
|
||||||
|
Iterator<T> serviceProviderIter = pluginRegistry.getServiceProviders(category, false);
|
||||||
|
ArrayList<T> providers = new ArrayList<>();
|
||||||
|
while (serviceProviderIter.hasNext()) {
|
||||||
|
providers.add(serviceProviderIter.next());
|
||||||
|
}
|
||||||
|
Collections.sort(providers, (first, second) -> {
|
||||||
|
return first.getClass().getCanonicalName().compareToIgnoreCase(second.getClass().getCanonicalName());
|
||||||
|
});
|
||||||
|
for(int i = 0; i < providers.size() - 1; i++) {
|
||||||
|
for(int j = i + 1; j < providers.size(); j++) {
|
||||||
|
// The registry only accepts pairwise orderings. To guarantee a
|
||||||
|
// total order, all pairs need to be exhausted.
|
||||||
|
pluginRegistry.setOrdering(category, providers.get(i),
|
||||||
|
providers.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -123,7 +123,7 @@ final class PDFAttachmentExtractor {
|
|||||||
@Override
|
@Override
|
||||||
public void parseEmbedded(InputStream in, ContentHandler ch, Metadata mtdt, boolean bln) throws SAXException, IOException {
|
public void parseEmbedded(InputStream in, ContentHandler ch, Metadata mtdt, boolean bln) throws SAXException, IOException {
|
||||||
//Resource naming scheme is used internally in autopsy, therefore we can guarentee uniqueness.
|
//Resource naming scheme is used internally in autopsy, therefore we can guarentee uniqueness.
|
||||||
String uniqueExtractedName = parentID + "_attch_" + attachmentCount++; //NON-NLS
|
String uniqueExtractedName = "extract_" + attachmentCount++; //NON-NLS
|
||||||
|
|
||||||
String name = mtdt.get(Metadata.RESOURCE_NAME_KEY);
|
String name = mtdt.get(Metadata.RESOURCE_NAME_KEY);
|
||||||
String ext = FilenameUtils.getExtension(name);
|
String ext = FilenameUtils.getExtension(name);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2019 Basis Technology Corp.
|
* Copyright 2011-2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -46,7 +46,6 @@ import org.apache.tika.Tika;
|
|||||||
import org.apache.tika.exception.TikaException;
|
import org.apache.tika.exception.TikaException;
|
||||||
import org.apache.tika.metadata.Metadata;
|
import org.apache.tika.metadata.Metadata;
|
||||||
import org.apache.tika.parser.AutoDetectParser;
|
import org.apache.tika.parser.AutoDetectParser;
|
||||||
import org.apache.tika.parser.EmptyParser;
|
|
||||||
import org.apache.tika.parser.ParseContext;
|
import org.apache.tika.parser.ParseContext;
|
||||||
import org.apache.tika.parser.Parser;
|
import org.apache.tika.parser.Parser;
|
||||||
import org.apache.tika.parser.ParsingReader;
|
import org.apache.tika.parser.ParsingReader;
|
||||||
@ -72,6 +71,9 @@ import org.xml.sax.ContentHandler;
|
|||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import org.apache.tika.parser.pdf.PDFParserConfig.OCR_STRATEGY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts text from Tika supported content. Protects against Tika parser hangs
|
* Extracts text from Tika supported content. Protects against Tika parser hangs
|
||||||
@ -126,16 +128,6 @@ final class TikaTextExtractor implements TextExtractor {
|
|||||||
"application/x-z", //NON-NLS
|
"application/x-z", //NON-NLS
|
||||||
"application/x-compress"); //NON-NLS
|
"application/x-compress"); //NON-NLS
|
||||||
|
|
||||||
//Tika should ignore types with embedded files that can be handled by the unpacking modules
|
|
||||||
private static final List<String> EMBEDDED_FILE_MIME_TYPES
|
|
||||||
= ImmutableList.of("application/msword", //NON-NLS
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", //NON-NLS
|
|
||||||
"application/vnd.ms-powerpoint", //NON-NLS
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation", //NON-NLS
|
|
||||||
"application/vnd.ms-excel", //NON-NLS
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS
|
|
||||||
"application/pdf"); //NON-NLS
|
|
||||||
|
|
||||||
// Used to log to the tika file that is why it uses the java.util.logging.logger class instead of the Autopsy one
|
// Used to log to the tika file that is why it uses the java.util.logging.logger class instead of the Autopsy one
|
||||||
private static final java.util.logging.Logger TIKA_LOGGER = java.util.logging.Logger.getLogger("Tika"); //NON-NLS
|
private static final java.util.logging.Logger TIKA_LOGGER = java.util.logging.Logger.getLogger("Tika"); //NON-NLS
|
||||||
private static final Logger AUTOPSY_LOGGER = Logger.getLogger(TikaTextExtractor.class.getName());
|
private static final Logger AUTOPSY_LOGGER = Logger.getLogger(TikaTextExtractor.class.getName());
|
||||||
@ -193,52 +185,31 @@ final class TikaTextExtractor implements TextExtractor {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Reader getReader() throws InitReaderException {
|
public Reader getReader() throws InitReaderException {
|
||||||
InputStream stream = null;
|
if (!this.isSupported()) {
|
||||||
|
throw new InitReaderException("Content is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
ParseContext parseContext = new ParseContext();
|
// Only abstract files are supported, see isSupported()
|
||||||
|
final AbstractFile file = ((AbstractFile) content);
|
||||||
|
// This mime type must be non-null, see isSupported()
|
||||||
|
final String mimeType = file.getMIMEType();
|
||||||
|
|
||||||
//Disable appending embedded file text to output for EFE supported types
|
// Handle images seperately so the OCR task can be cancelled.
|
||||||
//JIRA-4975
|
// See JIRA-4519 for the need to have cancellation in the UI and ingest.
|
||||||
if(content instanceof AbstractFile && EMBEDDED_FILE_MIME_TYPES.contains(((AbstractFile)content).getMIMEType())) {
|
if (ocrEnabled() && mimeType.toLowerCase().startsWith("image/")) {
|
||||||
parseContext.set(Parser.class, new EmptyParser());
|
InputStream imageOcrStream = performOCR(file);
|
||||||
} else {
|
return new InputStreamReader(imageOcrStream, Charset.forName("UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up Tika
|
||||||
|
final InputStream stream = new ReadContentInputStream(content);
|
||||||
|
final ParseContext parseContext = new ParseContext();
|
||||||
|
|
||||||
|
// Documents can contain other documents. By adding
|
||||||
|
// the parser back into the context, Tika will recursively
|
||||||
|
// parse embedded documents.
|
||||||
parseContext.set(Parser.class, parser);
|
parseContext.set(Parser.class, parser);
|
||||||
}
|
|
||||||
|
|
||||||
if (ocrEnabled() && content instanceof AbstractFile) {
|
|
||||||
AbstractFile file = ((AbstractFile) content);
|
|
||||||
//Run OCR on images with Tesseract directly.
|
|
||||||
if (file.getMIMEType().toLowerCase().startsWith("image/")) {
|
|
||||||
stream = performOCR(file);
|
|
||||||
} else {
|
|
||||||
//Otherwise, go through Tika for PDFs so that it can
|
|
||||||
//extract images and run Tesseract on them.
|
|
||||||
PDFParserConfig pdfConfig = new PDFParserConfig();
|
|
||||||
|
|
||||||
// Extracting the inline images and letting Tesseract run on each inline image.
|
|
||||||
// https://wiki.apache.org/tika/PDFParser%20%28Apache%20PDFBox%29
|
|
||||||
// https://tika.apache.org/1.7/api/org/apache/tika/parser/pdf/PDFParserConfig.html
|
|
||||||
pdfConfig.setExtractInlineImages(true);
|
|
||||||
// Multiple pages within a PDF file might refer to the same underlying image.
|
|
||||||
pdfConfig.setExtractUniqueInlineImagesOnly(true);
|
|
||||||
parseContext.set(PDFParserConfig.class, pdfConfig);
|
|
||||||
|
|
||||||
// Configure Tesseract parser to perform OCR
|
|
||||||
TesseractOCRConfig ocrConfig = new TesseractOCRConfig();
|
|
||||||
String tesseractFolder = TESSERACT_PATH.getParent();
|
|
||||||
ocrConfig.setTesseractPath(tesseractFolder);
|
|
||||||
|
|
||||||
ocrConfig.setLanguage(languagePacks);
|
|
||||||
ocrConfig.setTessdataPath(PlatformUtil.getOcrLanguagePacksPath());
|
|
||||||
parseContext.set(TesseractOCRConfig.class, ocrConfig);
|
|
||||||
|
|
||||||
stream = new ReadContentInputStream(content);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stream = new ReadContentInputStream(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
Metadata metadata = new Metadata();
|
|
||||||
// Use the more memory efficient Tika SAX parsers for DOCX and
|
// Use the more memory efficient Tika SAX parsers for DOCX and
|
||||||
// PPTX files (it already uses SAX for XLSX).
|
// PPTX files (it already uses SAX for XLSX).
|
||||||
OfficeParserConfig officeParserConfig = new OfficeParserConfig();
|
OfficeParserConfig officeParserConfig = new OfficeParserConfig();
|
||||||
@ -246,6 +217,30 @@ final class TikaTextExtractor implements TextExtractor {
|
|||||||
officeParserConfig.setUseSAXDocxExtractor(true);
|
officeParserConfig.setUseSAXDocxExtractor(true);
|
||||||
parseContext.set(OfficeParserConfig.class, officeParserConfig);
|
parseContext.set(OfficeParserConfig.class, officeParserConfig);
|
||||||
|
|
||||||
|
if (ocrEnabled()) {
|
||||||
|
// Configure OCR for Tika if it chooses to run OCR
|
||||||
|
// during extraction
|
||||||
|
TesseractOCRConfig ocrConfig = new TesseractOCRConfig();
|
||||||
|
String tesseractFolder = TESSERACT_PATH.getParent();
|
||||||
|
ocrConfig.setTesseractPath(tesseractFolder);
|
||||||
|
ocrConfig.setLanguage(languagePacks);
|
||||||
|
ocrConfig.setTessdataPath(PlatformUtil.getOcrLanguagePacksPath());
|
||||||
|
parseContext.set(TesseractOCRConfig.class, ocrConfig);
|
||||||
|
|
||||||
|
// Configure how Tika handles OCRing PDFs
|
||||||
|
PDFParserConfig pdfConfig = new PDFParserConfig();
|
||||||
|
|
||||||
|
// This stategy tries to pick between OCRing a page in the
|
||||||
|
// PDF and doing text extraction. It makes this choice by
|
||||||
|
// first running text extraction and then counting characters.
|
||||||
|
// If there are too few characters or too many unmapped
|
||||||
|
// unicode characters, it'll run the entire page through OCR
|
||||||
|
// and take that output instead. See JIRA-6938
|
||||||
|
pdfConfig.setOcrStrategy(OCR_STRATEGY.AUTO);
|
||||||
|
parseContext.set(PDFParserConfig.class, pdfConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
Metadata metadata = new Metadata();
|
||||||
//Make the creation of a TikaReader a cancellable future in case it takes too long
|
//Make the creation of a TikaReader a cancellable future in case it takes too long
|
||||||
Future<Reader> future = executorService.submit(
|
Future<Reader> future = executorService.submit(
|
||||||
new GetTikaReader(parser, stream, metadata, parseContext));
|
new GetTikaReader(parser, stream, metadata, parseContext));
|
||||||
|
@ -6,3 +6,4 @@ TranslationOptionsPanelController.moduleErr.msg=A module caused an error listeni
|
|||||||
TranslationContentPanel.showLabel.text=Show:
|
TranslationContentPanel.showLabel.text=Show:
|
||||||
TranslationOptionsPanel.translationServiceLabel.text=Text translator:
|
TranslationOptionsPanel.translationServiceLabel.text=Text translator:
|
||||||
TranslationOptionsPanel.translationOptionsDescription.text=Configure a 3rd party text translation service to enable text and file name translation.
|
TranslationOptionsPanel.translationOptionsDescription.text=Configure a 3rd party text translation service to enable text and file name translation.
|
||||||
|
TranslationOptionsPanel.enableOcrCheckBox.text=Enable Optical Character Recognition (OCR) in the translation content viewer
|
||||||
|
@ -10,3 +10,4 @@ TranslationOptionsPanelController.moduleErr.msg=A module caused an error listeni
|
|||||||
TranslationContentPanel.showLabel.text=Show:
|
TranslationContentPanel.showLabel.text=Show:
|
||||||
TranslationOptionsPanel.translationServiceLabel.text=Text translator:
|
TranslationOptionsPanel.translationServiceLabel.text=Text translator:
|
||||||
TranslationOptionsPanel.translationOptionsDescription.text=Configure a 3rd party text translation service to enable text and file name translation.
|
TranslationOptionsPanel.translationOptionsDescription.text=Configure a 3rd party text translation service to enable text and file name translation.
|
||||||
|
TranslationOptionsPanel.enableOcrCheckBox.text=Enable Optical Character Recognition (OCR) in the translation content viewer
|
||||||
|
@ -16,17 +16,23 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="jSeparator1" alignment="0" max="32767" attributes="0"/>
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="translationServicePanel" max="32767" attributes="0"/>
|
<Component id="translationServicePanel" max="32767" attributes="0"/>
|
||||||
|
<Component id="translationOptionsDescription" alignment="0" pref="462" max="32767" attributes="0"/>
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Component id="translationServiceLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="translationServiceLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||||
<Component id="translatorComboBox" min="-2" pref="214" max="-2" attributes="0"/>
|
<Component id="translatorComboBox" min="-2" pref="214" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Component id="enableOcrCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Component id="translationOptionsDescription" alignment="0" pref="462" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -42,9 +48,13 @@
|
|||||||
<Component id="translatorComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Component id="translatorComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="translationServiceLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Component id="translationServiceLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="translationServicePanel" max="32767" attributes="0"/>
|
<Component id="translationServicePanel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
|
<Component id="jSeparator1" min="-2" pref="10" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="enableOcrCheckBox" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
@ -76,5 +86,17 @@
|
|||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.JSeparator" name="jSeparator1">
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JCheckBox" name="enableOcrCheckBox">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/Bundle.properties" key="TranslationOptionsPanel.enableOcrCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="enableOcrCheckBoxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
@ -111,6 +111,7 @@ final class TranslationOptionsPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
translatorComboBox.setSelectedItem(currentSelection);
|
translatorComboBox.setSelectedItem(currentSelection);
|
||||||
loadSelectedPanelSettings();
|
loadSelectedPanelSettings();
|
||||||
|
enableOcrCheckBox.setSelected(UserPreferences.getUseOcrInTranslation());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,6 +129,8 @@ final class TranslationOptionsPanel extends javax.swing.JPanel {
|
|||||||
logger.log(Level.WARNING, "Unable to save settings for TextTranslator named: " + currentSelection, ex);
|
logger.log(Level.WARNING, "Unable to save settings for TextTranslator named: " + currentSelection, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Save whether OCR is enabled in the content viewer
|
||||||
|
UserPreferences.setUseOcrInTranslation(enableOcrCheckBox.isSelected());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,6 +147,8 @@ final class TranslationOptionsPanel extends javax.swing.JPanel {
|
|||||||
translationServiceLabel = new javax.swing.JLabel();
|
translationServiceLabel = new javax.swing.JLabel();
|
||||||
translationServicePanel = new javax.swing.JPanel();
|
translationServicePanel = new javax.swing.JPanel();
|
||||||
translationOptionsDescription = new javax.swing.JLabel();
|
translationOptionsDescription = new javax.swing.JLabel();
|
||||||
|
jSeparator1 = new javax.swing.JSeparator();
|
||||||
|
enableOcrCheckBox = new javax.swing.JCheckBox();
|
||||||
|
|
||||||
translatorComboBox.addActionListener(new java.awt.event.ActionListener() {
|
translatorComboBox.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
@ -157,20 +162,31 @@ final class TranslationOptionsPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(translationOptionsDescription, org.openide.util.NbBundle.getMessage(TranslationOptionsPanel.class, "TranslationOptionsPanel.translationOptionsDescription.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(translationOptionsDescription, org.openide.util.NbBundle.getMessage(TranslationOptionsPanel.class, "TranslationOptionsPanel.translationOptionsDescription.text")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(enableOcrCheckBox, org.openide.util.NbBundle.getMessage(TranslationOptionsPanel.class, "TranslationOptionsPanel.enableOcrCheckBox.text")); // NOI18N
|
||||||
|
enableOcrCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
enableOcrCheckBoxActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(jSeparator1)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(translationServicePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(translationServicePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
|
.addComponent(translationOptionsDescription, javax.swing.GroupLayout.DEFAULT_SIZE, 462, Short.MAX_VALUE)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addComponent(translationServiceLabel)
|
.addComponent(translationServiceLabel)
|
||||||
.addGap(10, 10, 10)
|
.addGap(10, 10, 10)
|
||||||
.addComponent(translatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 214, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(translatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 214, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
.addGap(0, 0, Short.MAX_VALUE))
|
.addComponent(enableOcrCheckBox))
|
||||||
.addComponent(translationOptionsDescription, javax.swing.GroupLayout.PREFERRED_SIZE, 462, Short.MAX_VALUE))
|
.addGap(0, 0, Short.MAX_VALUE)))
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
@ -183,8 +199,12 @@ final class TranslationOptionsPanel extends javax.swing.JPanel {
|
|||||||
.addComponent(translatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(translatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addComponent(translationServiceLabel))
|
.addComponent(translationServiceLabel))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(translationServicePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(translationServicePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addContainerGap())
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
|
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(enableOcrCheckBox)
|
||||||
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
@ -192,8 +212,14 @@ final class TranslationOptionsPanel extends javax.swing.JPanel {
|
|||||||
updatePanel();
|
updatePanel();
|
||||||
}//GEN-LAST:event_translatorComboBoxActionPerformed
|
}//GEN-LAST:event_translatorComboBoxActionPerformed
|
||||||
|
|
||||||
|
private void enableOcrCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_enableOcrCheckBoxActionPerformed
|
||||||
|
controller.changed();
|
||||||
|
}//GEN-LAST:event_enableOcrCheckBoxActionPerformed
|
||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JCheckBox enableOcrCheckBox;
|
||||||
|
private javax.swing.JSeparator jSeparator1;
|
||||||
private javax.swing.JLabel translationOptionsDescription;
|
private javax.swing.JLabel translationOptionsDescription;
|
||||||
private javax.swing.JLabel translationServiceLabel;
|
private javax.swing.JLabel translationServiceLabel;
|
||||||
private javax.swing.JPanel translationServicePanel;
|
private javax.swing.JPanel translationServicePanel;
|
||||||
|
@ -8,6 +8,7 @@ TranslatedContentViewer.errorExtractingText=An error occurred while extracting t
|
|||||||
TranslatedContentViewer.extractingText=Extracting text, please wait...
|
TranslatedContentViewer.extractingText=Extracting text, please wait...
|
||||||
TranslatedContentViewer.fileHasNoText=File has no text.
|
TranslatedContentViewer.fileHasNoText=File has no text.
|
||||||
TranslatedContentViewer.noServiceProvider=The machine translation software was not found.
|
TranslatedContentViewer.noServiceProvider=The machine translation software was not found.
|
||||||
|
TranslatedContentViewer.ocrNotEnabled=OCR is not enabled. To change, go to Tools->Options->Machine Translation
|
||||||
TranslatedContentViewer.translatingText=Translating text, please wait...
|
TranslatedContentViewer.translatingText=Translating text, please wait...
|
||||||
# {0} - exception message
|
# {0} - exception message
|
||||||
TranslatedContentViewer.translationException=An error occurred while translating the text ({0}).
|
TranslatedContentViewer.translationException=An error occurred while translating the text ({0}).
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2019 Basis Technology Corp.
|
* Copyright 2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -38,16 +38,15 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataContentViewerUtility;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator;
|
import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator;
|
||||||
import org.sleuthkit.autopsy.textextractors.TextExtractor;
|
import org.sleuthkit.autopsy.textextractors.TextExtractor;
|
||||||
import org.sleuthkit.autopsy.textextractors.TextExtractorFactory;
|
import org.sleuthkit.autopsy.textextractors.TextExtractorFactory;
|
||||||
import org.sleuthkit.autopsy.textextractors.configs.ImageConfig;
|
import org.sleuthkit.autopsy.textextractors.configs.ImageConfig;
|
||||||
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||||
import org.sleuthkit.autopsy.texttranslation.ui.TranslationContentPanel.DisplayDropdownOptions;
|
import org.sleuthkit.autopsy.texttranslation.ui.TranslationContentPanel.DisplayDropdownOptions;
|
||||||
@ -60,8 +59,6 @@ public final class TranslatedTextViewer implements TextViewer {
|
|||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(TranslatedTextViewer.class.getName());
|
private static final Logger logger = Logger.getLogger(TranslatedTextViewer.class.getName());
|
||||||
|
|
||||||
private static final boolean OCR_ENABLED = true;
|
|
||||||
private static final boolean OCR_DISABLED = false;
|
|
||||||
private static final int MAX_EXTRACT_SIZE_BYTES = 25600;
|
private static final int MAX_EXTRACT_SIZE_BYTES = 25600;
|
||||||
private static final List<String> INSTALLED_LANGUAGE_PACKS = PlatformUtil.getOcrLanguagePacks();
|
private static final List<String> INSTALLED_LANGUAGE_PACKS = PlatformUtil.getOcrLanguagePacks();
|
||||||
private final TranslationContentPanel panel = new TranslationContentPanel();
|
private final TranslationContentPanel panel = new TranslationContentPanel();
|
||||||
@ -81,15 +78,10 @@ public final class TranslatedTextViewer implements TextViewer {
|
|||||||
SelectionChangeListener displayDropDownListener = new DisplayDropDownChangeListener();
|
SelectionChangeListener displayDropDownListener = new DisplayDropDownChangeListener();
|
||||||
panel.addDisplayTextActionListener(displayDropDownListener);
|
panel.addDisplayTextActionListener(displayDropDownListener);
|
||||||
panel.addOcrDropDownActionListener(new OCRDropdownChangeListener());
|
panel.addOcrDropDownActionListener(new OCRDropdownChangeListener());
|
||||||
Content source = DataContentViewerUtility.getDefaultContent(node);
|
if (UserPreferences.getUseOcrInTranslation()) {
|
||||||
|
|
||||||
if (source instanceof AbstractFile) {
|
|
||||||
boolean isImage = ((AbstractFile) source).getMIMEType().toLowerCase().startsWith("image/");
|
|
||||||
if (isImage) {
|
|
||||||
panel.enableOCRSelection(OCR_ENABLED);
|
|
||||||
panel.addLanguagePackNames(INSTALLED_LANGUAGE_PACKS);
|
panel.addLanguagePackNames(INSTALLED_LANGUAGE_PACKS);
|
||||||
}
|
}
|
||||||
}
|
panel.enableOCRSelection(UserPreferences.getUseOcrInTranslation());
|
||||||
|
|
||||||
int payloadMaxInKB = TextTranslationService.getInstance().getMaxTextChars() / 1000;
|
int payloadMaxInKB = TextTranslationService.getInstance().getMaxTextChars() / 1000;
|
||||||
panel.setWarningLabelMsg(String.format(Bundle.TranslatedTextViewer_maxPayloadSize(), payloadMaxInKB));
|
panel.setWarningLabelMsg(String.format(Bundle.TranslatedTextViewer_maxPayloadSize(), payloadMaxInKB));
|
||||||
@ -201,15 +193,17 @@ public final class TranslatedTextViewer implements TextViewer {
|
|||||||
* @throws
|
* @throws
|
||||||
* org.sleuthkit.autopsy.textextractors.TextExtractor.InitReaderException
|
* org.sleuthkit.autopsy.textextractors.TextExtractor.InitReaderException
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"TranslatedContentViewer.ocrNotEnabled=OCR is not enabled. To change, go to Tools->Options->Machine Translation",
|
||||||
|
})
|
||||||
private String getFileText(AbstractFile file) throws IOException, InterruptedException, TextExtractor.InitReaderException {
|
private String getFileText(AbstractFile file) throws IOException, InterruptedException, TextExtractor.InitReaderException {
|
||||||
final boolean isImage = file.getMIMEType().toLowerCase().startsWith("image/"); // NON-NLS
|
final boolean isImage = file.getMIMEType().toLowerCase().startsWith("image/"); // NON-NLS
|
||||||
String result;
|
if (isImage && ! UserPreferences.getUseOcrInTranslation()) {
|
||||||
if (isImage) {
|
return Bundle.TranslatedContentViewer_ocrNotEnabled();
|
||||||
result = extractText(file, OCR_ENABLED);
|
|
||||||
} else {
|
|
||||||
result = extractText(file, OCR_DISABLED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String result = extractText(file, UserPreferences.getUseOcrInTranslation());
|
||||||
|
|
||||||
//Correct for UTF-8
|
//Correct for UTF-8
|
||||||
byte[] resultInUTF8Bytes = result.getBytes("UTF8");
|
byte[] resultInUTF8Bytes = result.getBytes("UTF8");
|
||||||
byte[] trimToArraySize = Arrays.copyOfRange(resultInUTF8Bytes, 0,
|
byte[] trimToArraySize = Arrays.copyOfRange(resultInUTF8Bytes, 0,
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
Netbeans platform does not properly scope classloaders while running qa-functional test code. The result is that NoClassDefError's occur in instances where an external jar (i.e. importing a class from common-io) is referenced in test code and the same external jar is referenced in multiple NBM's. Importing from external jars in qa-functional should be avoided. See jira issue 6954 for more information.
|
@ -25,11 +25,10 @@ import java.nio.file.Paths;
|
|||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
|
|
||||||
import org.netbeans.junit.NbModuleSuite;
|
import org.netbeans.junit.NbModuleSuite;
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.InvalidAccountIDException;
|
import org.sleuthkit.datamodel.InvalidAccountIDException;
|
||||||
|
|
||||||
@ -95,7 +94,8 @@ public class CentralRepoAccountsTest extends TestCase {
|
|||||||
if (CentralRepository.isEnabled()) {
|
if (CentralRepository.isEnabled()) {
|
||||||
CentralRepository.getInstance().shutdownConnections();
|
CentralRepository.getInstance().shutdownConnections();
|
||||||
}
|
}
|
||||||
FileUtils.deleteDirectory(testDirectory.toFile());
|
|
||||||
|
FileUtil.deleteDir(testDirectory.toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPredefinedAccountTypes() {
|
public void testPredefinedAccountTypes() {
|
||||||
|
@ -35,7 +35,6 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.netbeans.junit.NbModuleSuite;
|
import org.netbeans.junit.NbModuleSuite;
|
||||||
import org.openide.util.Exceptions;
|
import org.openide.util.Exceptions;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
@ -47,6 +46,7 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
import static junit.framework.Assert.assertFalse;
|
import static junit.framework.Assert.assertFalse;
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functional tests for the Central Repository data model.
|
* Functional tests for the Central Repository data model.
|
||||||
@ -100,8 +100,8 @@ public class CentralRepoDatamodelTest extends TestCase {
|
|||||||
if (CentralRepository.isEnabled()) {
|
if (CentralRepository.isEnabled()) {
|
||||||
CentralRepository.getInstance().shutdownConnections();
|
CentralRepository.getInstance().shutdownConnections();
|
||||||
}
|
}
|
||||||
FileUtils.deleteDirectory(testDirectory.toFile());
|
FileUtil.deleteDir(testDirectory.toFile());
|
||||||
} catch (IOException | CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
Assert.fail(ex.getMessage());
|
Assert.fail(ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,8 +194,8 @@ public class CentralRepoDatamodelTest extends TestCase {
|
|||||||
if (CentralRepository.isEnabled()) {
|
if (CentralRepository.isEnabled()) {
|
||||||
CentralRepository.getInstance().shutdownConnections();
|
CentralRepository.getInstance().shutdownConnections();
|
||||||
}
|
}
|
||||||
FileUtils.deleteDirectory(testDirectory.toFile());
|
FileUtil.deleteDir(testDirectory.toFile());
|
||||||
} catch (CentralRepoException | IOException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
Exceptions.printStackTrace(ex);
|
||||||
Assert.fail(ex.getMessage());
|
Assert.fail(ex.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,10 @@ import junit.framework.Assert;
|
|||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
|
|
||||||
import org.netbeans.junit.NbModuleSuite;
|
import org.netbeans.junit.NbModuleSuite;
|
||||||
import org.openide.util.Exceptions;
|
import org.openide.util.Exceptions;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.InvalidAccountIDException;
|
import org.sleuthkit.datamodel.InvalidAccountIDException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
@ -257,12 +257,12 @@ public class CentralRepoPersonasTest extends TestCase {
|
|||||||
// This function is run after every test, NOT after the entire collection of
|
// This function is run after every test, NOT after the entire collection of
|
||||||
// tests defined in the class are run.
|
// tests defined in the class are run.
|
||||||
@Override
|
@Override
|
||||||
public void tearDown() throws CentralRepoException, IOException {
|
public void tearDown() throws CentralRepoException {
|
||||||
// Close and delete the test case and central repo db
|
// Close and delete the test case and central repo db
|
||||||
if (CentralRepository.isEnabled()) {
|
if (CentralRepository.isEnabled()) {
|
||||||
CentralRepository.getInstance().shutdownConnections();
|
CentralRepository.getInstance().shutdownConnections();
|
||||||
}
|
}
|
||||||
FileUtils.deleteDirectory(testDirectory.toFile());
|
FileUtil.deleteDir(testDirectory.toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.netbeans.junit.NbTestCase;
|
import org.netbeans.junit.NbTestCase;
|
||||||
import org.openide.util.Exceptions;
|
import org.openide.util.Exceptions;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
@ -63,6 +62,7 @@ import org.sleuthkit.autopsy.modules.vmextractor.VMExtractorIngestModuleFactory;
|
|||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepoFactory;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepoFactory;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||||
import org.sleuthkit.autopsy.modules.pictureanalyzer.PictureAnalyzerIngestModuleFactory;
|
import org.sleuthkit.autopsy.modules.pictureanalyzer.PictureAnalyzerIngestModuleFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -247,8 +247,8 @@ class InterCaseTestUtils {
|
|||||||
if (CentralRepository.isEnabled()) {
|
if (CentralRepository.isEnabled()) {
|
||||||
CentralRepository.getInstance().shutdownConnections();
|
CentralRepository.getInstance().shutdownConnections();
|
||||||
}
|
}
|
||||||
FileUtils.deleteDirectory(CENTRAL_REPO_DIRECTORY_PATH.toFile());
|
FileUtil.deleteDir(CENTRAL_REPO_DIRECTORY_PATH.toFile());
|
||||||
} catch (IOException | CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
Exceptions.printStackTrace(ex);
|
||||||
Assert.fail(ex.getMessage());
|
Assert.fail(ex.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,8 @@
|
|||||||
<build-prerequisite/>
|
<build-prerequisite/>
|
||||||
<compile-dependency/>
|
<compile-dependency/>
|
||||||
<run-dependency>
|
<run-dependency>
|
||||||
<specification-version>1.0</specification-version>
|
<release-version>1</release-version>
|
||||||
|
<specification-version>23</specification-version>
|
||||||
</run-dependency>
|
</run-dependency>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -118,7 +118,8 @@
|
|||||||
<build-prerequisite/>
|
<build-prerequisite/>
|
||||||
<compile-dependency/>
|
<compile-dependency/>
|
||||||
<run-dependency>
|
<run-dependency>
|
||||||
<specification-version>1.0</specification-version>
|
<release-version>1</release-version>
|
||||||
|
<specification-version>23</specification-version>
|
||||||
</run-dependency>
|
</run-dependency>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
Manifest-Version: 1.0
|
Manifest-Version: 1.0
|
||||||
AutoUpdate-Show-In-Client: true
|
AutoUpdate-Show-In-Client: true
|
||||||
OpenIDE-Module: org.sleuthkit.autopsy.Tika
|
OpenIDE-Module: org.sleuthkit.autopsy.Tika/1
|
||||||
|
OpenIDE-Module-Implementation-Version: 1
|
||||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/Tika/Bundle.properties
|
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/Tika/Bundle.properties
|
||||||
OpenIDE-Module-Specification-Version: 1.0
|
OpenIDE-Module-Specification-Version: 23
|
||||||
|
|
||||||
|
3
ZookeeperNodeMigration/.gitignore
vendored
Executable file
3
ZookeeperNodeMigration/.gitignore
vendored
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
/nbproject/private/
|
||||||
|
/build/
|
||||||
|
|
73
ZookeeperNodeMigration/build.xml
Executable file
73
ZookeeperNodeMigration/build.xml
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- You may freely edit this file. See commented blocks below for -->
|
||||||
|
<!-- some examples of how to customize the build. -->
|
||||||
|
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||||
|
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||||
|
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||||
|
<!-- the Compile on Save feature is turned off for the project. -->
|
||||||
|
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||||
|
<!-- in the project's Project Properties dialog box.-->
|
||||||
|
<project name="ZookeeperNodeMigration" default="default" basedir=".">
|
||||||
|
<description>Builds, tests, and runs the project ZookeeperNodeMigration.</description>
|
||||||
|
<import file="nbproject/build-impl.xml"/>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
There exist several targets which are by default empty and which can be
|
||||||
|
used for execution of your tasks. These targets are usually executed
|
||||||
|
before and after some main targets. They are:
|
||||||
|
|
||||||
|
-pre-init: called before initialization of project properties
|
||||||
|
-post-init: called after initialization of project properties
|
||||||
|
-pre-compile: called before javac compilation
|
||||||
|
-post-compile: called after javac compilation
|
||||||
|
-pre-compile-single: called before javac compilation of single file
|
||||||
|
-post-compile-single: called after javac compilation of single file
|
||||||
|
-pre-compile-test: called before javac compilation of JUnit tests
|
||||||
|
-post-compile-test: called after javac compilation of JUnit tests
|
||||||
|
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||||
|
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||||
|
-pre-jar: called before JAR building
|
||||||
|
-post-jar: called after JAR building
|
||||||
|
-post-clean: called after cleaning build products
|
||||||
|
|
||||||
|
(Targets beginning with '-' are not intended to be called on their own.)
|
||||||
|
|
||||||
|
Example of inserting an obfuscator after compilation could look like this:
|
||||||
|
|
||||||
|
<target name="-post-compile">
|
||||||
|
<obfuscate>
|
||||||
|
<fileset dir="${build.classes.dir}"/>
|
||||||
|
</obfuscate>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
For list of available properties check the imported
|
||||||
|
nbproject/build-impl.xml file.
|
||||||
|
|
||||||
|
|
||||||
|
Another way to customize the build is by overriding existing main targets.
|
||||||
|
The targets of interest are:
|
||||||
|
|
||||||
|
-init-macrodef-javac: defines macro for javac compilation
|
||||||
|
-init-macrodef-junit: defines macro for junit execution
|
||||||
|
-init-macrodef-debug: defines macro for class debugging
|
||||||
|
-init-macrodef-java: defines macro for class execution
|
||||||
|
-do-jar: JAR building
|
||||||
|
run: execution of project
|
||||||
|
-javadoc-build: Javadoc generation
|
||||||
|
test-report: JUnit report generation
|
||||||
|
|
||||||
|
An example of overriding the target for project execution could look like this:
|
||||||
|
|
||||||
|
<target name="run" depends="ZookeeperNodeMigration-impl.jar">
|
||||||
|
<exec dir="bin" executable="launcher.exe">
|
||||||
|
<arg file="${dist.jar}"/>
|
||||||
|
</exec>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
Notice that the overridden target depends on the jar target and not only on
|
||||||
|
the compile target as the regular run target does. Again, for a list of available
|
||||||
|
properties which you can use, check the target you are overriding in the
|
||||||
|
nbproject/build-impl.xml file.
|
||||||
|
|
||||||
|
-->
|
||||||
|
</project>
|
32
ZookeeperNodeMigration/dist/README.TXT
vendored
Executable file
32
ZookeeperNodeMigration/dist/README.TXT
vendored
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
========================
|
||||||
|
BUILD OUTPUT DESCRIPTION
|
||||||
|
========================
|
||||||
|
|
||||||
|
When you build an Java application project that has a main class, the IDE
|
||||||
|
automatically copies all of the JAR
|
||||||
|
files on the projects classpath to your projects dist/lib folder. The IDE
|
||||||
|
also adds each of the JAR files to the Class-Path element in the application
|
||||||
|
JAR files manifest file (MANIFEST.MF).
|
||||||
|
|
||||||
|
To run the project from the command line, go to the dist folder and
|
||||||
|
type the following:
|
||||||
|
|
||||||
|
java -jar "ZookeeperNodeMigration.jar"
|
||||||
|
|
||||||
|
To distribute this project, zip up the dist folder (including the lib folder)
|
||||||
|
and distribute the ZIP file.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* If two JAR files on the project classpath have the same name, only the first
|
||||||
|
JAR file is copied to the lib folder.
|
||||||
|
* Only JAR files are copied to the lib folder.
|
||||||
|
If the classpath contains other types of files or folders, these files (folders)
|
||||||
|
are not copied.
|
||||||
|
* If a library on the projects classpath also has a Class-Path element
|
||||||
|
specified in the manifest,the content of the Class-Path element has to be on
|
||||||
|
the projects runtime path.
|
||||||
|
* To set a main class in a standard Java project, right-click the project node
|
||||||
|
in the Projects window and choose Properties. Then click Run and enter the
|
||||||
|
class name in the Main Class field. Alternatively, you can manually type the
|
||||||
|
class name in the manifest Main-Class element.
|
BIN
ZookeeperNodeMigration/dist/ZookeeperNodeMigration.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/ZookeeperNodeMigration.jar
vendored
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/dist/lib/curator-client-2.8.0.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/lib/curator-client-2.8.0.jar
vendored
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/dist/lib/curator-framework-2.8.0.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/lib/curator-framework-2.8.0.jar
vendored
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/dist/lib/curator-recipes-2.8.0.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/lib/curator-recipes-2.8.0.jar
vendored
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/dist/lib/guava-17.0.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/lib/guava-17.0.jar
vendored
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/dist/lib/log4j-1.2.17.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/lib/log4j-1.2.17.jar
vendored
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/dist/lib/slf4j-api-1.7.24.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/lib/slf4j-api-1.7.24.jar
vendored
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/dist/lib/slf4j-log4j12-1.7.6.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/lib/slf4j-log4j12-1.7.6.jar
vendored
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/dist/lib/zookeeper-3.4.6.jar
vendored
Executable file
BIN
ZookeeperNodeMigration/dist/lib/zookeeper-3.4.6.jar
vendored
Executable file
Binary file not shown.
23
ZookeeperNodeMigration/docs/README.TXT
Executable file
23
ZookeeperNodeMigration/docs/README.TXT
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
To run the project from the command line, go to the folder that contains "ZookeeperNodeMigration.jar" and
|
||||||
|
type the following:
|
||||||
|
|
||||||
|
java -jar ZookeeperNodeMigration.jar
|
||||||
|
|
||||||
|
To distribute this project, zip up the dist folder (including the lib folder)
|
||||||
|
and distribute the ZIP file.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
ZookeeperNodeMigration input needs to be:
|
||||||
|
[Input Zookeeper IP Address or Hostname] [Input Zookeeper Port Number] [Output Zookeeper IP Address or Hostname] [Output Zookeeper Port Number]
|
||||||
|
|
||||||
|
For example, if you execute the following command from command line line, the Zookeeper
|
||||||
|
nodes will get copied from Zookeeper server on localhost:9983 to Zookeeper server on localhost:19983 :
|
||||||
|
|
||||||
|
java -jar ZookeeperNodeMigration.jar localhost 9983 localhost 19983
|
||||||
|
|
||||||
|
|
||||||
|
If you do not have Java installed on the machine, you can use the packaged version of Java that is distributed along
|
||||||
|
with Autopsy. For example:
|
||||||
|
|
||||||
|
"C:\Program Files\Autopsy-4.16.0\jre\bin\java.exe" -jar ZookeeperNodeMigration.jar localhost 9983 localhost 19983
|
||||||
|
|
3
ZookeeperNodeMigration/manifest.mf
Executable file
3
ZookeeperNodeMigration/manifest.mf
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
X-COMMENT: Main-Class will be added automatically by build
|
||||||
|
|
1770
ZookeeperNodeMigration/nbproject/build-impl.xml
Executable file
1770
ZookeeperNodeMigration/nbproject/build-impl.xml
Executable file
File diff suppressed because it is too large
Load Diff
107
ZookeeperNodeMigration/nbproject/project.properties
Executable file
107
ZookeeperNodeMigration/nbproject/project.properties
Executable file
@ -0,0 +1,107 @@
|
|||||||
|
annotation.processing.enabled=true
|
||||||
|
annotation.processing.enabled.in.editor=false
|
||||||
|
annotation.processing.processors.list=
|
||||||
|
annotation.processing.run.all.processors=true
|
||||||
|
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
|
||||||
|
application.title=ZookeeperNodeMigration
|
||||||
|
application.vendor=elivis
|
||||||
|
build.classes.dir=${build.dir}/classes
|
||||||
|
build.classes.excludes=**/*.java,**/*.form
|
||||||
|
# This directory is removed when the project is cleaned:
|
||||||
|
build.dir=build
|
||||||
|
build.generated.dir=${build.dir}/generated
|
||||||
|
build.generated.sources.dir=${build.dir}/generated-sources
|
||||||
|
# Only compile against the classpath explicitly listed here:
|
||||||
|
build.sysclasspath=ignore
|
||||||
|
build.test.classes.dir=${build.dir}/test/classes
|
||||||
|
build.test.results.dir=${build.dir}/test/results
|
||||||
|
# Uncomment to specify the preferred debugger connection transport:
|
||||||
|
#debug.transport=dt_socket
|
||||||
|
debug.classpath=\
|
||||||
|
${run.classpath}
|
||||||
|
debug.modulepath=\
|
||||||
|
${run.modulepath}
|
||||||
|
debug.test.classpath=\
|
||||||
|
${run.test.classpath}
|
||||||
|
debug.test.modulepath=\
|
||||||
|
${run.test.modulepath}
|
||||||
|
# Files in build.classes.dir which should be excluded from distribution jar
|
||||||
|
dist.archive.excludes=
|
||||||
|
# This directory is removed when the project is cleaned:
|
||||||
|
dist.dir=dist
|
||||||
|
dist.jar=${dist.dir}/ZookeeperNodeMigration.jar
|
||||||
|
dist.javadoc.dir=${dist.dir}/javadoc
|
||||||
|
endorsed.classpath=
|
||||||
|
excludes=
|
||||||
|
file.reference.curator-client-2.8.0.jar=release/curator-client-2.8.0.jar
|
||||||
|
file.reference.curator-framework-2.8.0.jar=release/curator-framework-2.8.0.jar
|
||||||
|
file.reference.curator-recipes-2.8.0.jar=release/curator-recipes-2.8.0.jar
|
||||||
|
file.reference.guava-17.0.jar=release/guava-17.0.jar
|
||||||
|
file.reference.log4j-1.2.17.jar=release/log4j-1.2.17.jar
|
||||||
|
file.reference.slf4j-api-1.7.24.jar=release/slf4j-api-1.7.24.jar
|
||||||
|
file.reference.slf4j-log4j12-1.7.6.jar=release/slf4j-log4j12-1.7.6.jar
|
||||||
|
file.reference.zookeeper-3.4.6.jar=release/zookeeper-3.4.6.jar
|
||||||
|
includes=**
|
||||||
|
jar.compress=false
|
||||||
|
javac.classpath=\
|
||||||
|
${file.reference.curator-client-2.8.0.jar}:\
|
||||||
|
${file.reference.curator-framework-2.8.0.jar}:\
|
||||||
|
${file.reference.curator-recipes-2.8.0.jar}:\
|
||||||
|
${file.reference.zookeeper-3.4.6.jar}:\
|
||||||
|
${file.reference.slf4j-api-1.7.24.jar}:\
|
||||||
|
${file.reference.slf4j-log4j12-1.7.6.jar}:\
|
||||||
|
${file.reference.log4j-1.2.17.jar}:\
|
||||||
|
${file.reference.guava-17.0.jar}
|
||||||
|
# Space-separated list of extra javac options
|
||||||
|
javac.compilerargs=
|
||||||
|
javac.deprecation=false
|
||||||
|
javac.external.vm=true
|
||||||
|
javac.modulepath=
|
||||||
|
javac.processormodulepath=
|
||||||
|
javac.processorpath=\
|
||||||
|
${javac.classpath}
|
||||||
|
javac.source=1.8
|
||||||
|
javac.target=1.8
|
||||||
|
javac.test.classpath=\
|
||||||
|
${javac.classpath}:\
|
||||||
|
${build.classes.dir}
|
||||||
|
javac.test.modulepath=\
|
||||||
|
${javac.modulepath}
|
||||||
|
javac.test.processorpath=\
|
||||||
|
${javac.test.classpath}
|
||||||
|
javadoc.additionalparam=
|
||||||
|
javadoc.author=false
|
||||||
|
javadoc.encoding=${source.encoding}
|
||||||
|
javadoc.html5=false
|
||||||
|
javadoc.noindex=false
|
||||||
|
javadoc.nonavbar=false
|
||||||
|
javadoc.notree=false
|
||||||
|
javadoc.private=false
|
||||||
|
javadoc.splitindex=true
|
||||||
|
javadoc.use=true
|
||||||
|
javadoc.version=false
|
||||||
|
javadoc.windowtitle=
|
||||||
|
jlink.launcher=false
|
||||||
|
jlink.launcher.name=ZookeeperNodeMigration
|
||||||
|
main.class=zookeepernodemigration.ZookeeperNodeMigration
|
||||||
|
manifest.file=manifest.mf
|
||||||
|
meta.inf.dir=${src.dir}/META-INF
|
||||||
|
mkdist.disabled=false
|
||||||
|
platform.active=default_platform
|
||||||
|
run.classpath=\
|
||||||
|
${javac.classpath}:\
|
||||||
|
${build.classes.dir}
|
||||||
|
# Space-separated list of JVM arguments used when running the project.
|
||||||
|
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
|
||||||
|
# To set system properties for unit tests define test-sys-prop.name=value:
|
||||||
|
run.jvmargs=
|
||||||
|
run.modulepath=\
|
||||||
|
${javac.modulepath}
|
||||||
|
run.test.classpath=\
|
||||||
|
${javac.test.classpath}:\
|
||||||
|
${build.test.classes.dir}
|
||||||
|
run.test.modulepath=\
|
||||||
|
${javac.test.modulepath}
|
||||||
|
source.encoding=UTF-8
|
||||||
|
src.dir=src
|
||||||
|
test.src.dir=test
|
15
ZookeeperNodeMigration/nbproject/project.xml
Executable file
15
ZookeeperNodeMigration/nbproject/project.xml
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||||
|
<type>org.netbeans.modules.java.j2seproject</type>
|
||||||
|
<configuration>
|
||||||
|
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||||
|
<name>ZookeeperNodeMigration</name>
|
||||||
|
<source-roots>
|
||||||
|
<root id="src.dir"/>
|
||||||
|
</source-roots>
|
||||||
|
<test-roots>
|
||||||
|
<root id="test.src.dir"/>
|
||||||
|
</test-roots>
|
||||||
|
</data>
|
||||||
|
</configuration>
|
||||||
|
</project>
|
BIN
ZookeeperNodeMigration/release/curator-client-2.8.0.jar
Executable file
BIN
ZookeeperNodeMigration/release/curator-client-2.8.0.jar
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/release/curator-framework-2.8.0.jar
Executable file
BIN
ZookeeperNodeMigration/release/curator-framework-2.8.0.jar
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/release/curator-recipes-2.8.0.jar
Executable file
BIN
ZookeeperNodeMigration/release/curator-recipes-2.8.0.jar
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/release/guava-17.0.jar
Executable file
BIN
ZookeeperNodeMigration/release/guava-17.0.jar
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/release/log4j-1.2.17.jar
Executable file
BIN
ZookeeperNodeMigration/release/log4j-1.2.17.jar
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/release/slf4j-api-1.7.24.jar
Executable file
BIN
ZookeeperNodeMigration/release/slf4j-api-1.7.24.jar
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/release/slf4j-log4j12-1.7.6.jar
Executable file
BIN
ZookeeperNodeMigration/release/slf4j-log4j12-1.7.6.jar
Executable file
Binary file not shown.
BIN
ZookeeperNodeMigration/release/zookeeper-3.4.6.jar
Executable file
BIN
ZookeeperNodeMigration/release/zookeeper-3.4.6.jar
Executable file
Binary file not shown.
687
ZookeeperNodeMigration/src/zookeepernodemigration/AutoIngestJobNodeData.java
Executable file
687
ZookeeperNodeMigration/src/zookeepernodemigration/AutoIngestJobNodeData.java
Executable file
@ -0,0 +1,687 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2020 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package zookeepernodemigration;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.nio.BufferUnderflowException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.lang.model.type.TypeKind;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that converts auto ingest job data for an auto ingest job
|
||||||
|
* coordination service node to and from byte arrays.
|
||||||
|
*/
|
||||||
|
final class AutoIngestJobNodeData {
|
||||||
|
|
||||||
|
private static final int CURRENT_VERSION = 2;
|
||||||
|
private static final int DEFAULT_PRIORITY = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This number is the sum of each piece of data, based on it's type. For the
|
||||||
|
* types boolean, int, and long, values 1, 4, and 8 will be added
|
||||||
|
* respectively. For String objects, the length of the string, plus either a
|
||||||
|
* byte or short respesenting the length of the string, will be added.
|
||||||
|
*
|
||||||
|
* This field is used to set the size of the buffer during the byte array
|
||||||
|
* creation in the 'toArray()' method. Since the final size of the array
|
||||||
|
* isn't immediately known at the time of creation, this number is used to
|
||||||
|
* create an array as large as could possibly be needed to store all the
|
||||||
|
* data. This avoids the need to continuously enlarge the buffer. Once the
|
||||||
|
* buffer has all the necessary data, it will be resized as appropriate.
|
||||||
|
*/
|
||||||
|
private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131637;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version 0 fields.
|
||||||
|
*/
|
||||||
|
private int processingStatus;
|
||||||
|
private int priority;
|
||||||
|
private int numberOfCrashes;
|
||||||
|
private long completedDate;
|
||||||
|
private boolean errorsOccurred;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version 1 fields.
|
||||||
|
*/
|
||||||
|
private int version;
|
||||||
|
private String manifestFilePath; // 'short' length used in byte array
|
||||||
|
private long manifestFileDate;
|
||||||
|
private String caseName; // 'byte' length used in byte array
|
||||||
|
private String deviceId; // 'byte' length used in byte array
|
||||||
|
private String dataSourcePath; // 'short' length used in byte array
|
||||||
|
private String caseDirectoryPath; // 'short' length used in byte array
|
||||||
|
private String processingHostName; // 'short' length used in byte array
|
||||||
|
private byte processingStage;
|
||||||
|
private long processingStageStartDate;
|
||||||
|
private String processingStageDetailsDescription; // 'byte' length used in byte array
|
||||||
|
private long processingStageDetailsStartDate;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version 2 fields.
|
||||||
|
*/
|
||||||
|
private long dataSourceSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processing statuses for an auto ingest job.
|
||||||
|
*/
|
||||||
|
enum ProcessingStatus {
|
||||||
|
PENDING,
|
||||||
|
PROCESSING,
|
||||||
|
COMPLETED,
|
||||||
|
DELETED
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processing stages for an auto ingest job.
|
||||||
|
*/
|
||||||
|
enum Stage {
|
||||||
|
|
||||||
|
PENDING("Pending"),
|
||||||
|
STARTING("Starting"),
|
||||||
|
UPDATING_SHARED_CONFIG("Updating shared configuration"),
|
||||||
|
CHECKING_SERVICES("Checking services"),
|
||||||
|
OPENING_CASE("Opening case"),
|
||||||
|
IDENTIFYING_DATA_SOURCE("Identifying data source type"),
|
||||||
|
ADDING_DATA_SOURCE("Adding data source"),
|
||||||
|
ANALYZING_DATA_SOURCE("Analyzing data source"),
|
||||||
|
ANALYZING_FILES("Analyzing files"),
|
||||||
|
EXPORTING_FILES("Exporting files"),
|
||||||
|
CANCELLING_MODULE("Cancelling module"),
|
||||||
|
CANCELLING("Cancelling"),
|
||||||
|
COMPLETED("Completed");
|
||||||
|
|
||||||
|
private final String displayText;
|
||||||
|
|
||||||
|
private Stage(String displayText) {
|
||||||
|
this.displayText = displayText;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDisplayText() {
|
||||||
|
return displayText;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processing stage details for an auto ingest job.
|
||||||
|
*/
|
||||||
|
static final class StageDetails implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private final String description;
|
||||||
|
private final Date startDate;
|
||||||
|
|
||||||
|
StageDetails(String description, Date startDate) {
|
||||||
|
this.description = description;
|
||||||
|
this.startDate = startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date getStartDate() {
|
||||||
|
return new Date(this.startDate.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current version of the auto ingest job coordination service node
|
||||||
|
* data.
|
||||||
|
*
|
||||||
|
* @return The version number.
|
||||||
|
*/
|
||||||
|
static int getCurrentVersion() {
|
||||||
|
return AutoIngestJobNodeData.CURRENT_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses a coordination service node data to construct an object that
|
||||||
|
* converts auto ingest job data for an auto ingest job coordination service
|
||||||
|
* node to and from byte arrays.
|
||||||
|
*
|
||||||
|
* @param nodeData The raw bytes received from the coordination service.
|
||||||
|
*/
|
||||||
|
AutoIngestJobNodeData(byte[] nodeData) throws InvalidDataException {
|
||||||
|
if (null == nodeData || nodeData.length == 0) {
|
||||||
|
throw new InvalidDataException(null == nodeData ? "Null nodeData byte array" : "Zero-length nodeData byte array");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set default values for all fields.
|
||||||
|
*/
|
||||||
|
this.processingStatus = ProcessingStatus.PENDING.ordinal();
|
||||||
|
this.priority = DEFAULT_PRIORITY;
|
||||||
|
this.numberOfCrashes = 0;
|
||||||
|
this.completedDate = 0L;
|
||||||
|
this.errorsOccurred = false;
|
||||||
|
this.version = 0;
|
||||||
|
this.manifestFilePath = "";
|
||||||
|
this.manifestFileDate = 0L;
|
||||||
|
this.caseName = "";
|
||||||
|
this.deviceId = "";
|
||||||
|
this.dataSourcePath = "";
|
||||||
|
this.caseDirectoryPath = "";
|
||||||
|
this.processingHostName = "";
|
||||||
|
this.processingStage = (byte) Stage.PENDING.ordinal();
|
||||||
|
this.processingStageStartDate = 0L;
|
||||||
|
this.processingStageDetailsDescription = "";
|
||||||
|
this.processingStageDetailsStartDate = 0L;
|
||||||
|
this.dataSourceSize = 0L;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get fields from node data.
|
||||||
|
*/
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(nodeData);
|
||||||
|
try {
|
||||||
|
if (buffer.hasRemaining()) {
|
||||||
|
/*
|
||||||
|
* Get version 0 fields.
|
||||||
|
*/
|
||||||
|
this.processingStatus = buffer.getInt();
|
||||||
|
this.priority = buffer.getInt();
|
||||||
|
this.numberOfCrashes = buffer.getInt();
|
||||||
|
this.completedDate = buffer.getLong();
|
||||||
|
int errorFlag = buffer.getInt();
|
||||||
|
this.errorsOccurred = (1 == errorFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.hasRemaining()) {
|
||||||
|
/*
|
||||||
|
* Get version 1 fields.
|
||||||
|
*/
|
||||||
|
this.version = buffer.getInt();
|
||||||
|
this.deviceId = getStringFromBuffer(buffer, TypeKind.BYTE);
|
||||||
|
this.caseName = getStringFromBuffer(buffer, TypeKind.BYTE);
|
||||||
|
this.caseDirectoryPath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
||||||
|
this.manifestFileDate = buffer.getLong();
|
||||||
|
this.manifestFilePath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
||||||
|
this.dataSourcePath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
||||||
|
this.processingStage = buffer.get();
|
||||||
|
this.processingStageStartDate = buffer.getLong();
|
||||||
|
this.processingStageDetailsDescription = getStringFromBuffer(buffer, TypeKind.BYTE);
|
||||||
|
this.processingStageDetailsStartDate = buffer.getLong();
|
||||||
|
this.processingHostName = getStringFromBuffer(buffer, TypeKind.SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.hasRemaining()) {
|
||||||
|
/*
|
||||||
|
* Get version 2 fields.
|
||||||
|
*/
|
||||||
|
this.dataSourceSize = buffer.getLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (BufferUnderflowException ex) {
|
||||||
|
throw new InvalidDataException("Node data is incomplete", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the processing status of the job.
|
||||||
|
*
|
||||||
|
* @return The processing status.
|
||||||
|
*/
|
||||||
|
ProcessingStatus getProcessingStatus() {
|
||||||
|
return ProcessingStatus.values()[this.processingStatus];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the processing status of the job.
|
||||||
|
*
|
||||||
|
* @param processingSatus The processing status.
|
||||||
|
*/
|
||||||
|
void setProcessingStatus(ProcessingStatus processingStatus) {
|
||||||
|
this.processingStatus = processingStatus.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the priority of the job.
|
||||||
|
*
|
||||||
|
* @return The priority.
|
||||||
|
*/
|
||||||
|
int getPriority() {
|
||||||
|
return this.priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the priority of the job. A higher number indicates a higheer
|
||||||
|
* priority.
|
||||||
|
*
|
||||||
|
* @param priority The priority.
|
||||||
|
*/
|
||||||
|
void setPriority(int priority) {
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of times the job has crashed during processing.
|
||||||
|
*
|
||||||
|
* @return The number of crashes.
|
||||||
|
*/
|
||||||
|
int getNumberOfCrashes() {
|
||||||
|
return this.numberOfCrashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the number of times the job has crashed during processing.
|
||||||
|
*
|
||||||
|
* @param numberOfCrashes The number of crashes.
|
||||||
|
*/
|
||||||
|
void setNumberOfCrashes(int numberOfCrashes) {
|
||||||
|
this.numberOfCrashes = numberOfCrashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the date the job was completed. A completion date equal to the epoch
|
||||||
|
* (January 1, 1970, 00:00:00 GMT), i.e., Date.getTime() returns 0L,
|
||||||
|
* indicates the job has not been completed.
|
||||||
|
*
|
||||||
|
* @return The job completion date.
|
||||||
|
*/
|
||||||
|
Date getCompletedDate() {
|
||||||
|
return new Date(this.completedDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the date the job was completed. A completion date equal to the epoch
|
||||||
|
* (January 1, 1970, 00:00:00 GMT), i.e., Date.getTime() returns 0L,
|
||||||
|
* indicates the job has not been completed.
|
||||||
|
*
|
||||||
|
* @param completedDate The job completion date.
|
||||||
|
*/
|
||||||
|
void setCompletedDate(Date completedDate) {
|
||||||
|
this.completedDate = completedDate.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether or not any errors occurred during the processing of the job.
|
||||||
|
*
|
||||||
|
* @return True or false.
|
||||||
|
*/
|
||||||
|
boolean getErrorsOccurred() {
|
||||||
|
return this.errorsOccurred;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether or not any errors occurred during the processing of job.
|
||||||
|
*
|
||||||
|
* @param errorsOccurred True or false.
|
||||||
|
*/
|
||||||
|
void setErrorsOccurred(boolean errorsOccurred) {
|
||||||
|
this.errorsOccurred = errorsOccurred;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the node data version number.
|
||||||
|
*
|
||||||
|
* @return The version number.
|
||||||
|
*/
|
||||||
|
int getVersion() {
|
||||||
|
return this.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the device ID of the device associated with the data source for the
|
||||||
|
* job.
|
||||||
|
*
|
||||||
|
* @return The device ID.
|
||||||
|
*/
|
||||||
|
String getDeviceId() {
|
||||||
|
return this.deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the device ID of the device associated with the data source for the
|
||||||
|
* job.
|
||||||
|
*
|
||||||
|
* @param deviceId The device ID.
|
||||||
|
*/
|
||||||
|
void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the case name.
|
||||||
|
*
|
||||||
|
* @return The case name.
|
||||||
|
*/
|
||||||
|
String getCaseName() {
|
||||||
|
return this.caseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the case name.
|
||||||
|
*
|
||||||
|
* @param caseName The case name.
|
||||||
|
*/
|
||||||
|
void setCaseName(String caseName) {
|
||||||
|
this.caseName = caseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the path to the case directory of the case associated with the job.
|
||||||
|
*
|
||||||
|
* @param caseDirectoryPath The path to the case directory.
|
||||||
|
*/
|
||||||
|
synchronized void setCaseDirectoryPath(Path caseDirectoryPath) {
|
||||||
|
if (caseDirectoryPath == null) {
|
||||||
|
this.caseDirectoryPath = "";
|
||||||
|
} else {
|
||||||
|
this.caseDirectoryPath = caseDirectoryPath.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the path to the case directory of the case associated with the job.
|
||||||
|
*
|
||||||
|
* @return The case directory path or an empty string path if the case
|
||||||
|
* directory has not been created yet.
|
||||||
|
*/
|
||||||
|
synchronized Path getCaseDirectoryPath() {
|
||||||
|
if (!caseDirectoryPath.isEmpty()) {
|
||||||
|
return Paths.get(caseDirectoryPath);
|
||||||
|
} else {
|
||||||
|
return Paths.get("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the date the manifest was created.
|
||||||
|
*
|
||||||
|
* @return The date the manifest was created.
|
||||||
|
*/
|
||||||
|
Date getManifestFileDate() {
|
||||||
|
return new Date(this.manifestFileDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the date the manifest was created.
|
||||||
|
*
|
||||||
|
* @param manifestFileDate The date the manifest was created.
|
||||||
|
*/
|
||||||
|
void setManifestFileDate(Date manifestFileDate) {
|
||||||
|
this.manifestFileDate = manifestFileDate.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the manifest file path.
|
||||||
|
*
|
||||||
|
* @return The manifest file path.
|
||||||
|
*/
|
||||||
|
Path getManifestFilePath() {
|
||||||
|
return Paths.get(this.manifestFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the manifest file path.
|
||||||
|
*
|
||||||
|
* @param manifestFilePath The manifest file path.
|
||||||
|
*/
|
||||||
|
void setManifestFilePath(Path manifestFilePath) {
|
||||||
|
if (manifestFilePath != null) {
|
||||||
|
this.manifestFilePath = manifestFilePath.toString();
|
||||||
|
} else {
|
||||||
|
this.manifestFilePath = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the path of the data source for the job.
|
||||||
|
*
|
||||||
|
* @return The data source path.
|
||||||
|
*/
|
||||||
|
Path getDataSourcePath() {
|
||||||
|
return Paths.get(dataSourcePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file name portion of the path of the data source for the job.
|
||||||
|
*
|
||||||
|
* @return The data source file name.
|
||||||
|
*/
|
||||||
|
public String getDataSourceFileName() {
|
||||||
|
return Paths.get(dataSourcePath).getFileName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the path of the data source for the job.
|
||||||
|
*
|
||||||
|
* @param dataSourcePath The data source path.
|
||||||
|
*/
|
||||||
|
void setDataSourcePath(Path dataSourcePath) {
|
||||||
|
if (dataSourcePath != null) {
|
||||||
|
this.dataSourcePath = dataSourcePath.toString();
|
||||||
|
} else {
|
||||||
|
this.dataSourcePath = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the processing stage of the job.
|
||||||
|
*
|
||||||
|
* @return The processing stage.
|
||||||
|
*/
|
||||||
|
Stage getProcessingStage() {
|
||||||
|
return Stage.values()[this.processingStage];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the processing stage job.
|
||||||
|
*
|
||||||
|
* @param processingStage The processing stage.
|
||||||
|
*/
|
||||||
|
void setProcessingStage(Stage processingStage) {
|
||||||
|
this.processingStage = (byte) processingStage.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the processing stage start date.
|
||||||
|
*
|
||||||
|
* @return The processing stage start date.
|
||||||
|
*/
|
||||||
|
Date getProcessingStageStartDate() {
|
||||||
|
return new Date(this.processingStageStartDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the processing stage start date.
|
||||||
|
*
|
||||||
|
* @param processingStageStartDate The processing stage start date.
|
||||||
|
*/
|
||||||
|
void setProcessingStageStartDate(Date processingStageStartDate) {
|
||||||
|
this.processingStageStartDate = processingStageStartDate.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the processing stage details.
|
||||||
|
*
|
||||||
|
* @return A processing stage details object.
|
||||||
|
*/
|
||||||
|
StageDetails getProcessingStageDetails() {
|
||||||
|
return new StageDetails(this.processingStageDetailsDescription, new Date(this.processingStageDetailsStartDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the details of the current processing stage.
|
||||||
|
*
|
||||||
|
* @param stageDetails A stage details object.
|
||||||
|
*/
|
||||||
|
void setProcessingStageDetails(StageDetails stageDetails) {
|
||||||
|
this.processingStageDetailsDescription = stageDetails.getDescription();
|
||||||
|
this.processingStageDetailsStartDate = stageDetails.getStartDate().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the processing host name, may be the empty string.
|
||||||
|
*
|
||||||
|
* @return The processing host. The empty string if the job is not currently
|
||||||
|
* being processed.
|
||||||
|
*/
|
||||||
|
String getProcessingHostName() {
|
||||||
|
return this.processingHostName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the processing host name. May be the empty string.
|
||||||
|
*
|
||||||
|
* @param processingHost The processing host name. The empty string if the
|
||||||
|
* job is not currently being processed.
|
||||||
|
*/
|
||||||
|
void setProcessingHostName(String processingHost) {
|
||||||
|
this.processingHostName = processingHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total size of the data source.
|
||||||
|
*
|
||||||
|
* @return The data source size.
|
||||||
|
*/
|
||||||
|
long getDataSourceSize() {
|
||||||
|
return this.dataSourceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the total size of the data source.
|
||||||
|
*
|
||||||
|
* @param dataSourceSize The data source size.
|
||||||
|
*/
|
||||||
|
void setDataSourceSize(long dataSourceSize) {
|
||||||
|
this.dataSourceSize = dataSourceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the node data as a byte array that can be sent to the coordination
|
||||||
|
* service.
|
||||||
|
*
|
||||||
|
* @return The node data as a byte array.
|
||||||
|
*/
|
||||||
|
byte[] toArray() {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(MAX_POSSIBLE_NODE_DATA_SIZE);
|
||||||
|
|
||||||
|
// Write data (compatible with version 0)
|
||||||
|
buffer.putInt(this.processingStatus);
|
||||||
|
buffer.putInt(this.priority);
|
||||||
|
buffer.putInt(this.numberOfCrashes);
|
||||||
|
buffer.putLong(this.completedDate);
|
||||||
|
buffer.putInt(this.errorsOccurred ? 1 : 0);
|
||||||
|
|
||||||
|
if (this.version >= 1) {
|
||||||
|
// Write version
|
||||||
|
buffer.putInt(this.version);
|
||||||
|
|
||||||
|
// Write data
|
||||||
|
putStringIntoBuffer(deviceId, buffer, TypeKind.BYTE);
|
||||||
|
putStringIntoBuffer(caseName, buffer, TypeKind.BYTE);
|
||||||
|
putStringIntoBuffer(caseDirectoryPath, buffer, TypeKind.SHORT);
|
||||||
|
buffer.putLong(this.manifestFileDate);
|
||||||
|
putStringIntoBuffer(manifestFilePath, buffer, TypeKind.SHORT);
|
||||||
|
putStringIntoBuffer(dataSourcePath, buffer, TypeKind.SHORT);
|
||||||
|
buffer.put(this.processingStage);
|
||||||
|
buffer.putLong(this.processingStageStartDate);
|
||||||
|
putStringIntoBuffer(this.processingStageDetailsDescription, buffer, TypeKind.BYTE);
|
||||||
|
buffer.putLong(this.processingStageDetailsStartDate);
|
||||||
|
putStringIntoBuffer(processingHostName, buffer, TypeKind.SHORT);
|
||||||
|
|
||||||
|
if (this.version >= 2) {
|
||||||
|
buffer.putLong(this.dataSourceSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the array
|
||||||
|
byte[] array = new byte[buffer.position()];
|
||||||
|
buffer.rewind();
|
||||||
|
buffer.get(array, 0, array.length);
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method retrieves a string from a given buffer. Depending on the type
|
||||||
|
* specified, either a 'byte' or a 'short' will first be read out of the
|
||||||
|
* buffer which gives the length of the string so it can be properly parsed.
|
||||||
|
*
|
||||||
|
* @param buffer The buffer from which the string will be read.
|
||||||
|
* @param lengthType The size of the length data.
|
||||||
|
*
|
||||||
|
* @return The string read from the buffer.
|
||||||
|
*/
|
||||||
|
private String getStringFromBuffer(ByteBuffer buffer, TypeKind lengthType) {
|
||||||
|
int length = 0;
|
||||||
|
String output = "";
|
||||||
|
|
||||||
|
switch (lengthType) {
|
||||||
|
case BYTE:
|
||||||
|
length = buffer.get();
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
length = buffer.getShort();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
byte[] array = new byte[length];
|
||||||
|
buffer.get(array, 0, length);
|
||||||
|
output = new String(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method puts a given string into a given buffer. Depending on the
|
||||||
|
* type specified, either a 'byte' or a 'short' will be inserted prior to
|
||||||
|
* the string which gives the length of the string so it can be properly
|
||||||
|
* parsed.
|
||||||
|
*
|
||||||
|
* @param stringValue The string to write to the buffer.
|
||||||
|
* @param buffer The buffer to which the string will be written.
|
||||||
|
* @param lengthType The size of the length data.
|
||||||
|
*/
|
||||||
|
private void putStringIntoBuffer(String stringValue, ByteBuffer buffer, TypeKind lengthType) {
|
||||||
|
switch (lengthType) {
|
||||||
|
case BYTE:
|
||||||
|
buffer.put((byte) stringValue.length());
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
buffer.putShort((short) stringValue.length());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.put(stringValue.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
final static class InvalidDataException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private InvalidDataException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InvalidDataException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
93
ZookeeperNodeMigration/src/zookeepernodemigration/TimeStampUtils.java
Executable file
93
ZookeeperNodeMigration/src/zookeepernodemigration/TimeStampUtils.java
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2020 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package zookeepernodemigration;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods for working with time stamps of the form
|
||||||
|
* 'yyyy_MM_dd_HH_mm_ss'.
|
||||||
|
*/
|
||||||
|
final class TimeStampUtils {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sample time stamp suffix: 2015_02_02_12_10_31
|
||||||
|
*/
|
||||||
|
private static final Pattern TIME_STAMP_PATTERN = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$");
|
||||||
|
private static final int LENGTH_OF_DATE_TIME_STAMP = 20; // length of the above time stamp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a string ends with a time stamp.
|
||||||
|
*
|
||||||
|
* @param inputString The string to check.
|
||||||
|
*
|
||||||
|
* @return True or false.
|
||||||
|
*/
|
||||||
|
static boolean endsWithTimeStamp(String inputString) {
|
||||||
|
Matcher m = TIME_STAMP_PATTERN.matcher(inputString);
|
||||||
|
return m.find();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the fixed length of the time stamp suffix.
|
||||||
|
*
|
||||||
|
* @return The length.
|
||||||
|
*/
|
||||||
|
static int getTimeStampLength() {
|
||||||
|
return LENGTH_OF_DATE_TIME_STAMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the time stamp suffix from a string, if present.
|
||||||
|
*
|
||||||
|
* @param inputString The string to trim.
|
||||||
|
*
|
||||||
|
* @return The trimmed string.
|
||||||
|
*/
|
||||||
|
static String removeTimeStamp(String inputString) {
|
||||||
|
String trimmedString = inputString;
|
||||||
|
if (inputString != null && endsWithTimeStamp(inputString)) {
|
||||||
|
trimmedString = inputString.substring(0, inputString.length() - getTimeStampLength());
|
||||||
|
}
|
||||||
|
return trimmedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the time stamp suffix from a string, if present.
|
||||||
|
*
|
||||||
|
* @param inputString the name to check for a timestamp
|
||||||
|
*
|
||||||
|
* @return The time stamp, may be the empty.
|
||||||
|
*/
|
||||||
|
static String getTimeStampOnly(String inputString) {
|
||||||
|
String timeStamp = "";
|
||||||
|
if (inputString != null && endsWithTimeStamp(inputString)) {
|
||||||
|
timeStamp = inputString.substring(inputString.length() - getTimeStampLength(), inputString.length());
|
||||||
|
}
|
||||||
|
return timeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private contructor to prevent instantiation.
|
||||||
|
*/
|
||||||
|
private TimeStampUtils() {
|
||||||
|
}
|
||||||
|
}
|
464
ZookeeperNodeMigration/src/zookeepernodemigration/ZookeeperNodeMigration.java
Executable file
464
ZookeeperNodeMigration/src/zookeepernodemigration/ZookeeperNodeMigration.java
Executable file
@ -0,0 +1,464 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2020 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package zookeepernodemigration;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.apache.curator.RetryPolicy;
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
|
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
|
||||||
|
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
|
||||||
|
import org.apache.curator.retry.ExponentialBackoffRetry;
|
||||||
|
import org.apache.zookeeper.CreateMode;
|
||||||
|
import org.apache.zookeeper.KeeperException;
|
||||||
|
import org.apache.zookeeper.KeeperException.NoNodeException;
|
||||||
|
import org.apache.zookeeper.WatchedEvent;
|
||||||
|
import org.apache.zookeeper.ZooDefs;
|
||||||
|
import org.apache.zookeeper.ZooKeeper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to migrate Autopsy coordination service data from one ZK database to
|
||||||
|
* another.
|
||||||
|
*/
|
||||||
|
public class ZookeeperNodeMigration {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ZookeeperNodeMigration.class.getName());
|
||||||
|
private static final int SESSION_TIMEOUT_MILLISECONDS = 300000;
|
||||||
|
private static final int CONNECTION_TIMEOUT_MILLISECONDS = 300000;
|
||||||
|
private static final int ZOOKEEPER_SESSION_TIMEOUT_MILLIS = 3000;
|
||||||
|
private static final int ZOOKEEPER_CONNECTION_TIMEOUT_MILLIS = 15000;
|
||||||
|
private static final String DEFAULT_NAMESPACE_ROOT = "autopsy";
|
||||||
|
private static CuratorFramework inputCurator;
|
||||||
|
private static CuratorFramework outputCurator;
|
||||||
|
private static Map<String, String> categoryNodeToPath;
|
||||||
|
|
||||||
|
private ZookeeperNodeMigration(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main method.
|
||||||
|
*
|
||||||
|
* @param args the command line arguments
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
String inputZkIpAddr, inputZkPort, outputZkIpAddr, outputZkPort;
|
||||||
|
|
||||||
|
if (args.length == 4) {
|
||||||
|
inputZkIpAddr = args[0];
|
||||||
|
inputZkPort = args[1];
|
||||||
|
outputZkIpAddr = args[2];
|
||||||
|
outputZkPort = args[3];
|
||||||
|
} else {
|
||||||
|
System.out.println("Input needs to be [Input Zookeeper IP Address] [Input Zookeeper Port Number] [Output Zookeeper IP Address] [Output Zookeeper Port Number]");
|
||||||
|
LOGGER.log(Level.SEVERE, "Input needs to be [Input Zookeeper IP Address] [Input Zookeeper Port Number] [Output Zookeeper IP Address] [Output Zookeeper Port Number]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputZkIpAddr.isEmpty() || inputZkPort.isEmpty() || outputZkIpAddr.isEmpty() || outputZkPort.isEmpty()) {
|
||||||
|
System.out.println("Input needs to be [Input Zookeeper IP Address] [Input Zookeeper Port Number] [Output Zookeeper IP Address] [Output Zookeeper Port Number]");
|
||||||
|
LOGGER.log(Level.SEVERE, "Input needs to be [Input Zookeeper IP Address] [Input Zookeeper Port Number] [Output Zookeeper IP Address] [Output Zookeeper Port Number]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputCurator = initializeCurator(inputZkIpAddr, inputZkPort);
|
||||||
|
if (inputCurator == null) {
|
||||||
|
System.out.println("Unable to initialize Zookeeper or Curator: " + inputZkIpAddr + ":" + inputZkPort);
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to initialize Zookeeper or Curator: {0}:{1}", new Object[]{inputZkIpAddr, inputZkPort});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
categoryNodeToPath = populateCategoryNodes(inputCurator);
|
||||||
|
} catch (KeeperException | CoordinationServiceException ex) {
|
||||||
|
System.out.println("Unable to initialize Curator: " + inputZkIpAddr + ":" + inputZkPort);
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to initialize Curator: {0}:{1}", new Object[]{inputZkIpAddr, inputZkPort});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputCurator = initializeCurator(outputZkIpAddr, outputZkPort);
|
||||||
|
if (outputCurator == null) {
|
||||||
|
System.out.println("Unable to initialize Zookeeper or Curator: " + outputZkIpAddr + ":" + outputZkPort);
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to initialize Zookeeper or Curator: {0}:{1}", new Object[]{outputZkIpAddr, outputZkPort});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// if output ZK database is new, we may have to ceate root "autopsy" node and it's sub-nodes
|
||||||
|
populateCategoryNodes(outputCurator);
|
||||||
|
} catch (KeeperException | CoordinationServiceException ex) {
|
||||||
|
System.out.println("Unable to initialize Curator: " + outputZkIpAddr + ":" + outputZkPort);
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to initialize Curator: {0}:{1}", new Object[]{outputZkIpAddr, outputZkPort});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
copyAllCategoryNodes();
|
||||||
|
|
||||||
|
System.out.println("Done...");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy all Autopsy coordination service nodes from one ZK database to
|
||||||
|
* another.
|
||||||
|
*/
|
||||||
|
private static void copyAllCategoryNodes() {
|
||||||
|
|
||||||
|
for (CategoryNode category : CategoryNode.values()) {
|
||||||
|
List<String> inputNodeList = Collections.EMPTY_LIST;
|
||||||
|
try {
|
||||||
|
inputNodeList = getNodeList(category);
|
||||||
|
} catch (CoordinationServiceException ex) {
|
||||||
|
System.out.println("Unable to get ZK nodes for category: " + category.getDisplayName());
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to get ZK nodes for category: " + category.getDisplayName(), ex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String zkNode : inputNodeList) {
|
||||||
|
try {
|
||||||
|
final byte[] nodeBytes = getNodeData(category, zkNode);
|
||||||
|
try (Lock manifestLock = tryGetExclusiveLock(outputCurator, category, zkNode)) {
|
||||||
|
setNodeData(outputCurator, category, zkNode, nodeBytes);
|
||||||
|
}
|
||||||
|
} catch (CoordinationServiceException | InterruptedException ex) {
|
||||||
|
System.out.println("Unable to write ZK node data for node: " + zkNode);
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to write ZK node data for node: " + zkNode, ex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Curator framework.
|
||||||
|
*
|
||||||
|
* @param zkIpAddr Zookeeper server IP address.
|
||||||
|
* @param zookeeperPort Zookeeper server port number.
|
||||||
|
*
|
||||||
|
* @return CuratorFramework object
|
||||||
|
*/
|
||||||
|
private static CuratorFramework initializeCurator(String zkIpAddr, String zookeeperPort) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!isZooKeeperAccessible(zkIpAddr, zookeeperPort)) {
|
||||||
|
System.out.println("Unable to connect to Zookeeper");
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to connect to Zookeeper");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException | IOException ex) {
|
||||||
|
System.out.println("Unable to connect to Zookeeper");
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to connect to Zookeeper", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connect to ZooKeeper via Curator.
|
||||||
|
*/
|
||||||
|
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
|
||||||
|
String connectString = zkIpAddr + ":" + zookeeperPort;
|
||||||
|
CuratorFramework curator = CuratorFrameworkFactory.newClient(connectString, SESSION_TIMEOUT_MILLISECONDS, CONNECTION_TIMEOUT_MILLISECONDS, retryPolicy);
|
||||||
|
curator.start();
|
||||||
|
return curator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates Autopsy coordination service root ZK nodes.
|
||||||
|
*/
|
||||||
|
private static Map<String, String> populateCategoryNodes(CuratorFramework curator) throws KeeperException, CoordinationServiceException {
|
||||||
|
/*
|
||||||
|
* Create the top-level root and category nodes.
|
||||||
|
*/
|
||||||
|
String rootNodeName = DEFAULT_NAMESPACE_ROOT;
|
||||||
|
String rootNode = rootNodeName;
|
||||||
|
|
||||||
|
if (!rootNode.startsWith("/")) {
|
||||||
|
rootNode = "/" + rootNode;
|
||||||
|
}
|
||||||
|
Map<String, String> categoryPaths = new ConcurrentHashMap<>();
|
||||||
|
for (CategoryNode node : CategoryNode.values()) {
|
||||||
|
String nodePath = rootNode + "/" + node.getDisplayName();
|
||||||
|
try {
|
||||||
|
curator.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE).forPath(nodePath);
|
||||||
|
} catch (KeeperException ex) {
|
||||||
|
if (ex.code() != KeeperException.Code.NODEEXISTS) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new CoordinationServiceException("Curator experienced an error", ex);
|
||||||
|
}
|
||||||
|
categoryPaths.put(node.getDisplayName(), nodePath);
|
||||||
|
}
|
||||||
|
return categoryPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if ZooKeeper is accessible with the current settings. Closes
|
||||||
|
* the connection prior to returning.
|
||||||
|
*
|
||||||
|
* @return true if a connection was achieved, false otherwise
|
||||||
|
*
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private static boolean isZooKeeperAccessible(String solrIpAddr, String zookeeperPort) throws InterruptedException, IOException {
|
||||||
|
boolean result = false;
|
||||||
|
Object workerThreadWaitNotifyLock = new Object();
|
||||||
|
String connectString = solrIpAddr + ":" + zookeeperPort;
|
||||||
|
ZooKeeper zooKeeper = new ZooKeeper(connectString, ZOOKEEPER_SESSION_TIMEOUT_MILLIS,
|
||||||
|
(WatchedEvent event) -> {
|
||||||
|
synchronized (workerThreadWaitNotifyLock) {
|
||||||
|
workerThreadWaitNotifyLock.notifyAll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
synchronized (workerThreadWaitNotifyLock) {
|
||||||
|
workerThreadWaitNotifyLock.wait(ZOOKEEPER_CONNECTION_TIMEOUT_MILLIS);
|
||||||
|
}
|
||||||
|
ZooKeeper.States state = zooKeeper.getState();
|
||||||
|
if (state == ZooKeeper.States.CONNECTED || state == ZooKeeper.States.CONNECTEDREADONLY) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
zooKeeper.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to get an exclusive lock on a node path appended to a category path
|
||||||
|
* in the namespace managed by this coordination service. Returns
|
||||||
|
* immediately if the lock can not be acquired.
|
||||||
|
*
|
||||||
|
* IMPORTANT: The lock needs to be released in the same thread in which it
|
||||||
|
* is acquired.
|
||||||
|
*
|
||||||
|
* @param category The desired category in the namespace.
|
||||||
|
* @param nodePath The node path to use as the basis for the lock.
|
||||||
|
*
|
||||||
|
* @return The lock, or null if the lock could not be obtained.
|
||||||
|
*
|
||||||
|
* @throws CoordinationServiceException If there is an error during lock
|
||||||
|
* acquisition.
|
||||||
|
*/
|
||||||
|
private static Lock tryGetExclusiveLock(CuratorFramework curator, CategoryNode category, String nodePath) throws CoordinationServiceException {
|
||||||
|
String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
|
||||||
|
try {
|
||||||
|
InterProcessReadWriteLock lock = new InterProcessReadWriteLock(curator, fullNodePath);
|
||||||
|
if (!lock.writeLock().acquire(0, TimeUnit.SECONDS)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Lock(nodePath, lock.writeLock());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new CoordinationServiceException(String.format("Failed to get exclusive lock for %s", fullNodePath), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the data associated with the specified node.
|
||||||
|
*
|
||||||
|
* @param category The desired category in the namespace.
|
||||||
|
* @param nodePath The node to retrieve the data for.
|
||||||
|
*
|
||||||
|
* @return The data associated with the node, if any, or null if the node
|
||||||
|
* has not been created yet.
|
||||||
|
*
|
||||||
|
* @throws CoordinationServiceException If there is an error setting the
|
||||||
|
* node data.
|
||||||
|
* @throws InterruptedException If interrupted while blocked during
|
||||||
|
* setting of node data.
|
||||||
|
*/
|
||||||
|
private static byte[] getNodeData(CategoryNode category, String nodePath) throws CoordinationServiceException, InterruptedException {
|
||||||
|
String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
|
||||||
|
try {
|
||||||
|
return inputCurator.getData().forPath(fullNodePath);
|
||||||
|
} catch (NoNodeException ex) {
|
||||||
|
return null;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (ex instanceof InterruptedException) {
|
||||||
|
throw (InterruptedException) ex;
|
||||||
|
} else {
|
||||||
|
throw new CoordinationServiceException(String.format("Failed to get data for %s", fullNodePath), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the given data with the specified node.
|
||||||
|
*
|
||||||
|
* @param category The desired category in the namespace.
|
||||||
|
* @param nodePath The node to associate the data with.
|
||||||
|
* @param data The data to store with the node.
|
||||||
|
*
|
||||||
|
* @throws CoordinationServiceException If there is an error setting the
|
||||||
|
* node data.
|
||||||
|
* @throws InterruptedException If interrupted while blocked during
|
||||||
|
* setting of node data.
|
||||||
|
*/
|
||||||
|
private static void setNodeData(CuratorFramework curator, CategoryNode category, String nodePath, byte[] data) throws CoordinationServiceException, InterruptedException {
|
||||||
|
String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
|
||||||
|
try {
|
||||||
|
curator.setData().forPath(fullNodePath, data);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (ex instanceof InterruptedException) {
|
||||||
|
throw (InterruptedException) ex;
|
||||||
|
} else {
|
||||||
|
throw new CoordinationServiceException(String.format("Failed to set data for %s", fullNodePath), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the specified node.
|
||||||
|
*
|
||||||
|
* @param category The desired category in the namespace.
|
||||||
|
* @param nodePath The node to delete.
|
||||||
|
*
|
||||||
|
* @throws CoordinationServiceException If there is an error setting the
|
||||||
|
* node data.
|
||||||
|
* @throws InterruptedException If interrupted while blocked during
|
||||||
|
* setting of node data.
|
||||||
|
*/
|
||||||
|
private static void deleteNode(CategoryNode category, String nodePath) throws CoordinationServiceException, InterruptedException {
|
||||||
|
String fullNodePath = getFullyQualifiedNodePath(category, nodePath);
|
||||||
|
try {
|
||||||
|
inputCurator.delete().forPath(fullNodePath);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (ex instanceof InterruptedException) {
|
||||||
|
throw (InterruptedException) ex;
|
||||||
|
} else {
|
||||||
|
throw new CoordinationServiceException(String.format("Failed to set data for %s", fullNodePath), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of the child nodes of a category in the namespace.
|
||||||
|
*
|
||||||
|
* @param category The desired category in the namespace.
|
||||||
|
*
|
||||||
|
* @return A list of child node names.
|
||||||
|
*
|
||||||
|
* @throws CoordinationServiceException If there is an error getting the
|
||||||
|
* node list.
|
||||||
|
*/
|
||||||
|
private static List<String> getNodeList(CategoryNode category) throws CoordinationServiceException {
|
||||||
|
try {
|
||||||
|
List<String> list = inputCurator.getChildren().forPath(categoryNodeToPath.get(category.getDisplayName()));
|
||||||
|
return list;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new CoordinationServiceException(String.format("Failed to get node list for %s", category.getDisplayName()), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a node path within a given category.
|
||||||
|
*
|
||||||
|
* @param category A category node.
|
||||||
|
* @param nodePath A node path relative to a category node path.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String getFullyQualifiedNodePath(CategoryNode category, String nodePath) {
|
||||||
|
// nodePath on Unix systems starts with a "/" and ZooKeeper doesn't like two slashes in a row
|
||||||
|
if (nodePath.startsWith("/")) {
|
||||||
|
return categoryNodeToPath.get(category.getDisplayName()) + nodePath.toUpperCase();
|
||||||
|
} else {
|
||||||
|
return categoryNodeToPath.get(category.getDisplayName()) + "/" + nodePath.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception type thrown by the coordination service.
|
||||||
|
*/
|
||||||
|
private final static class CoordinationServiceException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private CoordinationServiceException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CoordinationServiceException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An opaque encapsulation of a lock for use in distributed synchronization.
|
||||||
|
* Instances are obtained by calling a get lock method and must be passed to
|
||||||
|
* a release lock method.
|
||||||
|
*/
|
||||||
|
private static class Lock implements AutoCloseable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation uses the Curator read/write lock. see
|
||||||
|
* http://curator.apache.org/curator-recipes/shared-reentrant-read-write-lock.html
|
||||||
|
*/
|
||||||
|
private final InterProcessMutex interProcessLock;
|
||||||
|
private final String nodePath;
|
||||||
|
|
||||||
|
private Lock(String nodePath, InterProcessMutex lock) {
|
||||||
|
this.nodePath = nodePath;
|
||||||
|
this.interProcessLock = lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodePath() {
|
||||||
|
return nodePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() throws CoordinationServiceException {
|
||||||
|
try {
|
||||||
|
this.interProcessLock.release();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new CoordinationServiceException(String.format("Failed to release the lock on %s", nodePath), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws CoordinationServiceException {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Category nodes are the immediate children of the root node of a shared
|
||||||
|
* hierarchical namespace managed by a coordination service.
|
||||||
|
*/
|
||||||
|
public enum CategoryNode {
|
||||||
|
|
||||||
|
CASES("cases"),
|
||||||
|
MANIFESTS("manifests"),
|
||||||
|
CONFIG("config"),
|
||||||
|
CENTRAL_REPO("centralRepository"),
|
||||||
|
HEALTH_MONITOR("healthMonitor");
|
||||||
|
|
||||||
|
private final String displayName;
|
||||||
|
|
||||||
|
private CategoryNode(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -108,7 +108,6 @@
|
|||||||
<copy file="${basedir}/unix_setup.sh" tofile="${zip-tmp}/${app.name}/unix_setup.sh"/>
|
<copy file="${basedir}/unix_setup.sh" tofile="${zip-tmp}/${app.name}/unix_setup.sh"/>
|
||||||
<copy file="${basedir}/ManifestTool/ManifestTool.exe" todir="${zip-tmp}/${app.name}/bin"/>
|
<copy file="${basedir}/ManifestTool/ManifestTool.exe" todir="${zip-tmp}/${app.name}/bin"/>
|
||||||
|
|
||||||
|
|
||||||
<copy file="${basedir}/icons/icon.ico" tofile="${zip-tmp}/${app.name}/icon.ico" overwrite="true"/>
|
<copy file="${basedir}/icons/icon.ico" tofile="${zip-tmp}/${app.name}/icon.ico" overwrite="true"/>
|
||||||
|
|
||||||
<!-- Copy the Autopsy documentation to the docs folder -->
|
<!-- Copy the Autopsy documentation to the docs folder -->
|
||||||
@ -116,6 +115,14 @@
|
|||||||
<fileset dir="${basedir}/docs/doxygen-user/user-docs"/>
|
<fileset dir="${basedir}/docs/doxygen-user/user-docs"/>
|
||||||
</copy>
|
</copy>
|
||||||
|
|
||||||
|
<!-- Copy the ZooKeeper migration tool, it's JAR files, and documentation -->
|
||||||
|
<copy flatten="false" todir="${zip-tmp}/${app.name}/autopsy/ZookeeperNodeMigration">
|
||||||
|
<fileset dir="${basedir}/ZookeeperNodeMigration/dist"/>
|
||||||
|
</copy>
|
||||||
|
<copy flatten="false" todir="${zip-tmp}/${app.name}/autopsy/ZookeeperNodeMigration" overwrite="true">
|
||||||
|
<fileset dir="${basedir}/ZookeeperNodeMigration/docs"/>
|
||||||
|
</copy>
|
||||||
|
|
||||||
<property name="app.property.file" value="${zip-tmp}/${app.name}/etc/${app.name}.conf" />
|
<property name="app.property.file" value="${zip-tmp}/${app.name}/etc/${app.name}.conf" />
|
||||||
<var name="jvm-value" value="--branding ${app.name} -J-Xms24m -J-Xmx4G -J-Xverify:none -J-XX:+UseG1GC -J-XX:+UseStringDeduplication"/>
|
<var name="jvm-value" value="--branding ${app.name} -J-Xms24m -J-Xmx4G -J-Xverify:none -J-XX:+UseG1GC -J-XX:+UseStringDeduplication"/>
|
||||||
<!-- for Japanese localized version add option: -Duser.language=ja -->
|
<!-- for Japanese localized version add option: -Duser.language=ja -->
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 60 KiB |
BIN
docs/doxygen-user/images/mt_ocr_image.png
Normal file
BIN
docs/doxygen-user/images/mt_ocr_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
BIN
docs/doxygen-user/images/mt_ocr_result.png
Normal file
BIN
docs/doxygen-user/images/mt_ocr_result.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -57,6 +57,7 @@ The "Indexed Text" tab shows the results when running the keyword search module
|
|||||||
|
|
||||||
\image html keyword-search-ocr-indexed-text.png
|
\image html keyword-search-ocr-indexed-text.png
|
||||||
|
|
||||||
|
\anchor keyword_search_ocr_config
|
||||||
By default, OCR is only configured for English text. Its configuration depends on the presence of language files (called "traineddata" files)
|
By default, OCR is only configured for English text. Its configuration depends on the presence of language files (called "traineddata" files)
|
||||||
that exist in a location that Autopsy can understand. To add support for more languages, you will need to download additional "traineddata"
|
that exist in a location that Autopsy can understand. To add support for more languages, you will need to download additional "traineddata"
|
||||||
and move them to the right location. The following steps breakdown this process for you:
|
and move them to the right location. The following steps breakdown this process for you:
|
||||||
|
@ -17,6 +17,8 @@ To set up a machine translation service, go to Options->Tools and then select th
|
|||||||
|
|
||||||
Each service will require slightly different configuration steps. After setting everything up, you can run a quick check that the service is set up correctly using the "Test" button.
|
Each service will require slightly different configuration steps. After setting everything up, you can run a quick check that the service is set up correctly using the "Test" button.
|
||||||
|
|
||||||
|
The checkbox at the bottom allows you to enable or disable optical character recognition (OCR). When enabled, if you select an image in the \ref mt_content_viewer "content viewer" Autopsy will use OCR to attempt to extract text to be translated. Instructions for installing OCR packages for different languages can be found on the \ref keyword_search_ocr_config "Keyword Search page".
|
||||||
|
|
||||||
\section mt_file_names Translating File Names
|
\section mt_file_names Translating File Names
|
||||||
|
|
||||||
You can use machine translation to automatically translate file and folder names, such as the ones seen below:
|
You can use machine translation to automatically translate file and folder names, such as the ones seen below:
|
||||||
@ -49,4 +51,12 @@ Then use the drop-down menu on the right to change from "Original Text" to "Tran
|
|||||||
|
|
||||||
\image html mt_message_translated.png
|
\image html mt_message_translated.png
|
||||||
|
|
||||||
|
If you've enabled OCR as described in the \ref mt_config section above, you can extract and translate text from images. Here is an image containing the beginning of a French poem:
|
||||||
|
|
||||||
|
\image html mt_ocr_image.png
|
||||||
|
|
||||||
|
If you go to the Text tab and then the Translation viewer it will use OCR to read text from the image and then display the translation.
|
||||||
|
|
||||||
|
\image html mt_ocr_result.png
|
||||||
|
|
||||||
*/
|
*/
|
@ -44,7 +44,8 @@
|
|||||||
<build-prerequisite/>
|
<build-prerequisite/>
|
||||||
<compile-dependency/>
|
<compile-dependency/>
|
||||||
<run-dependency>
|
<run-dependency>
|
||||||
<specification-version>1.0</specification-version>
|
<release-version>1</release-version>
|
||||||
|
<specification-version>23</specification-version>
|
||||||
</run-dependency>
|
</run-dependency>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -139,6 +139,10 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
boolean isPstFile = PstParser.isPstFile(abstractFile);
|
boolean isPstFile = PstParser.isPstFile(abstractFile);
|
||||||
boolean isVcardFile = VcardParser.isVcardFile(abstractFile);
|
boolean isVcardFile = VcardParser.isVcardFile(abstractFile);
|
||||||
|
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return ProcessResult.OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (isMbox || isEMLFile || isPstFile || isVcardFile ) {
|
if (isMbox || isEMLFile || isPstFile || isVcardFile ) {
|
||||||
try {
|
try {
|
||||||
communicationArtifactsHelper = new CommunicationArtifactsHelper(currentCase.getSleuthkitCase(),
|
communicationArtifactsHelper = new CommunicationArtifactsHelper(currentCase.getSleuthkitCase(),
|
||||||
@ -213,6 +217,9 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
Iterator<EmailMessage> pstMsgIterator = parser.getEmailMessageIterator();
|
Iterator<EmailMessage> pstMsgIterator = parser.getEmailMessageIterator();
|
||||||
if (pstMsgIterator != null) {
|
if (pstMsgIterator != null) {
|
||||||
processEmails(parser.getPartialEmailMessages(), pstMsgIterator , abstractFile);
|
processEmails(parser.getPartialEmailMessages(), pstMsgIterator , abstractFile);
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return ProcessResult.OK;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// sometimes parser returns ParseResult=OK but there are no messages
|
// sometimes parser returns ParseResult=OK but there are no messages
|
||||||
postErrorMessage(
|
postErrorMessage(
|
||||||
@ -321,6 +328,9 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
processMboxFile(file, abstractFile, emailFolder);
|
processMboxFile(file, abstractFile, emailFolder);
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return ProcessResult.OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (file.delete() == false) {
|
if (file.delete() == false) {
|
||||||
logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
|
logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
|
||||||
@ -349,7 +359,9 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
if (splitFile.delete() == false) {
|
if (splitFile.delete() == false) {
|
||||||
logger.log(Level.INFO, "Failed to delete temp file: {0}", splitFile); //NON-NLS
|
logger.log(Level.INFO, "Failed to delete temp file: {0}", splitFile); //NON-NLS
|
||||||
}
|
}
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return ProcessResult.OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,6 +397,9 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
List<EmailMessage> emails = new ArrayList<>();
|
List<EmailMessage> emails = new ArrayList<>();
|
||||||
if(emailIterator != null) {
|
if(emailIterator != null) {
|
||||||
while(emailIterator.hasNext()) {
|
while(emailIterator.hasNext()) {
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
EmailMessage emailMessage = emailIterator.next();
|
EmailMessage emailMessage = emailIterator.next();
|
||||||
if(emailMessage != null) {
|
if(emailMessage != null) {
|
||||||
emails.add(emailMessage);
|
emails.add(emailMessage);
|
||||||
@ -526,6 +541,10 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
|
|
||||||
int msgCnt = 0;
|
int msgCnt = 0;
|
||||||
while(fullMessageIterator.hasNext()) {
|
while(fullMessageIterator.hasNext()) {
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EmailMessage current = fullMessageIterator.next();
|
EmailMessage current = fullMessageIterator.next();
|
||||||
|
|
||||||
if(current == null) {
|
if(current == null) {
|
||||||
@ -550,6 +569,9 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
|
|
||||||
if (derivedFiles.isEmpty() == false) {
|
if (derivedFiles.isEmpty() == false) {
|
||||||
for (AbstractFile derived : derivedFiles) {
|
for (AbstractFile derived : derivedFiles) {
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
services.fireModuleContentEvent(new ModuleContentEvent(derived));
|
services.fireModuleContentEvent(new ModuleContentEvent(derived));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -675,6 +697,10 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
String senderAddress;
|
String senderAddress;
|
||||||
senderAddressList.addAll(findEmailAddresess(from));
|
senderAddressList.addAll(findEmailAddresess(from));
|
||||||
|
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
AccountFileInstance senderAccountInstance = null;
|
AccountFileInstance senderAccountInstance = null;
|
||||||
|
|
||||||
if (senderAddressList.size() == 1) {
|
if (senderAddressList.size() == 1) {
|
||||||
@ -690,13 +716,20 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
logger.log(Level.WARNING, "Failed to find sender address, from = {0}", from); //NON-NLS
|
logger.log(Level.WARNING, "Failed to find sender address, from = {0}", from); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
List<String> recipientAddresses = new ArrayList<>();
|
List<String> recipientAddresses = new ArrayList<>();
|
||||||
recipientAddresses.addAll(findEmailAddresess(to));
|
recipientAddresses.addAll(findEmailAddresess(to));
|
||||||
recipientAddresses.addAll(findEmailAddresess(cc));
|
recipientAddresses.addAll(findEmailAddresess(cc));
|
||||||
recipientAddresses.addAll(findEmailAddresess(bcc));
|
recipientAddresses.addAll(findEmailAddresess(bcc));
|
||||||
|
|
||||||
List<AccountFileInstance> recipientAccountInstances = new ArrayList<>();
|
List<AccountFileInstance> recipientAccountInstances = new ArrayList<>();
|
||||||
recipientAddresses.forEach((addr) -> {
|
for (String addr : recipientAddresses) {
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
AccountFileInstance recipientAccountInstance =
|
AccountFileInstance recipientAccountInstance =
|
||||||
currentCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
|
currentCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
|
||||||
@ -706,7 +739,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
catch(TskCoreException ex) {
|
catch(TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, "Failed to create account for email address " + addr, ex); //NON-NLS
|
logger.log(Level.WARNING, "Failed to create account for email address " + addr, ex); //NON-NLS
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
addArtifactAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
|
addArtifactAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
|
||||||
addArtifactAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
|
addArtifactAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
|
||||||
@ -731,13 +764,24 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
|
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
|
||||||
bbart.addAttributes(bbattributes);
|
bbart.addAttributes(bbattributes);
|
||||||
|
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Add account relationships
|
// Add account relationships
|
||||||
currentCase.getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
|
currentCase.getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
|
||||||
|
|
||||||
|
if (context.fileIngestIsCancelled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// index the artifact for keyword search
|
// index the artifact for keyword search
|
||||||
blackboard.postArtifact(bbart, EmailParserModuleFactory.getModuleName());
|
blackboard.postArtifact(bbart, EmailParserModuleFactory.getModuleName());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user