3849 resolve merge conflict with develop

This commit is contained in:
William Schaefer 2021-08-04 14:51:26 -04:00
commit 388e127190
24 changed files with 572 additions and 178 deletions

View File

@ -98,6 +98,11 @@ import org.sleuthkit.autopsy.casemodule.events.PersonsAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.PersonsUpdatedEvent; import org.sleuthkit.autopsy.casemodule.events.PersonsUpdatedEvent;
import org.sleuthkit.autopsy.casemodule.events.PersonsDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.PersonsDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.TagNamesEvent.TagNamesAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.TagNamesEvent.TagNamesDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.TagNamesEvent.TagNamesUpdatedEvent;
import org.sleuthkit.autopsy.casemodule.events.TagSetsEvent.TagSetsAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.TagSetsEvent.TagSetsDeletedEvent;
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData.CaseNodeDataException; import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData.CaseNodeDataException;
import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils; import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils;
import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.casemodule.services.Services;
@ -484,7 +489,32 @@ public class Case {
/** /**
* One or more hosts have been removed from a person. * One or more hosts have been removed from a person.
*/ */
HOSTS_REMOVED_FROM_PERSON; HOSTS_REMOVED_FROM_PERSON,
/**
* One or more TagNames have been added.
*/
TAG_NAMES_ADDED,
/**
* One or more TagNames have been updated.
*/
TAG_NAMES_UPDATED,
/**
* One or more TagNames have been deleted.
*/
TAG_NAMES_DELETED,
/**
* One or more TagSets have been added.
*/
TAG_SETS_ADDED,
/**
* One or more TagSets have been removed.
*/
TAG_SETS_DELETED;
}; };
@ -609,6 +639,30 @@ public class Case {
eventPublisher.publish(new HostsRemovedFromPersonEvent(event.getPerson(), event.getHostIds())); eventPublisher.publish(new HostsRemovedFromPersonEvent(event.getPerson(), event.getHostIds()));
} }
@Subscribe
public void publicTagNamesAdded(TskEvent.TagNamesAddedTskEvent event) {
eventPublisher.publish(new TagNamesAddedEvent(event.getTagNames()));
}
@Subscribe
public void publicTagNamesUpdated(TskEvent.TagNamesUpdatedTskEvent event) {
eventPublisher.publish(new TagNamesUpdatedEvent(event.getTagNames()));
}
@Subscribe
public void publicTagNamesDeleted(TskEvent.TagNamesDeletedTskEvent event) {
eventPublisher.publish(new TagNamesDeletedEvent(event.getTagNameIds()));
}
@Subscribe
public void publicTagSetsAdded(TskEvent.TagSetsAddedTskEvent event) {
eventPublisher.publish(new TagSetsAddedEvent(event.getTagSets()));
}
@Subscribe
public void publicTagSetsDeleted(TskEvent.TagSetsDeletedTskEvent event) {
eventPublisher.publish(new TagSetsDeletedEvent(event.getTagSetIds()));
}
} }
/** /**

View File

@ -0,0 +1,126 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.util.ArrayList;
import java.util.List;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TaggingManager;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A base class for TagName added and update events.
*/
public class TagNamesEvent extends TskDataModelChangedEvent<TagName, TagName> {
private static final long serialVersionUID = 1L;
/**
* Construct the base event for TagNames that have been added or updated.
*
* @param eventName The name of the event.
* @param tagNames The TagNames that have been modified.
*/
private TagNamesEvent(String eventName, List<TagName> tagNames) {
super(eventName, null, null, tagNames, TagName::getId);
}
/**
* Returns a list of the added or modified TagNames.
*
* @return The event list of TagNames.
*/
public List<TagName> getTagNames() {
return getNewValue();
}
@Override
protected List<TagName> getNewValueObjects(SleuthkitCase caseDb, List<Long> ids) throws TskCoreException {
List<TagName> tagNames = new ArrayList<>();
TaggingManager taggingMrg = caseDb.getTaggingManager();
for (Long id : ids) {
tagNames.add(taggingMrg.getTagName(id));
}
return tagNames;
}
/**
* Application events published when TagNames have been Added from the
* Sleuth Kit data model for a case.
*/
public static class TagNamesAddedEvent extends TagNamesEvent {
private static final long serialVersionUID = 1L;
/**
* Construct an application event published when TagNames have been
* added to the Sleuth Kit data model.
*
* @param tagNames The TagNames that have been added.
*/
public TagNamesAddedEvent(List<TagName> tagNames) {
super(Case.Events.TAG_NAMES_ADDED.name(), tagNames);
}
}
/**
* Application events published when TagNames have been updated from the
* Sleuth Kit data model for a case.
*/
public static class TagNamesUpdatedEvent extends TagNamesEvent {
private static final long serialVersionUID = 1L;
/**
* Construct an application event published when TagNames have been
* updated in the Sleuth Kit data model.
*
* @param tagNames The TagNames that have been updated.
*/
public TagNamesUpdatedEvent(List<TagName> tagNames) {
super(Case.Events.TAG_NAMES_UPDATED.name(), tagNames);
}
}
/**
* Application events published when TagNames have been deleted from the
* Sleuth Kit data model for a case.
*/
public static class TagNamesDeletedEvent extends TskDataModelObjectsDeletedEvent {
private static final long serialVersionUID = 1L;
/**
* Constructs an application event published when the TagNames have been
* deleted from the Sleuth Kit data model for a case.
*
* @param tagNameIds The IDs of the TagNames that have been deleted.
*/
public TagNamesDeletedEvent(List<Long> tagNameIds) {
super(Case.Events.TAG_NAMES_DELETED.name(), tagNameIds);
}
public List<Long> getTagNameIds() {
return getOldValue();
}
}
}

View File

@ -0,0 +1,103 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.util.ArrayList;
import java.util.List;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TagSet;
import org.sleuthkit.datamodel.TaggingManager;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A base class for TagSet added and update events.
*/
public class TagSetsEvent extends TskDataModelChangedEvent<TagSet, TagSet> {
private static final long serialVersionUID = 1L;
/**
* Construct a new TagSetEvent.
*
* @param eventName
* @param tagSets
*/
private TagSetsEvent(String eventName, List<TagSet> tagSets) {
super(eventName, null, null, tagSets, TagSet::getId);
}
/**
* Returns a list of the TagSet objects that were added or modified for this
* event.
*
* @return A list of TagSet objects.
*/
public List<TagSet> getTagSets() {
return this.getNewValue();
}
@Override
protected List<TagSet> getNewValueObjects(SleuthkitCase caseDb, List<Long> ids) throws TskCoreException {
List<TagSet> tagSets = new ArrayList<>();
TaggingManager taggingMrg = caseDb.getTaggingManager();
for (Long id : ids) {
tagSets.add(taggingMrg.getTagSet(id));
}
return tagSets;
}
/**
* Application events published when TagSets have been Added from the Sleuth
* Kit data model for a case.
*/
public static class TagSetsAddedEvent extends TagSetsEvent {
private static final long serialVersionUID = 1L;
/**
* Construct an application event published when TagSetss have been
* added to the Sleuth Kit data model.
*
* @param tagSets The TagSets that have been added.
*/
public TagSetsAddedEvent(List<TagSet> tagSets) {
super(Case.Events.TAG_SETS_ADDED.name(), tagSets);
}
}
/**
* Application events published when TagSets have been deleted from the
* Sleuth Kit data model for a case.
*/
public static class TagSetsDeletedEvent extends TskDataModelObjectsDeletedEvent {
private static final long serialVersionUID = 1L;
/**
* Constructs an application event published when the TagSets have been
* deleted from the Sleuth Kit data model for a case.
*
* @param tagNameIds The IDs of the TagNames that have been deleted.
*/
public TagSetsDeletedEvent(List<Long> tagNameIds) {
super(Case.Events.TAG_SETS_DELETED.name(), tagNameIds);
}
}
}

View File

@ -236,7 +236,7 @@ final public class TagNameDefinition implements Comparable<TagNameDefinition> {
TagName saveToCase(SleuthkitCase caseDb) { TagName saveToCase(SleuthkitCase caseDb) {
TagName tagName = null; TagName tagName = null;
try { try {
tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus); tagName = caseDb.getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error saving tag name definition", ex); LOGGER.log(Level.SEVERE, "Error saving tag name definition", ex);
} }

View File

@ -18,9 +18,12 @@
*/ */
package org.sleuthkit.autopsy.casemodule.services; package org.sleuthkit.autopsy.casemodule.services;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -29,8 +32,11 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.events.TagNamesEvent;
import org.sleuthkit.autopsy.casemodule.events.TagNamesEvent.TagNamesDeletedEvent;
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager; import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -61,6 +67,37 @@ public class TagsManager implements Closeable {
private static final Object lock = new Object(); private static final Object lock = new Object();
private final Map<String, TagName> allTagNameMap = Collections.synchronizedMap(new HashMap<>());
private final PropertyChangeListener listener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(Case.Events.TAG_NAMES_ADDED.name())
|| evt.getPropertyName().equals(Case.Events.TAG_NAMES_UPDATED.name())) {
TagNamesEvent tagEvent = (TagNamesEvent) evt;
List<TagName> addTagNames = tagEvent.getTagNames();
for (TagName tag : addTagNames) {
allTagNameMap.put(tag.getDisplayName(), tag);
}
} else if (evt.getPropertyName().equals(Case.Events.TAG_NAMES_DELETED.name())) {
TagNamesDeletedEvent tagEvent = (TagNamesDeletedEvent) evt;
List<Long> deletedIds = tagEvent.getTagNameIds();
List<String> keysToRemove = new ArrayList<>();
for (TagName tagName : getAllTagNames()) {
if (deletedIds.contains(tagName.getId())) {
keysToRemove.add(tagName.getDisplayName());
}
}
for (String key : keysToRemove) {
allTagNameMap.remove(key);
}
}
}
};
private final PropertyChangeListener weakListener = WeakListeners.propertyChange(listener, null);
static { static {
//Create the contentviewer tags table if the current case does not //Create the contentviewer tags table if the current case does not
@ -177,8 +214,6 @@ public class TagsManager implements Closeable {
/* /*
* No current case, nothing more to add to the set. * No current case, nothing more to add to the set.
*/ */
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to get list of TagNames from TagsManager.", ex);
} }
return tagDisplayNames; return tagDisplayNames;
} }
@ -268,14 +303,14 @@ public class TagsManager implements Closeable {
// add the standard tag names // add the standard tag names
for (TagNameDefinition def : TagNameDefinition.getStandardTagNameDefinitions()) { for (TagNameDefinition def : TagNameDefinition.getStandardTagNameDefinitions()) {
caseDb.addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus()); taggingMgr.addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus());
} }
//Assume new case and add all tag sets //Assume new case and add all tag sets
for (TagSetDefinition setDef : TagSetDefinition.readTagSetDefinitions()) { for (TagSetDefinition setDef : TagSetDefinition.readTagSetDefinitions()) {
List<TagName> tagNamesInSet = new ArrayList<>(); List<TagName> tagNamesInSet = new ArrayList<>();
for (TagNameDefinition tagNameDef : setDef.getTagNameDefinitions()) { for (TagNameDefinition tagNameDef : setDef.getTagNameDefinitions()) {
tagNamesInSet.add(caseDb.addOrUpdateTagName(tagNameDef.getDisplayName(), tagNameDef.getDescription(), tagNameDef.getColor(), tagNameDef.getKnownStatus())); tagNamesInSet.add(taggingMgr.addOrUpdateTagName(tagNameDef.getDisplayName(), tagNameDef.getDescription(), tagNameDef.getColor(), tagNameDef.getKnownStatus()));
} }
if (!tagNamesInSet.isEmpty()) { if (!tagNamesInSet.isEmpty()) {
@ -283,6 +318,11 @@ public class TagsManager implements Closeable {
} }
} }
} }
for(TagName tagName: caseDb.getAllTagNames()) {
allTagNameMap.put(tagName.getDisplayName(), tagName);
}
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error updating standard tag name and tag set definitions", ex); LOGGER.log(Level.SEVERE, "Error updating standard tag name and tag set definitions", ex);
} catch (IOException ex) { } catch (IOException ex) {
@ -292,6 +332,10 @@ public class TagsManager implements Closeable {
for (TagNameDefinition tagName : TagNameDefinition.getTagNameDefinitions()) { for (TagNameDefinition tagName : TagNameDefinition.getTagNameDefinitions()) {
tagName.saveToCase(caseDb); tagName.saveToCase(caseDb);
} }
Case.addEventTypeSubscriber(Collections.singleton(Case.Events.TAG_NAMES_UPDATED), weakListener);
Case.addEventTypeSubscriber(Collections.singleton(Case.Events.TAG_NAMES_ADDED), weakListener);
Case.addEventTypeSubscriber(Collections.singleton(Case.Events.TAG_NAMES_DELETED), weakListener);
} }
/** /**
@ -337,11 +381,12 @@ public class TagsManager implements Closeable {
* Gets a list of all tag names currently in the case database. * Gets a list of all tag names currently in the case database.
* *
* @return A list, possibly empty, of TagName objects. * @return A list, possibly empty, of TagName objects.
*
* @throws TskCoreException If there is an error querying the case database.
*/ */
public List<TagName> getAllTagNames() throws TskCoreException { public synchronized List<TagName> getAllTagNames() {
return caseDb.getAllTagNames();
List<TagName> tagNames = new ArrayList<>();
tagNames.addAll(allTagNameMap.values());
return tagNames;
} }
/** /**
@ -439,7 +484,7 @@ public class TagsManager implements Closeable {
*/ */
public Map<String, TagName> getDisplayNamesToTagNamesMap() throws TskCoreException { public Map<String, TagName> getDisplayNamesToTagNamesMap() throws TskCoreException {
Map<String, TagName> tagNames = new HashMap<>(); Map<String, TagName> tagNames = new HashMap<>();
for (TagName tagName : caseDb.getAllTagNames()) { for (TagName tagName : getAllTagNames()) {
tagNames.put(tagName.getDisplayName(), tagName); tagNames.put(tagName.getDisplayName(), tagName);
} }
return tagNames; return tagNames;
@ -521,13 +566,13 @@ public class TagsManager implements Closeable {
public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException { public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException {
synchronized (lock) { synchronized (lock) {
try { try {
TagName tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus); TagName tagName = caseDb.getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus);
Set<TagNameDefinition> customTypes = TagNameDefinition.getTagNameDefinitions(); Set<TagNameDefinition> customTypes = TagNameDefinition.getTagNameDefinitions();
customTypes.add(new TagNameDefinition(displayName, description, color, knownStatus)); customTypes.add(new TagNameDefinition(displayName, description, color, knownStatus));
TagNameDefinition.setTagNameDefinitions(customTypes); TagNameDefinition.setTagNameDefinitions(customTypes);
return tagName; return tagName;
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
List<TagName> existingTagNames = caseDb.getAllTagNames(); List<TagName> existingTagNames = getAllTagNames();
for (TagName tagName : existingTagNames) { for (TagName tagName : existingTagNames) {
if (tagName.getDisplayName().equals(displayName)) { if (tagName.getDisplayName().equals(displayName)) {
throw new TagNameAlreadyExistsException(); throw new TagNameAlreadyExistsException();
@ -1039,5 +1084,4 @@ public class TagsManager implements Closeable {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
} }
} }

View File

@ -2,7 +2,7 @@ CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empt
CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created. CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created.
CommandListIngestSettingsPanel_Default_Report_DisplayName=Default CommandListIngestSettingsPanel_Default_Report_DisplayName=Default
CommandListIngestSettingsPanel_Make_Config=Make new profile... CommandListIngestSettingsPanel_Make_Config=Make new profile...
CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name: CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (commas not allowed):
OpenIDE-Module-Name=CommandLineAutopsy OpenIDE-Module-Name=CommandLineAutopsy
OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings
OptionsCategory_Keywords_General=Options OptionsCategory_Keywords_General=Options

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2019-2020 Basis Technology Corp. * Copyright 2019-2021 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");
@ -280,7 +280,7 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel {
add(nodePanel, java.awt.BorderLayout.CENTER); add(nodePanel, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@Messages({ @Messages({
"CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name:", "CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (commas not allowed):",
"CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empty, no profile created.", "CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empty, no profile created.",
"CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created." "CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created."
}) })
@ -289,6 +289,10 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel {
if (reportName.equals(Bundle.CommandListIngestSettingsPanel_Make_Config())) { if (reportName.equals(Bundle.CommandListIngestSettingsPanel_Make_Config())) {
reportName = JOptionPane.showInputDialog(this, Bundle.CommandListIngestSettingsPanel_Report_Name_Msg()); reportName = JOptionPane.showInputDialog(this, Bundle.CommandListIngestSettingsPanel_Report_Name_Msg());
// sanitize report name. Remove all commas because in CommandLineOptionProcessor we use commas
// to separate multiple report names
reportName = reportName.replaceAll(",", "");
// User hit cancel // User hit cancel
if (reportName == null) { if (reportName == null) {
return; return;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2019-2020 Basis Technology Corp. * Copyright 2019-2021 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");
@ -20,12 +20,15 @@ package org.sleuthkit.autopsy.commandlineingest;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.netbeans.api.sendopts.CommandException; import org.netbeans.api.sendopts.CommandException;
import org.netbeans.spi.sendopts.Env; import org.netbeans.spi.sendopts.Env;
@ -291,7 +294,6 @@ public class CommandLineOptionProcessor extends OptionProcessor {
} }
// Add "GENERATE_REPORTS" command, if present // Add "GENERATE_REPORTS" command, if present
String reportProfile = null;
if (values.containsKey(generateReportsOption)) { if (values.containsKey(generateReportsOption)) {
// 'caseDir' must only be specified if the case is not being created during the current run // 'caseDir' must only be specified if the case is not being created during the current run
@ -300,24 +302,34 @@ public class CommandLineOptionProcessor extends OptionProcessor {
handleError("'caseDir' argument is empty"); handleError("'caseDir' argument is empty");
} }
List<String> reportProfiles;
argDirs = values.get(generateReportsOption); argDirs = values.get(generateReportsOption);
if (argDirs.length > 0) { if (argDirs.length > 0) {
reportProfile = argDirs[0]; // use custom report configuration(s)
reportProfiles = Stream.of(argDirs[0].split(","))
.map(String::trim)
.collect(Collectors.toList());
if (reportProfiles == null || reportProfiles.isEmpty()) {
handleError("'generateReports' argument is empty");
}
for (String reportProfile : reportProfiles) {
if (reportProfile.isEmpty()) {
handleError("Empty report profile name");
}
CommandLineCommand newCommand = new CommandLineCommand(CommandLineCommand.CommandType.GENERATE_REPORTS);
newCommand.addInputValue(CommandLineCommand.InputType.CASE_FOLDER_PATH.name(), caseDir);
newCommand.addInputValue(CommandLineCommand.InputType.REPORT_PROFILE_NAME.name(), reportProfile);
commands.add(newCommand);
}
} else {
// use default report configuration
CommandLineCommand newCommand = new CommandLineCommand(CommandLineCommand.CommandType.GENERATE_REPORTS);
newCommand.addInputValue(CommandLineCommand.InputType.CASE_FOLDER_PATH.name(), caseDir);
commands.add(newCommand);
} }
// If the user doesn't supply an options for generateReports the
// argsDirs length will be 0, so if reportProfile is empty
// something is not right.
if (reportProfile != null && reportProfile.isEmpty()) {
handleError("'generateReports' argument is empty");
}
CommandLineCommand newCommand = new CommandLineCommand(CommandLineCommand.CommandType.GENERATE_REPORTS);
newCommand.addInputValue(CommandLineCommand.InputType.CASE_FOLDER_PATH.name(), caseDir);
if (reportProfile != null) {
newCommand.addInputValue(CommandLineCommand.InputType.REPORT_PROFILE_NAME.name(), reportProfile);
}
commands.add(newCommand);
runFromCommandLine = true; runFromCommandLine = true;
} }
} }

View File

@ -141,7 +141,7 @@ public class OsAccountViewer extends javax.swing.JPanel implements DataContentVi
@Override @Override
public int isPreferred(Node node) { public int isPreferred(Node node) {
return 5; return 1;
} }
/** /**

View File

@ -1,7 +1,10 @@
DataSourceFilter.errorMessage.emptyDataSource=At least one data source must be selected. DataSourceFilter.errorMessage.emptyDataSource=At least one data source must be selected.
DateSearchFilter.errorMessage.endDateBeforeStartDate=The end date should be after the start date. DateSearchFilter.errorMessage.endDateBeforeStartDate=The end date should be after the start date.
DateSearchFilter.errorMessage.noCheckboxSelected=At least one date type checkbox must be selected. DateSearchFilter.errorMessage.noCheckboxSelected=At least one date type checkbox must be selected.
FileSearchPanel.cancelledSearch.text=Search Was Cancelled
FileSearchPanel.emptyNode.display.text=No results found. FileSearchPanel.emptyNode.display.text=No results found.
FileSearchPanel.searchingNode.display.text=Performing file search by attributes. Please wait.
FileSearchPanel.searchingPath.text=File Search In Progress
HashSearchFilter.errorMessage.emptyHash=Hash data is empty. HashSearchFilter.errorMessage.emptyHash=Hash data is empty.
HashSearchFilter.errorMessage.wrongCharacter=MD5 contains invalid hex characters. HashSearchFilter.errorMessage.wrongCharacter=MD5 contains invalid hex characters.
# {0} - hash data length # {0} - hash data length

View File

@ -29,15 +29,17 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import org.openide.DialogDisplayer; import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor; import org.openide.NotifyDescriptor;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
@ -56,13 +58,14 @@ import org.sleuthkit.datamodel.TskCoreException;
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class FileSearchPanel extends javax.swing.JPanel { class FileSearchPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(FileSearchPanel.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final List<FileSearchFilter> filters = new ArrayList<>(); private final List<FileSearchFilter> filters = new ArrayList<>();
private static int resultWindowCount = 0; //keep track of result windows so they get unique names private static int resultWindowCount = 0; //keep track of result windows so they get unique names
private static final MimeTypeFilter mimeTypeFilter = new MimeTypeFilter(); private static final MimeTypeFilter mimeTypeFilter = new MimeTypeFilter();
private static final DataSourceFilter dataSourceFilter = new DataSourceFilter(); private static final DataSourceFilter dataSourceFilter = new DataSourceFilter();
private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text"); private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text");
private static SwingWorker<TableFilterNode, Void> searchWorker = null;
enum EVENT { enum EVENT {
CHECKED CHECKED
@ -176,56 +179,102 @@ class FileSearchPanel extends javax.swing.JPanel {
* Action when the "Search" button is pressed. * Action when the "Search" button is pressed.
* *
*/ */
@NbBundle.Messages("FileSearchPanel.emptyNode.display.text=No results found.") @NbBundle.Messages({"FileSearchPanel.emptyNode.display.text=No results found.",
"FileSearchPanel.searchingNode.display.text=Performing file search by attributes. Please wait.",
"FileSearchPanel.searchingPath.text=File Search In Progress",
"FileSearchPanel.cancelledSearch.text=Search Was Cancelled"})
private void search() { private void search() {
// change the cursor to "waiting cursor" for this operation if (searchWorker != null && searchWorker.isDone()) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); searchWorker.cancel(true);
}
try { try {
if (this.isValidSearch()) { if (this.isValidSearch()) {
String title = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.title", ++resultWindowCount);
String pathText = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.pathText");
// try to get the number of matches first // try to get the number of matches first
Case currentCase = Case.getCurrentCaseThrows(); // get the most updated case Case currentCase = Case.getCurrentCaseThrows(); // get the most updated case
long totalMatches = 0; Node emptyNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_searchingNode_display_text()), true);
List<AbstractFile> contentList = null; String title = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.title", ++resultWindowCount);
try { String pathText = Bundle.FileSearchPanel_searchingPath_text();
SleuthkitCase tskDb = currentCase.getSleuthkitCase(); final DataResultTopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
contentList = tskDb.findAllFilesWhere(this.getQuery()); emptyNode, 0);
} catch (TskCoreException ex) {
Logger logger = Logger.getLogger(this.getClass().getName());
logger.log(Level.WARNING, "Error while trying to get the number of matches.", ex); //NON-NLS
}
if (contentList == null) {
contentList = Collections.<AbstractFile>emptyList();
}
SearchNode sn = new SearchNode(contentList);
TableFilterNode tableFilterNode = new TableFilterNode(sn, true, sn.getName());
final TopComponent searchResultWin;
if (contentList.isEmpty()) {
Node emptyNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true);
searchResultWin = DataResultTopComponent.createInstance(title, pathText,
emptyNode, 0);
} else {
searchResultWin = DataResultTopComponent.createInstance(title, pathText,
tableFilterNode, contentList.size());
}
searchResultWin.requestActive(); // make it the active top component searchResultWin.requestActive(); // make it the active top component
searchResultWin.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
searchWorker = new SwingWorker<TableFilterNode, Void>() {
List<AbstractFile> contentList = null;
/** @Override
* If total matches more than 1000, pop up a dialog box that say protected TableFilterNode doInBackground() throws Exception {
* the performance maybe be slow and to increase the try {
* performance, tell the users to refine their search. SleuthkitCase tskDb = currentCase.getSleuthkitCase();
*/ contentList = tskDb.findAllFilesWhere(getQuery());
if (totalMatches > 10000) {
// show info } catch (TskCoreException ex) {
String msg = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.msg", totalMatches); Logger logger = Logger.getLogger(this.getClass().getName());
String details = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.details"); logger.log(Level.WARNING, "Error while trying to get the number of matches.", ex); //NON-NLS
MessageNotifyUtil.Notify.info(msg, details); }
if (contentList == null) {
contentList = Collections.<AbstractFile>emptyList();
}
if (contentList.isEmpty()) {
return new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true);
}
SearchNode sn = new SearchNode(contentList);
return new TableFilterNode(sn, true, sn.getName());
}
@Override
protected void done() {
String pathText = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.pathText");
try {
TableFilterNode tableFilterNode = get();
if (tableFilterNode == null) { //just incase this get() gets modified to return null or somehow can return null
tableFilterNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true);
}
if (searchResultWin != null && searchResultWin.isOpened()) {
searchResultWin.setNode(tableFilterNode);
searchResultWin.requestActive(); // make it the active top component
}
/**
* If total matches more than 1000, pop up a dialog
* box that say the performance maybe be slow and to
* increase the performance, tell the users to
* refine their search.
*/
if (contentList.size() > 10000) {
// show info
String msg = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.msg", contentList.size());
String details = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.details");
MessageNotifyUtil.Notify.info(msg, details);
}
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.SEVERE, "Error while performing file search by attributes", ex);
} catch (CancellationException ex) {
if (searchResultWin != null && searchResultWin.isOpened()) {
Node emptyNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_cancelledSearch_text()), true);
searchResultWin.setNode(emptyNode);
pathText = Bundle.FileSearchPanel_cancelledSearch_text();
}
logger.log(Level.INFO, "File search by attributes was cancelled", ex);
} finally {
if (searchResultWin != null && searchResultWin.isOpened()) {
searchResultWin.setPath(pathText);
searchResultWin.requestActive(); // make it the active top component
searchResultWin.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
};
if (searchResultWin != null && searchResultWin.isOpened()) {
searchResultWin.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("tcClosed") && !searchWorker.isDone() && evt.getOldValue() == null) {
searchWorker.cancel(true);
logger.log(Level.INFO, "User has closed the results window while search was in progress, search will be cancelled");
}
}
});
} }
searchWorker.execute();
} else { } else {
throw new FilterValidationException( throw new FilterValidationException(
NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.exception.noFilterSelected.msg")); NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.exception.noFilterSelected.msg"));
@ -234,8 +283,6 @@ class FileSearchPanel extends javax.swing.JPanel {
NotifyDescriptor d = new NotifyDescriptor.Message( NotifyDescriptor d = new NotifyDescriptor.Message(
NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.validationErr.msg", ex.getMessage())); NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.validationErr.msg", ex.getMessage()));
DialogDisplayer.getDefault().notify(d); DialogDisplayer.getDefault().notify(d);
} finally {
this.setCursor(null);
} }
} }

View File

@ -219,7 +219,7 @@ public final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewe
JMenuItem[] getMenuItems() throws TskCoreException { JMenuItem[] getMenuItems() throws TskCoreException {
List<JMenuItem> menuItems = new ArrayList<>(); List<JMenuItem> menuItems = new ArrayList<>();
BlackboardArtifact artifact = dataModelWaypoint.getArtifact(); BlackboardArtifact artifact = dataModelWaypoint.getArtifact();
Content content = artifact.getSleuthkitCase().getContentById(artifact.getObjectID()); Content content = dataModelWaypoint.getContent();
menuItems.addAll(getTimelineMenuItems(dataModelWaypoint.getArtifact())); menuItems.addAll(getTimelineMenuItems(dataModelWaypoint.getArtifact()));
menuItems.addAll(getDataModelActionFactoryMenuItems(artifact, content)); menuItems.addAll(getDataModelActionFactoryMenuItems(artifact, content));

View File

@ -28,6 +28,7 @@ import java.util.Set;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -44,6 +45,7 @@ public class Waypoint {
final private AbstractFile image; final private AbstractFile image;
final private BlackboardArtifact artifact; final private BlackboardArtifact artifact;
final private GeoPath parentGeoPath; final private GeoPath parentGeoPath;
final private Content content;
final private List<Waypoint.Property> propertiesList; final private List<Waypoint.Property> propertiesList;
@ -93,6 +95,11 @@ public class Waypoint {
this.parentGeoPath = parentGeoPath; this.parentGeoPath = parentGeoPath;
propertiesList = createGeolocationProperties(attributeMap); propertiesList = createGeolocationProperties(attributeMap);
try {
content = artifact.getSleuthkitCase().getContentById(artifact.getObjectID());
} catch (TskCoreException ex) {
throw new GeoLocationDataException(String.format("Failed to get contend for artifact id (%d)", artifact.getId()), ex);
}
} }
/** /**
@ -249,6 +256,10 @@ public class Waypoint {
return list; return list;
} }
public Content getContent() {
return content;
}
/** /**
* Simple property class for waypoint properties that a purely * Simple property class for waypoint properties that a purely
* informational. * informational.

View File

@ -538,7 +538,10 @@ final class IngestJobPipeline {
* @return True or false. * @return True or false.
*/ */
boolean hasFileIngestModules() { boolean hasFileIngestModules() {
return (fileIngestPipelines.isEmpty() == false); if (!fileIngestPipelines.isEmpty()) {
return !fileIngestPipelines.get(0).isEmpty();
}
return false;
} }
/** /**

View File

@ -340,7 +340,7 @@ public class PortableCaseReportModule implements ReportModule {
progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags()); progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
try { try {
for (TagName tagName : tagNames) { for (TagName tagName : tagNames) {
TagName newTagName = portableSkCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus()); TagName newTagName = portableSkCase.getTaggingManager().addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus());
oldTagNameToNewTagName.put(tagName, newTagName); oldTagNameToNewTagName.put(tagName, newTagName);
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {

View File

@ -149,7 +149,7 @@ public class ImageGalleryService implements AutopsyService {
private void addProjetVicTagSet(Case currentCase) throws TskCoreException { private void addProjetVicTagSet(Case currentCase) throws TskCoreException {
List<TagName> tagNames = new ArrayList<>(); List<TagName> tagNames = new ArrayList<>();
for (TagNameDefinition def : PROJECT_VIC_US_CATEGORIES) { for (TagNameDefinition def : PROJECT_VIC_US_CATEGORIES) {
tagNames.add(currentCase.getSleuthkitCase().addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus())); tagNames.add(currentCase.getSleuthkitCase().getTaggingManager().addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus()));
} }
currentCase.getServices().getTagsManager().addTagSet(PROJECT_VIC_TAG_SET_NAME, tagNames); currentCase.getServices().getTagsManager().addTagSet(PROJECT_VIC_TAG_SET_NAME, tagNames);
} }

View File

@ -40,7 +40,7 @@ from java.lang import Class
from java.lang import System from java.lang import System
from java.sql import DriverManager, SQLException from java.sql import DriverManager, SQLException
from java.util.logging import Level from java.util.logging import Level
from java.util import ArrayList from java.util import Arrays
from java.io import File from java.io import File
from org.sleuthkit.datamodel import SleuthkitCase from org.sleuthkit.datamodel import SleuthkitCase
from org.sleuthkit.datamodel import AbstractFile from org.sleuthkit.datamodel import AbstractFile
@ -113,7 +113,7 @@ class ContactsDbIngestModule(DataSourceIngestModule):
progressBar.switchToIndeterminate() progressBar.switchToIndeterminate()
# Use blackboard class to index blackboard artifacts for keyword search # Use blackboard class to index blackboard artifacts for keyword search
blackboard = Case.getCurrentCase().getServices().getBlackboard() blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard()
# Find files named contacts.db, regardless of parent path # Find files named contacts.db, regardless of parent path
fileManager = Case.getCurrentCase().getServices().getFileManager() fileManager = Case.getCurrentCase().getServices().getFileManager()
@ -162,30 +162,21 @@ class ContactsDbIngestModule(DataSourceIngestModule):
# Make an artifact on the blackboard, TSK_CONTACT and give it attributes for each of the fields # Make an artifact on the blackboard, TSK_CONTACT and give it attributes for each of the fields
art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) art = file.newDataArtifact(BlackboardArtifact.Type.TSK_CONTACT, Arrays.asList(
attributes = ArrayList() BlackboardAttribute(BlackboardAttribute.Type.TSK_NAME_PERSON,
ContactsDbIngestModuleFactory.moduleName, name),
BlackboardAttribute(BlackboardAttribute.Type.TSK_EMAIL,
ContactsDbIngestModuleFactory.moduleName, email),
BlackboardAttribute(BlackboardAttribute.Type.TSK_PHONE_NUMBER,
ContactsDbIngestModuleFactory.moduleName, phone)
))
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID(),
ContactsDbIngestModuleFactory.moduleName, name))
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL.getTypeID(),
ContactsDbIngestModuleFactory.moduleName, email))
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(),
ContactsDbIngestModuleFactory.moduleName, phone))
art.addAttributes(attributes)
try: try:
# index the artifact for keyword search # index the artifact for keyword search
blackboard.indexArtifact(art) blackboard.postArtifact(art, ContactsDbIngestModuleFactory.moduleName)
except Blackboard.BlackboardException as e: except Blackboard.BlackboardException as e:
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName()) self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
# Fire an event to notify the UI and others that there are new artifacts
IngestServices.getInstance().fireModuleDataEvent(
ModuleDataEvent(ContactsDbIngestModuleFactory.moduleName,
BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT, None))
# Clean up # Clean up
stmt.close() stmt.close()
dbConn.close() dbConn.close()

View File

@ -145,7 +145,7 @@ class RunExeIngestModule(DataSourceIngestModule):
# Add each argument in its own line. I.e. "-f foo" would be two calls to .add() # Add each argument in its own line. I.e. "-f foo" would be two calls to .add()
cmd.add(imagePaths[0]) cmd.add(imagePaths[0])
processBuilder = ProcessBuilder(cmd); processBuilder = ProcessBuilder(cmd)
processBuilder.redirectOutput(reportFile) processBuilder.redirectOutput(reportFile)
ExecUtil.execute(processBuilder, DataSourceIngestModuleProcessTerminator(self.context)) ExecUtil.execute(processBuilder, DataSourceIngestModuleProcessTerminator(self.context))

View File

@ -57,6 +57,8 @@ from org.sleuthkit.autopsy.casemodule import Case
from org.sleuthkit.autopsy.casemodule.services import Services from org.sleuthkit.autopsy.casemodule.services import Services
from org.sleuthkit.autopsy.casemodule.services import FileManager from org.sleuthkit.autopsy.casemodule.services import FileManager
from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import Blackboard
from org.sleuthkit.datamodel import Score
from java.util import Arrays
# Factory that defines the name and details of the module and allows Autopsy # Factory that defines the name and details of the module and allows Autopsy
# to create instances of the modules that will do the anlaysis. # to create instances of the modules that will do the anlaysis.
@ -107,7 +109,7 @@ class FindBigRoundFilesIngestModule(FileIngestModule):
def process(self, file): def process(self, file):
# Use blackboard class to index blackboard artifacts for keyword search # Use blackboard class to index blackboard artifacts for keyword search
blackboard = Case.getCurrentCase().getServices().getBlackboard() blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard()
# Skip non-files # Skip non-files
if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or
@ -120,22 +122,19 @@ class FindBigRoundFilesIngestModule(FileIngestModule):
# Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of
# artifact. Refer to the developer docs for other examples. # artifact. Refer to the developer docs for other examples.
art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT) art = file.newAnalysisResult(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, Score.SCORE_LIKELY_NOTABLE,
att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), None, "Big and Round Files", None,
FindBigRoundFilesIngestModuleFactory.moduleName, "Big and Round Files") Arrays.asList(
art.addAttribute(att) BlackboardAttribute(BlackboardAttribute.Type.TSK_SET_NAME,
FindBigRoundFilesIngestModuleFactory.moduleName,
"Big and Round Files"))).getAnalysisResult()
try: try:
# index the artifact for keyword search # post the artifact for listeners of artifact events
blackboard.indexArtifact(art) blackboard.postArtifact(art, FindBigRoundFilesIngestModuleFactory.moduleName)
except Blackboard.BlackboardException as e: except Blackboard.BlackboardException as e:
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName()) self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
# Fire an event to notify the UI and others that there is a new artifact
IngestServices.getInstance().fireModuleDataEvent(
ModuleDataEvent(FindBigRoundFilesIngestModuleFactory.moduleName,
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None))
return IngestModule.ProcessResult.OK return IngestModule.ProcessResult.OK
# Where any shutdown code is run and resources are freed. # Where any shutdown code is run and resources are freed.

View File

@ -45,12 +45,13 @@ from java.lang import Class
from java.lang import System from java.lang import System
from java.sql import DriverManager, SQLException from java.sql import DriverManager, SQLException
from java.util.logging import Level from java.util.logging import Level
from java.util import ArrayList from java.util import Arrays
from org.sleuthkit.datamodel import SleuthkitCase from org.sleuthkit.datamodel import SleuthkitCase
from org.sleuthkit.datamodel import AbstractFile from org.sleuthkit.datamodel import AbstractFile
from org.sleuthkit.datamodel import ReadContentInputStream from org.sleuthkit.datamodel import ReadContentInputStream
from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import Blackboard
from org.sleuthkit.datamodel import TskData from org.sleuthkit.datamodel import TskData
from org.sleuthkit.autopsy.ingest import IngestModule from org.sleuthkit.autopsy.ingest import IngestModule
from org.sleuthkit.autopsy.ingest.IngestModule import IngestModuleException from org.sleuthkit.autopsy.ingest.IngestModule import IngestModuleException
@ -130,12 +131,13 @@ class RegistryExampleIngestModule(DataSourceIngestModule):
tempDir = os.path.join(Case.getCurrentCase().getTempDirectory(), "RegistryExample") tempDir = os.path.join(Case.getCurrentCase().getTempDirectory(), "RegistryExample")
self.log(Level.INFO, "create Directory " + tempDir) self.log(Level.INFO, "create Directory " + tempDir)
try: try:
os.mkdir(tempDir) os.mkdir(tempDir)
except: except:
self.log(Level.INFO, "ExampleRegistry Directory already exists " + tempDir) self.log(Level.INFO, "ExampleRegistry Directory already exists " + tempDir)
# Set the database to be read to the once created by the prefetch parser program # Set the database to be read to the once created by the prefetch parser program
skCase = Case.getCurrentCase().getSleuthkitCase(); skCase = Case.getCurrentCase().getSleuthkitCase()
blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard()
fileManager = Case.getCurrentCase().getServices().getFileManager() fileManager = Case.getCurrentCase().getServices().getFileManager()
# Look for files to process # Look for files to process
@ -170,12 +172,12 @@ class RegistryExampleIngestModule(DataSourceIngestModule):
# Setup Artifact and Attributes # Setup Artifact and Attributes
try: artType = skCase.getArtifactType("TSK_REGISTRY_RUN_KEYS")
artID = skCase.addArtifactType( "TSK_REGISTRY_RUN_KEYS", "Registry Run Keys") if not artType:
except: try:
self.log(Level.INFO, "Artifacts Creation Error, some artifacts may not exist now. ==> ") artType = skCase.addBlackboardArtifactType( "TSK_REGISTRY_RUN_KEYS", "Registry Run Keys")
except:
artId = skCase.getArtifactTypeID("TSK_REGISTRY_RUN_KEYS") self.log(Level.WARNING, "Artifacts Creation Error, some artifacts may not exist now. ==> ")
try: try:
attributeIdRunKeyName = skCase.addArtifactAttributeType("TSK_REG_RUN_KEY_NAME", BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, "Run Key Name") attributeIdRunKeyName = skCase.addArtifactAttributeType("TSK_REG_RUN_KEY_NAME", BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, "Run Key Name")
@ -198,25 +200,24 @@ class RegistryExampleIngestModule(DataSourceIngestModule):
# RefistryKeysFound is a list that contains a list with the following records abstractFile, Registry Key Location, Key Name, Key value # RefistryKeysFound is a list that contains a list with the following records abstractFile, Registry Key Location, Key Name, Key value
for registryKey in self.registryKeysFound: for registryKey in self.registryKeysFound:
attributes = ArrayList() self.log(Level.INFO, "Creating artifact for registry key with path: " + registryKey[1] + " and key: " + registryKey[2])
art = registryKey[0].newArtifact(artId) art = registryKey[0].newDataArtifact(artType, Arrays.asList(
BlackboardAttribute(attributeIdRegKeyLoc, moduleName, registryKey[1]),
attributes.add(BlackboardAttribute(attributeIdRegKeyLoc, moduleName, registryKey[1])) BlackboardAttribute(attributeIdRunKeyName, moduleName, registryKey[2]),
attributes.add(BlackboardAttribute(attributeIdRunKeyName, moduleName, registryKey[2])) BlackboardAttribute(attributeIdRunKeyValue, moduleName, registryKey[3])
attributes.add(BlackboardAttribute(attributeIdRunKeyValue, moduleName, registryKey[3])) ))
art.addAttributes(attributes)
# index the artifact for keyword search # index the artifact for keyword search
try: try:
blackboard.indexArtifact(art) blackboard.postArtifact(art, moduleName)
except: except Blackboard.BlackboardException as ex:
self._logger.log(Level.WARNING, "Error indexing artifact " + art.getDisplayName()) self.log(Level.SEVERE, "Unable to index blackboard artifact " + str(art.getArtifactTypeName()), ex)
#Clean up registryExample directory and files #Clean up registryExample directory and files
try: try:
shutil.rmtree(tempDir) shutil.rmtree(tempDir)
except: except:
self.log(Level.INFO, "removal of directory tree failed " + tempDir) self.log(Level.INFO, "removal of directory tree failed " + tempDir)
# After all databases, post a message to the ingest messages in box. # After all databases, post a message to the ingest messages in box.
message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, message = IngestMessage.createMessage(IngestMessage.MessageType.DATA,
@ -236,7 +237,7 @@ class RegistryExampleIngestModule(DataSourceIngestModule):
softwareRegFile = RegistryHiveFile(File(softwareHive)) softwareRegFile = RegistryHiveFile(File(softwareHive))
for runKey in self.registrySoftwareRunKeys: for runKey in self.registrySoftwareRunKeys:
currentKey = self.findRegistryKey(softwareRegFile, runKey) currentKey = self.findRegistryKey(softwareRegFile, runKey)
if len(currentKey.getValueList()) > 0: if currentKey and len(currentKey.getValueList()) > 0:
skValues = currentKey.getValueList() skValues = currentKey.getValueList()
for skValue in skValues: for skValue in skValues:
regKey = [] regKey = []
@ -255,7 +256,7 @@ class RegistryExampleIngestModule(DataSourceIngestModule):
ntuserRegFile = RegistryHiveFile(File(ntuserHive)) ntuserRegFile = RegistryHiveFile(File(ntuserHive))
for runKey in self.registryNTUserRunKeys: for runKey in self.registryNTUserRunKeys:
currentKey = self.findRegistryKey(ntuserRegFile, runKey) currentKey = self.findRegistryKey(ntuserRegFile, runKey)
if len(currentKey.getValueList()) > 0: if currentKey and len(currentKey.getValueList()) > 0:
skValues = currentKey.getValueList() skValues = currentKey.getValueList()
for skValue in skValues: for skValue in skValues:
regKey = [] regKey = []
@ -276,9 +277,10 @@ class RegistryExampleIngestModule(DataSourceIngestModule):
for key in regKeyList: for key in regKeyList:
currentKey = currentKey.getSubkey(key) currentKey = currentKey.getSubkey(key)
return currentKey return currentKey
except: except Exception as ex:
# Key not found # Key not found
return null self.log(Level.SEVERE, "registry key parsing issue:", ex)
return None

View File

@ -37,6 +37,7 @@
import os import os
import codecs
from java.lang import System from java.lang import System
from java.util.logging import Level from java.util.logging import Level
from org.sleuthkit.datamodel import TskData from org.sleuthkit.datamodel import TskData
@ -72,11 +73,11 @@ class CSVReportModule(GeneralReportModuleAdapter):
# The 'baseReportDir' object being passed in is a string with the directory that reports are being stored in. Report should go into baseReportDir + getRelativeFilePath(). # The 'baseReportDir' object being passed in is a string with the directory that reports are being stored in. Report should go into baseReportDir + getRelativeFilePath().
# The 'progressBar' object is of type ReportProgressPanel. # The 'progressBar' object is of type ReportProgressPanel.
# See: http://sleuthkit.org/autopsy/docs/api-docs/latest/classorg_1_1sleuthkit_1_1autopsy_1_1report_1_1_report_progress_panel.html # See: http://sleuthkit.org/autopsy/docs/api-docs/latest/classorg_1_1sleuthkit_1_1autopsy_1_1report_1_1_report_progress_panel.html
def generateReport(self, baseReportDir, progressBar): def generateReport(self, reportSettings, progressBar):
# Open the output file. # Open the output file.
fileName = os.path.join(baseReportDir, self.getRelativeFilePath()) fileName = os.path.join(reportSettings.getReportDirectoryPath(), self.getRelativeFilePath())
report = open(fileName, 'w') report = codecs.open(fileName, "w", "utf-8")
# Query the database for the files (ignore the directories) # Query the database for the files (ignore the directories)
sleuthkitCase = Case.getCurrentCase().getSleuthkitCase() sleuthkitCase = Case.getCurrentCase().getSleuthkitCase()

View File

@ -53,9 +53,8 @@ from org.sleuthkit.autopsy.casemodule import Case
from org.sleuthkit.autopsy.casemodule.services import Services from org.sleuthkit.autopsy.casemodule.services import Services
from org.sleuthkit.autopsy.casemodule.services import FileManager from org.sleuthkit.autopsy.casemodule.services import FileManager
from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import Blackboard
from org.sleuthkit.autopsy.casemodule.services import Blackboard
from org.sleuthkit.datamodel import Score from org.sleuthkit.datamodel import Score
from java.util import ArrayList from java.util import Arrays
# Factory that defines the name and details of the module and allows Autopsy # Factory that defines the name and details of the module and allows Autopsy
# to create instances of the modules that will do the analysis. # to create instances of the modules that will do the analysis.
@ -86,8 +85,6 @@ class SampleJythonDataSourceIngestModuleFactory(IngestModuleFactoryAdapter):
# Data Source-level ingest module. One gets created per data source. # Data Source-level ingest module. One gets created per data source.
# TODO: Rename this to something more specific. Could just remove "Factory" from above name. # TODO: Rename this to something more specific. Could just remove "Factory" from above name.
class SampleJythonDataSourceIngestModule(DataSourceIngestModule): class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
LIKELY_NOTABLE_SCORE = Score(Score.Significance.LIKELY_NOTABLE, Score.MethodCategory.AUTO)
_logger = Logger.getLogger(SampleJythonDataSourceIngestModuleFactory.moduleName) _logger = Logger.getLogger(SampleJythonDataSourceIngestModuleFactory.moduleName)
def log(self, level, msg): def log(self, level, msg):
@ -118,7 +115,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
progressBar.switchToIndeterminate() progressBar.switchToIndeterminate()
# Use blackboard class to index blackboard artifacts for keyword search # Use blackboard class to index blackboard artifacts for keyword search
blackboard = Case.getCurrentCase().getServices().getBlackboard() blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard()
# For our example, we will use FileManager to get all # For our example, we will use FileManager to get all
# files with the word "test" # files with the word "test"
@ -142,13 +139,15 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
# Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of
# artfiact. Refer to the developer docs for other examples. # artfiact. Refer to the developer docs for other examples.
attrs = ArrayList() attrs = Arrays.asList(BlackboardAttribute(BlackboardAttribute.Type.TSK_SET_NAME,
attrs.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, SampleJythonDataSourceIngestModuleFactory.moduleName, "Test file")) SampleJythonDataSourceIngestModuleFactory.moduleName,
art = file.newAnalysisResult(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, self.LIKELY_NOTABLE_SCORE, None, "Test file", None, attrs) "Test file"))
art = file.newAnalysisResult(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, Score.SCORE_LIKELY_NOTABLE,
None, "Test file", None, attrs).getAnalysisResult()
try: try:
# index the artifact for keyword search # post the artifact for listeners of artifact events.
blackboard.indexArtifact(art) blackboard.postArtifact(art, SampleJythonDataSourceIngestModuleFactory.moduleName)
except Blackboard.BlackboardException as e: except Blackboard.BlackboardException as e:
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName()) self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())

View File

@ -55,8 +55,7 @@ from org.sleuthkit.autopsy.casemodule import Case
from org.sleuthkit.autopsy.casemodule.services import Services from org.sleuthkit.autopsy.casemodule.services import Services
from org.sleuthkit.autopsy.casemodule.services import FileManager from org.sleuthkit.autopsy.casemodule.services import FileManager
from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import Blackboard
from org.sleuthkit.datamodel import Score from java.util import Arrays
from java.util import ArrayList
# Factory that defines the name and details of the module and allows Autopsy # Factory that defines the name and details of the module and allows Autopsy
# to create instances of the modules that will do the anlaysis. # to create instances of the modules that will do the anlaysis.
@ -89,7 +88,6 @@ class SampleJythonFileIngestModuleFactory(IngestModuleFactoryAdapter):
# TODO: Rename this to something more specific. Could just remove "Factory" from above name. # TODO: Rename this to something more specific. Could just remove "Factory" from above name.
# Looks at the attributes of the passed in file. # Looks at the attributes of the passed in file.
class SampleJythonFileIngestModule(FileIngestModule): class SampleJythonFileIngestModule(FileIngestModule):
LIKELY_NOTABLE_SCORE = Score(Score.Significance.LIKELY_NOTABLE, Score.MethodCategory.AUTO)
_logger = Logger.getLogger(SampleJythonFileIngestModuleFactory.moduleName) _logger = Logger.getLogger(SampleJythonFileIngestModuleFactory.moduleName)
@ -119,7 +117,7 @@ class SampleJythonFileIngestModule(FileIngestModule):
return IngestModule.ProcessResult.OK return IngestModule.ProcessResult.OK
# Use blackboard class to index blackboard artifacts for keyword search # Use blackboard class to index blackboard artifacts for keyword search
blackboard = Case.getCurrentCase().getServices().getBlackboard() blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard()
# For an example, we will flag files with .txt in the name and make a blackboard artifact. # For an example, we will flag files with .txt in the name and make a blackboard artifact.
if file.getName().lower().endswith(".txt"): if file.getName().lower().endswith(".txt"):
@ -129,23 +127,18 @@ class SampleJythonFileIngestModule(FileIngestModule):
# Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of
# artifact. Refer to the developer docs for other examples. # artifact. Refer to the developer docs for other examples.
attrs = ArrayList() attrs = Arrays.asList(BlackboardAttribute(BlackboardAttribute.Type.TSK_SET_NAME,
attrs.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME,
SampleJythonFileIngestModuleFactory.moduleName, "Text Files")) SampleJythonFileIngestModuleFactory.moduleName, "Text Files"))
art = file.newAnalysisResult(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, self.LIKELY_NOTABLE_SCORE, None, "Text Files", None, attrs)
art = file.newAnalysisResult(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, Score.SCORE_LIKELY_NOTABLE,
None, "Text Files", None, attrs).getAnalysisResult()
try: try:
# index the artifact for keyword search # post the artifact for listeners of artifact events
blackboard.indexArtifact(art) blackboard.postArtifact(art, SampleJythonFileIngestModuleFactory.moduleName)
except Blackboard.BlackboardException as e: except Blackboard.BlackboardException as e:
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName()) self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
# Fire an event to notify the UI and others that there is a new artifact
IngestServices.getInstance().fireModuleDataEvent(
ModuleDataEvent(SampleJythonFileIngestModuleFactory.moduleName,
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None))
# For the example (this wouldn't be needed normally), we'll query the blackboard for data that was added # For the example (this wouldn't be needed normally), we'll query the blackboard for data that was added
# by other modules. We then iterate over its attributes. We'll just print them, but you would probably # by other modules. We then iterate over its attributes. We'll just print them, but you would probably
# want to do something with them. # want to do something with them.

View File

@ -67,10 +67,12 @@ class SampleGeneralReportModule(GeneralReportModuleAdapter):
return "sampleReport.txt" return "sampleReport.txt"
# TODO: Update this method to make a report # TODO: Update this method to make a report
# The 'baseReportDir' object being passed in is a string with the directory that reports are being stored in. Report should go into baseReportDir + getRelativeFilePath(). # The 'reportSettings' object being passed in is an instance of org.sleuthkit.autopsy.report.GeneralReportSettings.
# GeneralReportSettings.getReportDirectoryPath() is the directory that reports are being stored in.
# Report should go into GeneralReportSettings.getReportDirectoryPath() + getRelativeFilePath().
# The 'progressBar' object is of type ReportProgressPanel. # The 'progressBar' object is of type ReportProgressPanel.
# See: http://sleuthkit.org/autopsy/docs/api-docs/latest/classorg_1_1sleuthkit_1_1autopsy_1_1report_1_1_report_progress_panel.html # See: http://sleuthkit.org/autopsy/docs/api-docs/latest/classorg_1_1sleuthkit_1_1autopsy_1_1report_1_1_report_progress_panel.html
def generateReport(self, baseReportDir, progressBar): def generateReport(self, reportSettings, progressBar):
# For an example, we write a file with the number of files created in the past 2 weeks # For an example, we write a file with the number of files created in the past 2 weeks
# Configure progress bar for 2 tasks # Configure progress bar for 2 tasks
@ -95,7 +97,7 @@ class SampleGeneralReportModule(GeneralReportModuleAdapter):
progressBar.increment() progressBar.increment()
# Write the count to the report file. # Write the count to the report file.
fileName = os.path.join(baseReportDir, self.getRelativeFilePath()) fileName = os.path.join(reportSettings.getReportDirectoryPath(), self.getRelativeFilePath())
report = open(fileName, 'w') report = open(fileName, 'w')
report.write("file count = %d" % fileCount) report.write("file count = %d" % fileCount)
report.close() report.close()