mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 16:36:15 +00:00
Merged in develop and fixed conflicts
This commit is contained in:
commit
ad71309c8b
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Copyright 2013-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -29,6 +29,7 @@ import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactItem;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
@ -46,6 +47,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
})
|
||||
public class AddBlackboardArtifactTagAction extends AddTagAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// This class is a singleton to support multi-selection of nodes, since
|
||||
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
||||
// node in the array returns a reference to the same action object from Node.getActions(boolean).
|
||||
@ -82,8 +85,14 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
|
||||
* invocation of addTag(), we don't want to tag the same
|
||||
* BlackboardArtifact more than once, so we dedupe the
|
||||
* BlackboardArtifacts by stuffing them into a HashSet.
|
||||
*
|
||||
* RC (9/8/21): The documentation does NOT say that lookupAll() can
|
||||
* return duplicates. That would be very broken. What motivated this
|
||||
* "de-duping" ?
|
||||
*/
|
||||
selectedArtifacts.addAll(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||
for (BlackboardArtifactItem<?> item : Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactItem.class)) {
|
||||
selectedArtifacts.add(item.getTskContent());
|
||||
}
|
||||
} else {
|
||||
for (Content content : getContentToTag()) {
|
||||
if (content instanceof BlackboardArtifact) {
|
||||
@ -111,4 +120,10 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Copyright 2013-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -44,22 +44,29 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* An abstract base class for Actions that allow users to tag SleuthKit data
|
||||
* An abstract super class for Actions that allow users to tag Sleuth Kit data
|
||||
* model objects.
|
||||
*/
|
||||
abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String NO_COMMENT = "";
|
||||
private final Collection<Content> content = new HashSet<>();
|
||||
private final Collection<Content> contentObjsToTag;
|
||||
|
||||
/**
|
||||
* Constructs an instance of an abstract super class for Actions that allow
|
||||
* users to tag Sleuth Kit data model objects.
|
||||
*
|
||||
* @param menuText The menu item text.
|
||||
*/
|
||||
AddTagAction(String menuText) {
|
||||
super(menuText);
|
||||
contentObjsToTag = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JMenuItem getPopupPresenter() {
|
||||
content.clear();
|
||||
contentObjsToTag.clear();
|
||||
return new TagMenu();
|
||||
}
|
||||
|
||||
@ -70,7 +77,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
* @return The specified content for this action.
|
||||
*/
|
||||
Collection<Content> getContentToTag() {
|
||||
return Collections.unmodifiableCollection(content);
|
||||
return Collections.unmodifiableCollection(contentObjsToTag);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,8 +90,8 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
* apply to the Content specified.
|
||||
*/
|
||||
public JMenuItem getMenuForContent(Collection<? extends Content> contentToTag) {
|
||||
content.clear();
|
||||
content.addAll(contentToTag);
|
||||
contentObjsToTag.clear();
|
||||
contentObjsToTag.addAll(contentToTag);
|
||||
return new TagMenu();
|
||||
}
|
||||
|
||||
@ -111,6 +118,11 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
*/
|
||||
abstract protected void addTag(TagName tagName, String comment);
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instances of this class implement a context menu user interface for
|
||||
* creating or selecting a tag name for a tag and specifying an optional tag
|
||||
@ -126,7 +138,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
super(getActionDisplayName());
|
||||
|
||||
// Get the current set of tag names.
|
||||
Map<String, TagName> tagNamesMap = null;
|
||||
Map<String, TagName> tagNamesMap;
|
||||
List<String> standardTagNames = TagsManager.getStandardTagNames();
|
||||
Map<String, JMenu> tagSetMenuMap = new HashMap<>();
|
||||
List<JMenuItem> standardTagMenuitems = new ArrayList<>();
|
||||
@ -240,5 +252,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
|
||||
return tagNameItem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.centralrepository;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
@ -64,7 +65,13 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction {
|
||||
correlationAttributeInstance = CorrelationAttributeUtil.getCorrAttrForFile(file);
|
||||
if (correlationAttributeInstance == null) {
|
||||
addToDatabase = true;
|
||||
correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttrFromFile(file);
|
||||
final List<CorrelationAttributeInstance> md5CorrelationAttr = CorrelationAttributeUtil.makeCorrAttrsForSearch(file);
|
||||
if (!md5CorrelationAttr.isEmpty()) {
|
||||
//for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852
|
||||
correlationAttributeInstance = md5CorrelationAttr.get(0);
|
||||
} else {
|
||||
correlationAttributeInstance = null;
|
||||
}
|
||||
}
|
||||
if (file.getSize() == 0) {
|
||||
putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentEmptyFile());
|
||||
|
@ -53,7 +53,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.OsAccount;
|
||||
import org.sleuthkit.datamodel.OsAccountInstance;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
@ -116,7 +115,7 @@ public final class OtherOccurrences {
|
||||
// correlate on blackboard artifact attributes if they exist and supported
|
||||
BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
|
||||
if (bbArtifact != null && CentralRepository.isEnabled()) {
|
||||
ret.addAll(CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact));
|
||||
ret.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact));
|
||||
}
|
||||
|
||||
// we can correlate based on the MD5 if it is enabled
|
||||
|
@ -18,18 +18,18 @@ CentralRepositoryService.serviceName=Central Repository Service
|
||||
CorrelationAttributeInstance.invalidName.message=Invalid database table name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'.
|
||||
CorrelationAttributeInstance.nullName.message=Database name is null.
|
||||
CorrelationAttributeUtil.emailaddresses.text=Email Addresses
|
||||
CorrelationType.DOMAIN.displayName=Domains
|
||||
CorrelationType.EMAIL.displayName=Email Addresses
|
||||
CorrelationType.FILES.displayName=Files
|
||||
CorrelationType.DOMAIN.displayName=Domain
|
||||
CorrelationType.EMAIL.displayName=Email Address
|
||||
CorrelationType.FILES.displayName=File MD5
|
||||
CorrelationType.ICCID.displayName=ICCID Number
|
||||
CorrelationType.IMEI.displayName=IMEI Number
|
||||
CorrelationType.IMSI.displayName=IMSI Number
|
||||
CorrelationType.MAC.displayName=MAC Addresses
|
||||
CorrelationType.MAC.displayName=MAC Address
|
||||
CorrelationType.OS_ACCOUNT.displayName=Os Account
|
||||
CorrelationType.PHONE.displayName=Phone Numbers
|
||||
CorrelationType.PROG_NAME.displayName=Installed Programs
|
||||
CorrelationType.SSID.displayName=Wireless Networks
|
||||
CorrelationType.USBID.displayName=USB Devices
|
||||
CorrelationType.PHONE.displayName=Phone Number
|
||||
CorrelationType.PROG_NAME.displayName=Installed Program
|
||||
CorrelationType.SSID.displayName=Wireless Network
|
||||
CorrelationType.USBID.displayName=USB Device
|
||||
EamArtifactInstances.knownStatus.bad=Bad
|
||||
EamArtifactInstances.knownStatus.known=Known
|
||||
EamArtifactInstances.knownStatus.unknown=Unknown
|
||||
|
@ -282,7 +282,7 @@ final public class CorrelationAttributeNormalizer {
|
||||
if (imsiWithoutSeperators.matches(validImsiRegex)) {
|
||||
return imsiWithoutSeperators;
|
||||
} else {
|
||||
throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
|
||||
throw new CorrelationAttributeNormalizationException("Data provided was not a valid IMSI. : " + data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,7 +306,7 @@ final public class CorrelationAttributeNormalizer {
|
||||
if (macWithoutSeperators.matches(validMacRegex)) {
|
||||
return macWithoutSeperators;
|
||||
} else {
|
||||
throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
|
||||
throw new CorrelationAttributeNormalizationException("Data provided was not a valid MAC address. : " + data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,7 +335,7 @@ final public class CorrelationAttributeNormalizer {
|
||||
if (imeiWithoutSeperators.matches(validImeiRegex)) {
|
||||
return imeiWithoutSeperators;
|
||||
} else {
|
||||
throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
|
||||
throw new CorrelationAttributeNormalizationException("Data provided was not a valid IMEI. : " + data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2017-2020 Basis Technology Corp.
|
||||
* Copyright 2017-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.Cent
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -41,7 +42,6 @@ import org.sleuthkit.datamodel.DataArtifact;
|
||||
import org.sleuthkit.datamodel.HashUtility;
|
||||
import org.sleuthkit.datamodel.InvalidAccountIDException;
|
||||
import org.sleuthkit.datamodel.OsAccount;
|
||||
import org.sleuthkit.datamodel.OsAccountInstance;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@ -55,7 +55,7 @@ public class CorrelationAttributeUtil {
|
||||
private static final List<String> domainsToSkip = Arrays.asList("localhost", "127.0.0.1");
|
||||
|
||||
// artifact ids that specifically have a TSK_DOMAIN attribute that should be handled by CR
|
||||
private static Set<Integer> DOMAIN_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
private static final Set<Integer> DOMAIN_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(),
|
||||
@ -69,7 +69,7 @@ public class CorrelationAttributeUtil {
|
||||
* for the email address correlation attribute type. This string is
|
||||
* duplicated in the CorrelationAttributeInstance class.
|
||||
*
|
||||
* TODO (Jira-6088): We should not have multiple deifnitions of this string.
|
||||
* TODO (Jira-6088): We should not have multiple definitions of this string.
|
||||
*
|
||||
* @return The display name of the email address correlation attribute type.
|
||||
*/
|
||||
@ -78,56 +78,45 @@ public class CorrelationAttributeUtil {
|
||||
return Bundle.CorrelationAttributeUtil_emailaddresses_text();
|
||||
}
|
||||
|
||||
// Defines which artifact types act as the sources for CR data.
|
||||
// Most notably, does not include KEYWORD HIT, CALLLOGS, MESSAGES, CONTACTS
|
||||
// TSK_INTERESTING_ARTIFACT_HIT (See JIRA-6129 for more details on the
|
||||
// interesting artifact hit).
|
||||
// IMPORTANT: This set should be updated for new artifacts types that need to
|
||||
// be inserted into the CR.
|
||||
private static final Set<Integer> SOURCE_TYPES_FOR_CR_INSERT = new HashSet<Integer>() {
|
||||
{
|
||||
addAll(DOMAIN_ARTIFACT_TYPE_IDS);
|
||||
|
||||
add(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID());
|
||||
add(ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID());
|
||||
private static List<CorrelationAttributeInstance> makeCorrAttrsToSave(DataArtifact artifact) {
|
||||
int artifactTypeID = artifact.getArtifactTypeID();
|
||||
//The account fields in these types are expected to be saved in a TSK_ACCOUNT artifact, which will be processed
|
||||
if (artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes zero to many correlation attribute instances from the attributes of
|
||||
* artifacts that have correlatable data. The intention of this method is to
|
||||
* use the results to save to the CR, not to correlate with them. If you
|
||||
* want to correlate, please use makeCorrAttrsForCorrelation. An artifact
|
||||
* that can have correlatable data != An artifact that should be the source
|
||||
* of data in the CR, so results may be un-necessarily incomplete.
|
||||
*
|
||||
* @param artifact An artifact.
|
||||
*
|
||||
* @return A list, possibly empty, of correlation attribute instances for
|
||||
* the artifact.
|
||||
*/
|
||||
public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(BlackboardArtifact artifact) {
|
||||
if (SOURCE_TYPES_FOR_CR_INSERT.contains(artifact.getArtifactTypeID())) {
|
||||
// Restrict the correlation attributes to use for saving.
|
||||
// The artifacts which are suitable for saving are a subset of the
|
||||
// artifacts that are suitable for correlating.
|
||||
return makeCorrAttrsForCorrelation(artifact);
|
||||
}
|
||||
// Return an empty collection.
|
||||
return new ArrayList<>();
|
||||
return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes zero to many correlation attribute instances from the attributes of
|
||||
* artifacts that have correlatable data. The intention of this method is to
|
||||
* content objects that have correlatable data. The intention of this method
|
||||
* is to use the results to save to the CR, not to correlate with them. If
|
||||
* you want to correlate, please use makeCorrAttrsForSearch. An artifact
|
||||
* that can have correlatable data != An artifact that should be the source
|
||||
* of data in the CR, so results may be un-necessarily incomplete.
|
||||
*
|
||||
* @param content A Content object.
|
||||
*
|
||||
* @return A list, possibly empty, of correlation attribute instances for
|
||||
* the content.
|
||||
*/
|
||||
public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(Content content) {
|
||||
if (content instanceof DataArtifact) {
|
||||
return makeCorrAttrsToSave((DataArtifact) content);
|
||||
} else if (content instanceof AnalysisResult) {
|
||||
//AnalysisResults should already have the correlation attributes they are correlating on saved
|
||||
//This check replaces the check explicitly excluding keyword hits and interesting items that existed prior to the AnalysisResult designation
|
||||
return new ArrayList<>();
|
||||
} else {
|
||||
return makeCorrAttrsForSearch(content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes zero to many correlation attribute instances from the attributes of
|
||||
* content that have correlatable data. The intention of this method is to
|
||||
* use the results to correlate with, not to save. If you want to save,
|
||||
* please use makeCorrAttrsToSave. An artifact that can have correlatable
|
||||
* data != An artifact that should be the source of data in the CR, so
|
||||
@ -144,96 +133,126 @@ public class CorrelationAttributeUtil {
|
||||
* whether receiving a null return value is an error or not, plus null
|
||||
* checking is easy to forget, while catching exceptions is enforced.
|
||||
*
|
||||
* @param artifact An artifact.
|
||||
* @param Content A Content object.
|
||||
*
|
||||
* @return A list, possibly empty, of correlation attribute instances for
|
||||
* the artifact.
|
||||
* the content.
|
||||
*/
|
||||
public static List<CorrelationAttributeInstance> makeCorrAttrsForCorrelation(BlackboardArtifact artifact) {
|
||||
public static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(Content content) {
|
||||
if (content instanceof DataArtifact) {
|
||||
return makeCorrAttrsForSearch((DataArtifact) content);
|
||||
} else if (content instanceof AnalysisResult) {
|
||||
return makeCorrAttrsForSearch((AnalysisResult) content);
|
||||
} else if (content instanceof AbstractFile) {
|
||||
return makeCorrAttrsForSearch((AbstractFile) content);
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(AnalysisResult analysisResult) {
|
||||
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
|
||||
try {
|
||||
BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact);
|
||||
if (sourceArtifact != null) {
|
||||
|
||||
List<BlackboardAttribute> attributes = sourceArtifact.getAttributes();
|
||||
|
||||
int artifactTypeID = sourceArtifact.getArtifactTypeID();
|
||||
if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||
BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
|
||||
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, attributes);
|
||||
}
|
||||
} else if (DOMAIN_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) {
|
||||
BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN));
|
||||
if ((domainAttr != null)
|
||||
&& !domainsToSkip.contains(domainAttr.getValueString())) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes);
|
||||
}
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) {
|
||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID());
|
||||
Content dataSource = sourceContent.getDataSource();
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) {
|
||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID());
|
||||
Content dataSource = sourceContent.getDataSource();
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
|
||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID());
|
||||
Content dataSource = sourceContent.getDataSource();
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) {
|
||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID());
|
||||
Content dataSource = sourceContent.getDataSource();
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
||||
makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID()) {
|
||||
BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH));
|
||||
String pathAttrString = null;
|
||||
if (setNameAttr != null) {
|
||||
pathAttrString = setNameAttr.getValueString();
|
||||
}
|
||||
if (pathAttrString != null && !pathAttrString.isEmpty()) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes);
|
||||
} else {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes);
|
||||
}
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
|
||||
makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, sourceArtifact, attributes);
|
||||
int artifactTypeID = analysisResult.getArtifactTypeID();
|
||||
if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||
BlackboardAttribute setNameAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_SET_NAME);
|
||||
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, analysisResult, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, analysisResult.getAttributes());
|
||||
}
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
||||
BlackboardAttribute assocArtifactAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_ASSOCIATED_ARTIFACT);
|
||||
if (assocArtifactAttr != null) {
|
||||
BlackboardArtifact sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong());
|
||||
return CorrelationAttributeUtil.makeCorrAttrsForSearch(sourceArtifact);
|
||||
}
|
||||
}
|
||||
correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(analysisResult.getParent()));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get information regarding correlation attributes from AnalysisResult", ex);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Attempted to retrieve correlation attributes for search with no currently open case.", ex);
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get correlation type from central repository.", ex);
|
||||
}
|
||||
return correlationAttrs;
|
||||
}
|
||||
|
||||
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(DataArtifact artifact) {
|
||||
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
|
||||
try {
|
||||
|
||||
List<BlackboardAttribute> attributes = artifact.getAttributes();
|
||||
|
||||
int artifactTypeID = artifact.getArtifactTypeID();
|
||||
if (DOMAIN_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) {
|
||||
BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN));
|
||||
if ((domainAttr != null)
|
||||
&& !domainsToSkip.contains(domainAttr.getValueString())) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes);
|
||||
}
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) {
|
||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
Content dataSource = sourceContent.getDataSource();
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) {
|
||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
Content dataSource = sourceContent.getDataSource();
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
|
||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
Content dataSource = sourceContent.getDataSource();
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) {
|
||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
Content dataSource = sourceContent.getDataSource();
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID,
|
||||
attributes, sourceContent, dataSource);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
||||
makeCorrAttrFromAcctArtifact(correlationAttrs, artifact);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID()) {
|
||||
BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH));
|
||||
String pathAttrString = null;
|
||||
if (setNameAttr != null) {
|
||||
pathAttrString = setNameAttr.getValueString();
|
||||
}
|
||||
if (pathAttrString != null && !pathAttrString.isEmpty()) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes);
|
||||
} else {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes);
|
||||
}
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
|
||||
makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, artifact, attributes);
|
||||
}
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error normalizing correlation attribute (%s)", artifact), ex); // NON-NLS
|
||||
@ -292,8 +311,6 @@ public class CorrelationAttributeUtil {
|
||||
*/
|
||||
private static void makeCorrAttrsFromCommunicationArtifacts(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact artifact,
|
||||
List<BlackboardAttribute> attributes) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException {
|
||||
CorrelationAttributeInstance corrAttr = null;
|
||||
|
||||
/*
|
||||
* Extract the phone number from the artifact attribute.
|
||||
*/
|
||||
@ -305,56 +322,19 @@ public class CorrelationAttributeUtil {
|
||||
} else if (null != getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
|
||||
value = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalize the phone number.
|
||||
*/
|
||||
if (value != null
|
||||
&& CorrelationAttributeNormalizer.isValidPhoneNumber(value)) {
|
||||
|
||||
value = CorrelationAttributeNormalizer.normalizePhone(value);
|
||||
corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value);
|
||||
CorrelationAttributeInstance corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value);
|
||||
if (corrAttr != null) {
|
||||
corrAttrInstances.add(corrAttr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the associated artifact of a "meta-artifact" such as an "interesting
|
||||
* artifact hit" or "previously seen" artifact.
|
||||
*
|
||||
* @param artifact An artifact.
|
||||
*
|
||||
* @return The associated artifact if the input artifact is a
|
||||
* "meta-artifact", otherwise the input artifact.
|
||||
*
|
||||
* @throws NoCurrentCaseException If there is no open case.
|
||||
* @throws TskCoreException If there is an error querying thew case
|
||||
* database.
|
||||
*/
|
||||
private static BlackboardArtifact getCorrAttrSourceArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException {
|
||||
BlackboardArtifact sourceArtifact = null;
|
||||
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) {
|
||||
BlackboardAttribute assocArtifactAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
||||
if (assocArtifactAttr != null) {
|
||||
sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong());
|
||||
}
|
||||
} else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID() == artifact.getArtifactTypeID()
|
||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE.getTypeID() == artifact.getArtifactTypeID()
|
||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_UNSEEN.getTypeID() == artifact.getArtifactTypeID()) {
|
||||
Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
if (content instanceof DataArtifact) {
|
||||
sourceArtifact = (BlackboardArtifact) content;
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceArtifact == null) {
|
||||
sourceArtifact = artifact;
|
||||
}
|
||||
return sourceArtifact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a correlation attribute instance for an account artifact.
|
||||
*
|
||||
@ -506,21 +486,21 @@ public class CorrelationAttributeUtil {
|
||||
*/
|
||||
private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value,
|
||||
Content sourceContent, Content dataSource) {
|
||||
Content srcContent = sourceContent;
|
||||
Content dataSrc = dataSource;
|
||||
try {
|
||||
|
||||
if (sourceContent == null) {
|
||||
sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
if (srcContent == null) {
|
||||
srcContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
}
|
||||
if (null == sourceContent) {
|
||||
if (null == srcContent) {
|
||||
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load content with ID: {1} associated with artifact with ID: {2}",
|
||||
new Object[]{correlationType.getDisplayName(), artifact.getObjectID(), artifact.getId()}); // NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
||||
if (dataSource == null) {
|
||||
dataSource = sourceContent.getDataSource();
|
||||
if (dataSrc == null) {
|
||||
dataSrc = srcContent.getDataSource();
|
||||
}
|
||||
if (dataSource == null) {
|
||||
if (dataSrc == null) {
|
||||
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load data source for content with ID: {1}",
|
||||
new Object[]{correlationType.getDisplayName(), artifact.getObjectID()}); // NON-NLS
|
||||
return null;
|
||||
@ -532,24 +512,24 @@ public class CorrelationAttributeUtil {
|
||||
correlationType,
|
||||
value,
|
||||
correlationCase,
|
||||
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource),
|
||||
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSrc),
|
||||
"",
|
||||
"",
|
||||
TskData.FileKnown.UNKNOWN,
|
||||
sourceContent.getId());
|
||||
srcContent.getId());
|
||||
} else {
|
||||
if (!(sourceContent instanceof AbstractFile)) {
|
||||
if (!(srcContent instanceof AbstractFile)) {
|
||||
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Source content of artifact with ID: {1} is not an AbstractFile",
|
||||
new Object[]{correlationType.getDisplayName(), artifact.getId()});
|
||||
return null;
|
||||
}
|
||||
AbstractFile bbSourceFile = (AbstractFile) sourceContent;
|
||||
AbstractFile bbSourceFile = (AbstractFile) srcContent;
|
||||
|
||||
return new CorrelationAttributeInstance(
|
||||
correlationType,
|
||||
value,
|
||||
correlationCase,
|
||||
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource),
|
||||
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSrc),
|
||||
bbSourceFile.getParentPath() + bbSourceFile.getName(),
|
||||
"",
|
||||
TskData.FileKnown.UNKNOWN,
|
||||
@ -615,8 +595,12 @@ public class CorrelationAttributeUtil {
|
||||
}
|
||||
}
|
||||
|
||||
// @@@ BC: This seems like it should go into a DB-specific class because it is
|
||||
// much different from the other methods in this class. It is going to the DB for data.
|
||||
/**
|
||||
* Gets the correlation attribute instance for a file.
|
||||
* Gets the correlation attribute instance for a file. This method goes to
|
||||
* the CR to get an actual instance. It does not simply package the data
|
||||
* from file into a generic instance object.
|
||||
*
|
||||
* @param file The file.
|
||||
*
|
||||
@ -694,7 +678,8 @@ public class CorrelationAttributeUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a correlation attribute instance for a file.
|
||||
* Makes a correlation attribute instance for a file. Will include the
|
||||
* specific object ID.
|
||||
*
|
||||
* IMPORTANT: The correlation attribute instance is NOT added to the central
|
||||
* repository by this method.
|
||||
@ -711,23 +696,23 @@ public class CorrelationAttributeUtil {
|
||||
*
|
||||
* @return The correlation attribute instance or null, if an error occurred.
|
||||
*/
|
||||
public static CorrelationAttributeInstance makeCorrAttrFromFile(AbstractFile file) {
|
||||
|
||||
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(AbstractFile file) {
|
||||
List<CorrelationAttributeInstance> fileTypeList = new ArrayList<>(); // will be an empty or single element list as was decided in 7852
|
||||
if (!isSupportedAbstractFileType(file)) {
|
||||
return null;
|
||||
return fileTypeList;
|
||||
}
|
||||
|
||||
// We need a hash to make the correlation artifact instance.
|
||||
String md5 = file.getMd5Hash();
|
||||
if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) {
|
||||
return null;
|
||||
return fileTypeList;
|
||||
}
|
||||
|
||||
try {
|
||||
CorrelationAttributeInstance.Type filesType = CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID);
|
||||
|
||||
CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows());
|
||||
return new CorrelationAttributeInstance(
|
||||
fileTypeList.add(new CorrelationAttributeInstance(
|
||||
filesType,
|
||||
file.getMd5Hash(),
|
||||
correlationCase,
|
||||
@ -735,21 +720,17 @@ public class CorrelationAttributeUtil {
|
||||
file.getParentPath() + file.getName(),
|
||||
"",
|
||||
TskData.FileKnown.UNKNOWN,
|
||||
file.getId());
|
||||
|
||||
file.getId()));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS
|
||||
return null;
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS
|
||||
return null;
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error creating correlation attribute instance (%s)", file), ex); // NON-NLS
|
||||
return null;
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS
|
||||
return null;
|
||||
}
|
||||
return fileTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,6 +30,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
@ -65,8 +66,10 @@ import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.Blackboard;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE;
|
||||
import org.sleuthkit.datamodel.OsAccount;
|
||||
import org.sleuthkit.datamodel.OsAccountInstance;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
@ -311,18 +314,18 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
* Sets the known status for the correlation attribute instance for the
|
||||
* given abstract file.
|
||||
*
|
||||
* @param af The abstract file for which to set the correlation
|
||||
* attribute instance.
|
||||
* @param af The abstract file for which to set the correlation
|
||||
* attribute instance.
|
||||
* @param knownStatus The new known status for the correlation attribute
|
||||
* instance.
|
||||
* instance.
|
||||
*/
|
||||
private void setContentKnownStatus(AbstractFile af, TskData.FileKnown knownStatus) {
|
||||
final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile(af);
|
||||
|
||||
if (eamArtifact != null) {
|
||||
final List<CorrelationAttributeInstance> md5CorrelationAttr = CorrelationAttributeUtil.makeCorrAttrsForSearch(af);
|
||||
if (!md5CorrelationAttr.isEmpty()) {
|
||||
//for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852
|
||||
// send update to Central Repository db
|
||||
try {
|
||||
dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
|
||||
dbManager.setAttributeInstanceKnownStatus(md5CorrelationAttr.get(0), knownStatus);
|
||||
} catch (CentralRepoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
|
||||
}
|
||||
@ -407,7 +410,7 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
* for the item. If there are, set known status as notable. If not set
|
||||
* status as unknown.
|
||||
*
|
||||
* @param content The content for the tag that was added or deleted.
|
||||
* @param content The content for the tag that was added or deleted.
|
||||
* @param bbArtifact The artifact for the tag that was added or deleted.
|
||||
*/
|
||||
private void handleTagChange(Content content, BlackboardArtifact bbArtifact) {
|
||||
@ -452,11 +455,11 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
* Sets the known status of a blackboard artifact in the central
|
||||
* repository.
|
||||
*
|
||||
* @param bbArtifact The blackboard artifact to set known status.
|
||||
* @param bbArtifact The blackboard artifact to set known status.
|
||||
* @param knownStatus The new known status.
|
||||
*/
|
||||
private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) {
|
||||
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact);
|
||||
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact);
|
||||
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
|
||||
try {
|
||||
dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
|
||||
@ -528,7 +531,7 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
if (!hasTagWithConflictingKnownStatus) {
|
||||
//Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed
|
||||
//with the initial set of correlation attributes this should be a single correlation attribute
|
||||
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbTag.getArtifact());
|
||||
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbTag.getArtifact());
|
||||
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
|
||||
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
|
||||
}
|
||||
@ -566,9 +569,10 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
if (!hasTagWithConflictingKnownStatus) {
|
||||
Content taggedContent = contentTag.getContent();
|
||||
if (taggedContent instanceof AbstractFile) {
|
||||
final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile((AbstractFile) taggedContent);
|
||||
if (eamArtifact != null) {
|
||||
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
|
||||
final List<CorrelationAttributeInstance> eamArtifact = CorrelationAttributeUtil.makeCorrAttrsForSearch((AbstractFile) taggedContent);
|
||||
if (!eamArtifact.isEmpty()) {
|
||||
//for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852
|
||||
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact.get(0), tagName.getKnownStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -702,22 +706,45 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
|
||||
// Look up and create artifacts for previously seen accounts if requested
|
||||
if (IngestEventsListener.isFlagSeenDevices()) {
|
||||
List<CorrelationAttributeInstance> previousOccurences = dbManager.getArtifactInstancesByTypeValue(CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID), correlationAttributeInstance.getCorrelationValue());
|
||||
CorrelationAttributeInstance.Type osAcctType = CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID);
|
||||
List<CorrelationAttributeInstance> previousOccurences = dbManager.getArtifactInstancesByTypeValue(osAcctType, correlationAttributeInstance.getCorrelationValue());
|
||||
for (CorrelationAttributeInstance instance : previousOccurences) {
|
||||
if (!instance.getCorrelationCase().getCaseUUID().equals(correlationAttributeInstance.getCorrelationCase().getCaseUUID())) {
|
||||
SleuthkitCase tskCase = osAccount.getSleuthkitCase();
|
||||
Blackboard blackboard = tskCase.getBlackboard();
|
||||
|
||||
List<String> caseDisplayNames = dbManager.getListCasesHavingArtifactInstances(osAcctType, correlationAttributeInstance.getCorrelationValue());
|
||||
|
||||
// calculate score
|
||||
Score score;
|
||||
int numCases = caseDisplayNames.size();
|
||||
if (numCases <= IngestEventsListener.MAX_NUM_PREVIOUS_CASES_FOR_LIKELY_NOTABLE_SCORE) {
|
||||
score = Score.SCORE_LIKELY_NOTABLE;
|
||||
} else if (numCases > IngestEventsListener.MAX_NUM_PREVIOUS_CASES_FOR_LIKELY_NOTABLE_SCORE && numCases <= IngestEventsListener.MAX_NUM_PREVIOUS_CASES_FOR_PREV_SEEN_ARTIFACT_CREATION) {
|
||||
score = Score.SCORE_NONE;
|
||||
} else {
|
||||
// don't make an Analysis Result, the artifact is too common.
|
||||
continue;
|
||||
}
|
||||
|
||||
String prevCases = caseDisplayNames.stream().distinct().collect(Collectors.joining(","));
|
||||
String justification = "Previously seen in cases " + prevCases;
|
||||
Collection<BlackboardAttribute> attributesForNewArtifact = Arrays.asList(
|
||||
new BlackboardAttribute(
|
||||
TSK_SET_NAME, MODULE_NAME,
|
||||
Bundle.CaseEventsListener_prevExists_text()),
|
||||
new BlackboardAttribute(
|
||||
TSK_COMMENT, MODULE_NAME,
|
||||
Bundle.CaseEventsListener_prevCaseComment_text()));
|
||||
TSK_CORRELATION_TYPE, MODULE_NAME,
|
||||
osAcctType.getDisplayName()),
|
||||
new BlackboardAttribute(
|
||||
TSK_CORRELATION_VALUE, MODULE_NAME,
|
||||
correlationAttributeInstance.getCorrelationValue()),
|
||||
new BlackboardAttribute(
|
||||
TSK_OTHER_CASES, MODULE_NAME,
|
||||
prevCases));
|
||||
BlackboardArtifact newAnalysisResult = osAccount.newAnalysisResult(
|
||||
BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE,
|
||||
null, Bundle.CaseEventsListener_prevExists_text(), null, attributesForNewArtifact, osAccountInstance.getDataSource().getId()).getAnalysisResult();
|
||||
BlackboardArtifact.Type.TSK_PREVIOUSLY_SEEN, score,
|
||||
null, Bundle.CaseEventsListener_prevExists_text(), justification, attributesForNewArtifact, osAccountInstance.getDataSource().getId()).getAnalysisResult();
|
||||
try {
|
||||
// index the artifact for keyword search
|
||||
blackboard.postArtifact(newAnalysisResult, MODULE_NAME);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2017-2020 Basis Technology Corp.
|
||||
* Copyright 2017-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -46,16 +47,15 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Blackboard;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadUtils;
|
||||
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES;
|
||||
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisEvent;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Listen for ingest events and update entries in the Central Repository
|
||||
@ -70,6 +71,7 @@ import org.sleuthkit.datamodel.Score;
|
||||
*/
|
||||
@NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Central Repository"})
|
||||
public class IngestEventsListener {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName());
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
|
||||
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED);
|
||||
@ -78,12 +80,16 @@ public class IngestEventsListener {
|
||||
private static boolean flagNotableItems;
|
||||
private static boolean flagSeenDevices;
|
||||
private static boolean createCrProperties;
|
||||
private static boolean flagUniqueArtifacts;
|
||||
private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d";
|
||||
private final ExecutorService jobProcessingExecutor;
|
||||
private final PropertyChangeListener pcl1 = new IngestModuleEventListener();
|
||||
private final PropertyChangeListener pcl2 = new IngestJobEventListener();
|
||||
final Collection<String> recentlyAddedCeArtifacts = new LinkedHashSet<>();
|
||||
|
||||
static final int MAX_NUM_PREVIOUS_CASES_FOR_LIKELY_NOTABLE_SCORE = 10;
|
||||
static final int MAX_NUM_PREVIOUS_CASES_FOR_PREV_SEEN_ARTIFACT_CREATION = 20;
|
||||
|
||||
public IngestEventsListener() {
|
||||
jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(INGEST_EVENT_THREAD_NAME).build());
|
||||
}
|
||||
@ -189,6 +195,24 @@ public class IngestEventsListener {
|
||||
flagSeenDevices = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the listener to flag unique apps or not.
|
||||
*
|
||||
* @param value True to flag unique apps; otherwise false.
|
||||
*/
|
||||
public synchronized static void setFlagUniqueArtifacts(boolean value) {
|
||||
flagUniqueArtifacts = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are unique apps being flagged?
|
||||
*
|
||||
* @return True if flagging unique apps; otherwise false.
|
||||
*/
|
||||
public synchronized static boolean isFlagUniqueArtifacts() {
|
||||
return flagUniqueArtifacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the listener to create correlation properties
|
||||
*
|
||||
@ -199,7 +223,7 @@ public class IngestEventsListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an Interesting Item artifact based on a new artifact being
|
||||
* Make a "previously seen" artifact based on a new artifact being
|
||||
* previously seen.
|
||||
*
|
||||
* @param originalArtifact Original artifact that we want to flag
|
||||
@ -208,25 +232,31 @@ public class IngestEventsListener {
|
||||
*/
|
||||
@NbBundle.Messages({"IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
|
||||
"IngestEventsListener.prevCaseComment.text=Previous Case: "})
|
||||
static private void makeAndPostPreviousNotableArtifact(BlackboardArtifact originalArtifact, List<String> caseDisplayNames) {
|
||||
Collection<BlackboardAttribute> attributesForNewArtifact = Arrays.asList(
|
||||
static private void makeAndPostPreviousNotableArtifact(BlackboardArtifact originalArtifact, List<String> caseDisplayNames,
|
||||
CorrelationAttributeInstance.Type aType, String value) {
|
||||
String prevCases = caseDisplayNames.stream().distinct().collect(Collectors.joining(","));
|
||||
String justification = "Previously marked as notable in cases " + prevCases;
|
||||
Collection<BlackboardAttribute> attributesForNewArtifact = Arrays.asList(new BlackboardAttribute(
|
||||
TSK_SET_NAME, MODULE_NAME,
|
||||
Bundle.IngestEventsListener_prevTaggedSet_text()),
|
||||
new BlackboardAttribute(
|
||||
TSK_SET_NAME, MODULE_NAME,
|
||||
Bundle.IngestEventsListener_prevTaggedSet_text()),
|
||||
TSK_CORRELATION_TYPE, MODULE_NAME,
|
||||
aType.getDisplayName()),
|
||||
new BlackboardAttribute(
|
||||
TSK_COMMENT, MODULE_NAME,
|
||||
Bundle.IngestEventsListener_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(","))),
|
||||
TSK_CORRELATION_VALUE, MODULE_NAME,
|
||||
value),
|
||||
new BlackboardAttribute(
|
||||
TSK_ASSOCIATED_ARTIFACT, MODULE_NAME,
|
||||
originalArtifact.getArtifactID()));
|
||||
makeAndPostInterestingArtifact(originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevTaggedSet_text());
|
||||
TSK_OTHER_CASES, MODULE_NAME,
|
||||
prevCases));
|
||||
makeAndPostArtifact(BlackboardArtifact.Type.TSK_PREVIOUSLY_NOTABLE, originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevTaggedSet_text(),
|
||||
Score.SCORE_NOTABLE, justification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Interesting Artifact hit for a device which was previously seen
|
||||
* in the central repository.
|
||||
* Create a "previously seen" hit for a device which was previously seen
|
||||
* in the central repository. NOTE: Artifacts that are too common will be skipped.
|
||||
*
|
||||
* @param originalArtifact the artifact to create the interesting item for
|
||||
* @param originalArtifact the artifact to create the "previously seen" item for
|
||||
* @param caseDisplayNames the case names the artifact was previously seen
|
||||
* in
|
||||
*/
|
||||
@ -234,45 +264,85 @@ public class IngestEventsListener {
|
||||
"# {0} - typeName",
|
||||
"# {1} - count",
|
||||
"IngestEventsListener.prevCount.text=Number of previous {0}: {1}"})
|
||||
static private void makeAndPostPreviousSeenArtifact(BlackboardArtifact originalArtifact, List<String> caseDisplayNames) {
|
||||
static private void makeAndPostPreviousSeenArtifact(BlackboardArtifact originalArtifact, List<String> caseDisplayNames,
|
||||
CorrelationAttributeInstance.Type aType, String value) {
|
||||
|
||||
// calculate score
|
||||
Score score;
|
||||
int numCases = caseDisplayNames.size();
|
||||
if (numCases <= MAX_NUM_PREVIOUS_CASES_FOR_LIKELY_NOTABLE_SCORE) {
|
||||
score = Score.SCORE_LIKELY_NOTABLE;
|
||||
} else if (numCases > MAX_NUM_PREVIOUS_CASES_FOR_LIKELY_NOTABLE_SCORE && numCases <= MAX_NUM_PREVIOUS_CASES_FOR_PREV_SEEN_ARTIFACT_CREATION) {
|
||||
score = Score.SCORE_NONE;
|
||||
} else {
|
||||
// don't make an Analysis Result, the artifact is too common.
|
||||
return;
|
||||
}
|
||||
|
||||
String prevCases = caseDisplayNames.stream().distinct().collect(Collectors.joining(","));
|
||||
String justification = "Previously seen in cases " + prevCases;
|
||||
Collection<BlackboardAttribute> attributesForNewArtifact = Arrays.asList(new BlackboardAttribute(
|
||||
TSK_SET_NAME, MODULE_NAME,
|
||||
Bundle.IngestEventsListener_prevExists_text()),
|
||||
new BlackboardAttribute(
|
||||
TSK_COMMENT, MODULE_NAME,
|
||||
Bundle.IngestEventsListener_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(","))),
|
||||
TSK_CORRELATION_TYPE, MODULE_NAME,
|
||||
aType.getDisplayName()),
|
||||
new BlackboardAttribute(
|
||||
TSK_ASSOCIATED_ARTIFACT, MODULE_NAME,
|
||||
originalArtifact.getArtifactID()));
|
||||
makeAndPostInterestingArtifact(originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevExists_text());
|
||||
TSK_CORRELATION_VALUE, MODULE_NAME,
|
||||
value),
|
||||
new BlackboardAttribute(
|
||||
TSK_OTHER_CASES, MODULE_NAME,
|
||||
prevCases));
|
||||
makeAndPostArtifact(BlackboardArtifact.Type.TSK_PREVIOUSLY_SEEN, originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevExists_text(),
|
||||
score, justification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a "previously unseen" hit for an application which was never seen in
|
||||
* the central repository.
|
||||
*
|
||||
* @param originalArtifact the artifact to create the "previously unseen" item
|
||||
* for
|
||||
*/
|
||||
static private void makeAndPostPreviouslyUnseenArtifact(BlackboardArtifact originalArtifact, CorrelationAttributeInstance.Type aType, String value) {
|
||||
Collection<BlackboardAttribute> attributesForNewArtifact = Arrays.asList(
|
||||
new BlackboardAttribute(
|
||||
TSK_CORRELATION_TYPE, MODULE_NAME,
|
||||
aType.getDisplayName()),
|
||||
new BlackboardAttribute(
|
||||
TSK_CORRELATION_VALUE, MODULE_NAME,
|
||||
value));
|
||||
makeAndPostArtifact(BlackboardArtifact.Type.TSK_PREVIOUSLY_UNSEEN, originalArtifact, attributesForNewArtifact, "",
|
||||
Score.SCORE_LIKELY_NOTABLE, "This application has not been previously seen before");
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an interesting item artifact to flag the passed in artifact.
|
||||
* Make an artifact to flag the passed in artifact.
|
||||
*
|
||||
* @param originalArtifact Artifact in current case we want to flag
|
||||
* @param attributesForNewArtifact Attributes to assign to the new
|
||||
* Interesting items artifact
|
||||
* @param configuration The configuration to be specified for the new interesting artifact hit
|
||||
* @param attributesForNewArtifact Attributes to assign to the new artifact
|
||||
* @param configuration The configuration to be specified for the new artifact hit
|
||||
* @param score sleuthkit.datamodel.Score to be assigned to this artifact
|
||||
* @param justification Justification string
|
||||
*/
|
||||
private static void makeAndPostInterestingArtifact(BlackboardArtifact originalArtifact, Collection<BlackboardAttribute> attributesForNewArtifact, String configuration) {
|
||||
private static void makeAndPostArtifact(BlackboardArtifact.Type newArtifactType, BlackboardArtifact originalArtifact, Collection<BlackboardAttribute> attributesForNewArtifact, String configuration,
|
||||
Score score, String justification) {
|
||||
try {
|
||||
SleuthkitCase tskCase = originalArtifact.getSleuthkitCase();
|
||||
AbstractFile abstractFile = tskCase.getAbstractFileById(originalArtifact.getObjectID());
|
||||
Blackboard blackboard = tskCase.getBlackboard();
|
||||
// Create artifact if it doesn't already exist.
|
||||
if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_ARTIFACT_HIT, attributesForNewArtifact)) {
|
||||
BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult(
|
||||
BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE,
|
||||
null, configuration, null, attributesForNewArtifact)
|
||||
BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(newArtifactType.getTypeID());
|
||||
if (!blackboard.artifactExists(originalArtifact, type, attributesForNewArtifact)) {
|
||||
BlackboardArtifact newArtifact = originalArtifact.newAnalysisResult(
|
||||
newArtifactType, score,
|
||||
null, configuration, justification, attributesForNewArtifact)
|
||||
.getAnalysisResult();
|
||||
|
||||
try {
|
||||
// index the artifact for keyword search
|
||||
blackboard.postArtifact(newInterestingArtifact, MODULE_NAME);
|
||||
blackboard.postArtifact(newArtifact, MODULE_NAME);
|
||||
} catch (Blackboard.BlackboardException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + newInterestingArtifact.getArtifactID(), ex); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + newArtifact.getArtifactID(), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
@ -299,11 +369,13 @@ public class IngestEventsListener {
|
||||
}
|
||||
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
|
||||
case DATA_ADDED: {
|
||||
//if ingest isn't running create the interesting items otherwise use the ingest module setting to determine if we create interesting items
|
||||
//if ingest isn't running create the "previously seen" items,
|
||||
// otherwise use the ingest module setting to determine if we create "previously seen" items
|
||||
boolean flagNotable = !IngestManager.getInstance().isIngestRunning() || isFlagNotableItems();
|
||||
boolean flagPrevious = !IngestManager.getInstance().isIngestRunning() || isFlagSeenDevices();
|
||||
boolean createAttributes = !IngestManager.getInstance().isIngestRunning() || shouldCreateCrProperties();
|
||||
jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, flagNotable, flagPrevious, createAttributes));
|
||||
boolean flagUnique = !IngestManager.getInstance().isIngestRunning() || isFlagUniqueArtifacts();
|
||||
jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, flagNotable, flagPrevious, createAttributes, flagUnique));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -368,8 +440,8 @@ public class IngestEventsListener {
|
||||
try {
|
||||
dataSource = ((DataSourceAnalysisEvent) event).getDataSource();
|
||||
/*
|
||||
* We only care about Images for the purpose of
|
||||
* updating hash values.
|
||||
* We only care about Images for the purpose of updating hash
|
||||
* values.
|
||||
*/
|
||||
if (!(dataSource instanceof Image)) {
|
||||
return;
|
||||
@ -443,13 +515,15 @@ public class IngestEventsListener {
|
||||
private final boolean flagNotableItemsEnabled;
|
||||
private final boolean flagPreviousItemsEnabled;
|
||||
private final boolean createCorrelationAttributes;
|
||||
private final boolean flagUniqueItemsEnabled;
|
||||
|
||||
private DataAddedTask(CentralRepository db, PropertyChangeEvent evt, boolean flagNotableItemsEnabled, boolean flagPreviousItemsEnabled, boolean createCorrelationAttributes) {
|
||||
private DataAddedTask(CentralRepository db, PropertyChangeEvent evt, boolean flagNotableItemsEnabled, boolean flagPreviousItemsEnabled, boolean createCorrelationAttributes, boolean flagUnique) {
|
||||
this.dbManager = db;
|
||||
this.event = evt;
|
||||
this.flagNotableItemsEnabled = flagNotableItemsEnabled;
|
||||
this.flagPreviousItemsEnabled = flagPreviousItemsEnabled;
|
||||
this.createCorrelationAttributes = createCorrelationAttributes;
|
||||
this.flagUniqueItemsEnabled = flagUnique;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -471,41 +545,63 @@ public class IngestEventsListener {
|
||||
try {
|
||||
// Only do something with this artifact if it's unique within the job
|
||||
if (recentlyAddedCeArtifacts.add(eamArtifact.toString())) {
|
||||
|
||||
// Get a list of instances for a given value (hash, email, etc.)
|
||||
List<CorrelationAttributeInstance> previousOccurrences = new ArrayList<>();
|
||||
// check if we are flagging things
|
||||
if (flagNotableItemsEnabled || flagPreviousItemsEnabled || flagUniqueItemsEnabled) {
|
||||
try {
|
||||
previousOccurrences = dbManager.getArtifactInstancesByTypeValue(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
|
||||
|
||||
// make sure the previous instances do not contain current case
|
||||
for (Iterator<CorrelationAttributeInstance> iterator = previousOccurrences.iterator(); iterator.hasNext();) {
|
||||
CorrelationAttributeInstance instance = iterator.next();
|
||||
if (instance.getCorrelationCase().getCaseUUID().equals(eamArtifact.getCorrelationCase().getCaseUUID())) {
|
||||
// this is the current case - remove the instace from the previousOccurrences list
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
LOGGER.log(Level.INFO, String.format("Unable to flag previously seen device: %s.", eamArtifact.toString()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Was it previously marked as bad?
|
||||
// query db for artifact instances having this TYPE/VALUE and knownStatus = "Bad".
|
||||
// if getKnownStatus() is "Unknown" and this artifact instance was marked bad in a previous case,
|
||||
// create TSK_INTERESTING_ARTIFACT_HIT artifact on BB.
|
||||
// create TSK_PREVIOUSLY_SEEN artifact on BB.
|
||||
if (flagNotableItemsEnabled) {
|
||||
List<String> caseDisplayNames;
|
||||
try {
|
||||
caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
|
||||
if (!caseDisplayNames.isEmpty()) {
|
||||
makeAndPostPreviousNotableArtifact(bbArtifact,
|
||||
caseDisplayNames);
|
||||
}
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
LOGGER.log(Level.INFO, String.format("Unable to flag notable item: %s.", eamArtifact.toString()), ex);
|
||||
List<String> caseDisplayNames = getCaseDisplayNamesForNotable(previousOccurrences);
|
||||
if (!caseDisplayNames.isEmpty()) {
|
||||
makeAndPostPreviousNotableArtifact(bbArtifact,
|
||||
caseDisplayNames, eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
|
||||
|
||||
// if we have marked this artifact as notable, then skip the analysis of whether it was previously seen
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flagPreviousItemsEnabled
|
||||
|
||||
// flag previously seen devices and communication accounts (emails, phones, etc)
|
||||
if (flagPreviousItemsEnabled && !previousOccurrences.isEmpty()
|
||||
&& (eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.USBID_TYPE_ID
|
||||
|| eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.ICCID_TYPE_ID
|
||||
|| eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMEI_TYPE_ID
|
||||
|| eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMSI_TYPE_ID
|
||||
|| eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.MAC_TYPE_ID)) {
|
||||
try {
|
||||
//only alert to previous instances when they were in another case
|
||||
List<CorrelationAttributeInstance> previousOccurences = dbManager.getArtifactInstancesByTypeValue(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
|
||||
List<String> caseDisplayNames;
|
||||
for (CorrelationAttributeInstance instance : previousOccurences) {
|
||||
if (!instance.getCorrelationCase().getCaseUUID().equals(eamArtifact.getCorrelationCase().getCaseUUID())) {
|
||||
caseDisplayNames = dbManager.getListCasesHavingArtifactInstances(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
|
||||
makeAndPostPreviousSeenArtifact(bbArtifact, caseDisplayNames);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
LOGGER.log(Level.INFO, String.format("Unable to flag notable item: %s.", eamArtifact.toString()), ex);
|
||||
|| eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.MAC_TYPE_ID
|
||||
|| eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.EMAIL_TYPE_ID
|
||||
|| eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.PHONE_TYPE_ID)) {
|
||||
|
||||
List<String> caseDisplayNames = getCaseDisplayNames(previousOccurrences);
|
||||
makeAndPostPreviousSeenArtifact(bbArtifact, caseDisplayNames, eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
|
||||
}
|
||||
|
||||
// flag previously unseen apps and domains
|
||||
if (flagUniqueItemsEnabled
|
||||
&& (eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID
|
||||
|| eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.DOMAIN_TYPE_ID)) {
|
||||
|
||||
if (previousOccurrences.isEmpty()) {
|
||||
makeAndPostPreviouslyUnseenArtifact(bbArtifact, eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
|
||||
}
|
||||
}
|
||||
if (createCorrelationAttributes) {
|
||||
@ -528,4 +624,36 @@ public class IngestEventsListener {
|
||||
} // DATA_ADDED
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets case display names for a list of CorrelationAttributeInstance.
|
||||
*
|
||||
* @param occurrences List of CorrelationAttributeInstance
|
||||
*
|
||||
* @return List of case display names
|
||||
*/
|
||||
private List<String> getCaseDisplayNames(List<CorrelationAttributeInstance> occurrences) {
|
||||
List<String> caseNames = new ArrayList<>();
|
||||
for (CorrelationAttributeInstance occurrence : occurrences) {
|
||||
caseNames.add(occurrence.getCorrelationCase().getDisplayName());
|
||||
}
|
||||
return caseNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets case display names for only occurrences marked as NOTABLE/BAD.
|
||||
*
|
||||
* @param occurrences List of CorrelationAttributeInstance
|
||||
*
|
||||
* @return List of case display names of NOTABLE/BAD occurrences
|
||||
*/
|
||||
private List<String> getCaseDisplayNamesForNotable(List<CorrelationAttributeInstance> occurrences) {
|
||||
List<String> caseNames = new ArrayList<>();
|
||||
for (CorrelationAttributeInstance occurrence : occurrences) {
|
||||
if (occurrence.getKnownStatus() == TskData.FileKnown.BAD) {
|
||||
caseNames.add(occurrence.getCorrelationCase().getDisplayName());
|
||||
}
|
||||
}
|
||||
return caseNames;
|
||||
}
|
||||
}
|
||||
|
@ -2,3 +2,4 @@ IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings
|
||||
IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable
|
||||
IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag devices and users previously seen in other cases
|
||||
IngestSettingsPanel.createCorrelationPropertiesCheckbox.text=Save items to the Central Repository
|
||||
IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag apps and domains not seen in other cases
|
||||
|
@ -13,3 +13,4 @@ IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings
|
||||
IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable
|
||||
IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag devices and users previously seen in other cases
|
||||
IngestSettingsPanel.createCorrelationPropertiesCheckbox.text=Save items to the Central Repository
|
||||
IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag apps and domains not seen in other cases
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -48,10 +48,12 @@ import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Blackboard;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES;
|
||||
import org.sleuthkit.datamodel.HashUtility;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -69,6 +71,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
private static final String MODULE_NAME = CentralRepoIngestModuleFactory.getModuleName();
|
||||
static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS = false;
|
||||
static final boolean DEFAULT_FLAG_PREVIOUS_DEVICES = false;
|
||||
static final boolean DEFAULT_FLAG_UNIQUE_DEVICES = false;
|
||||
static final boolean DEFAULT_CREATE_CR_PROPERTIES = true;
|
||||
|
||||
private final static Logger logger = Logger.getLogger(CentralRepoIngestModule.class.getName());
|
||||
@ -83,6 +86,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
private final boolean flagPreviouslySeenDevices;
|
||||
private Blackboard blackboard;
|
||||
private final boolean createCorrelationProperties;
|
||||
private final boolean flagUniqueArtifacts;
|
||||
|
||||
/**
|
||||
* Instantiate the Central Repository ingest module.
|
||||
@ -93,6 +97,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
flagTaggedNotableItems = settings.isFlagTaggedNotableItems();
|
||||
flagPreviouslySeenDevices = settings.isFlagPreviousDevices();
|
||||
createCorrelationProperties = settings.shouldCreateCorrelationProperties();
|
||||
flagUniqueArtifacts = settings.isFlagUniqueArtifacts();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -151,7 +156,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
|
||||
HealthMonitor.submitTimingMetric(timingMetric);
|
||||
if (!caseDisplayNamesList.isEmpty()) {
|
||||
postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList);
|
||||
postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList, filesType, md5);
|
||||
}
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS
|
||||
@ -249,6 +254,9 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.shouldCreateCrProperties()) {
|
||||
IngestEventsListener.setCreateCrProperties(createCorrelationProperties);
|
||||
}
|
||||
if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.isFlagUniqueArtifacts()) {
|
||||
IngestEventsListener.setFlagUniqueArtifacts(flagUniqueArtifacts);
|
||||
}
|
||||
|
||||
if (CentralRepository.isEnabled() == false) {
|
||||
/*
|
||||
@ -327,26 +335,33 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* Post a new interesting artifact for the file marked bad.
|
||||
* Post a new "previously seen" artifact for the file marked bad.
|
||||
*
|
||||
* @param abstractFile The file from which to create an artifact.
|
||||
* @param caseDisplayNames Case names to be added to a TSK_COMMON attribute.
|
||||
*/
|
||||
private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List<String> caseDisplayNames) {
|
||||
private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List<String> caseDisplayNames, CorrelationAttributeInstance.Type aType, String value) {
|
||||
String prevCases = caseDisplayNames.stream().distinct().collect(Collectors.joining(","));
|
||||
String justification = "Previously marked as notable in cases " + prevCases;
|
||||
Collection<BlackboardAttribute> attributes = Arrays.asList(
|
||||
new BlackboardAttribute(
|
||||
TSK_SET_NAME, MODULE_NAME,
|
||||
Bundle.CentralRepoIngestModule_prevTaggedSet_text()),
|
||||
new BlackboardAttribute(
|
||||
TSK_COMMENT, MODULE_NAME,
|
||||
Bundle.CentralRepoIngestModule_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(","))));
|
||||
TSK_CORRELATION_TYPE, MODULE_NAME,
|
||||
aType.getDisplayName()),
|
||||
new BlackboardAttribute(
|
||||
TSK_CORRELATION_VALUE, MODULE_NAME,
|
||||
value),
|
||||
new BlackboardAttribute(
|
||||
TSK_OTHER_CASES, MODULE_NAME,
|
||||
prevCases));
|
||||
try {
|
||||
|
||||
// Create artifact if it doesn't already exist.
|
||||
if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_FILE_HIT, attributes)) {
|
||||
if (!blackboard.artifactExists(abstractFile, TSK_PREVIOUSLY_NOTABLE, attributes)) {
|
||||
BlackboardArtifact tifArtifact = abstractFile.newAnalysisResult(
|
||||
BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, Score.SCORE_LIKELY_NOTABLE,
|
||||
null, Bundle.CentralRepoIngestModule_prevTaggedSet_text(), null, attributes)
|
||||
BlackboardArtifact.Type.TSK_PREVIOUSLY_NOTABLE, Score.SCORE_NOTABLE,
|
||||
null, Bundle.CentralRepoIngestModule_prevTaggedSet_text(), justification, attributes)
|
||||
.getAnalysisResult();
|
||||
try {
|
||||
// index the artifact for keyword search
|
||||
|
@ -121,14 +121,14 @@ public class CentralRepoIngestModuleFactory extends IngestModuleFactoryAdapter {
|
||||
throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataArtifactIngestModuleFactory() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataArtifactIngestModule createDataArtifactIngestModule(IngestModuleIngestJobSettings settings) {
|
||||
return new CentralRepoDataArtifactIngestModule();
|
||||
}
|
||||
// @Override
|
||||
// public boolean isDataArtifactIngestModuleFactory() {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public DataArtifactIngestModule createDataArtifactIngestModule(IngestModuleIngestJobSettings settings) {
|
||||
// return new CentralRepoDataArtifactIngestModule();
|
||||
// }
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Copyright 2018-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -30,6 +30,7 @@ final class IngestSettings implements IngestModuleIngestJobSettings {
|
||||
private final boolean flagTaggedNotableItems;
|
||||
private final boolean flagPreviousDevices;
|
||||
private final boolean createCorrelationProperties;
|
||||
private final boolean flagUniqueArtifacts;
|
||||
|
||||
/**
|
||||
* Instantiate the ingest job settings with default values.
|
||||
@ -38,6 +39,7 @@ final class IngestSettings implements IngestModuleIngestJobSettings {
|
||||
this.flagTaggedNotableItems = CentralRepoIngestModule.DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS;
|
||||
this.flagPreviousDevices = CentralRepoIngestModule.DEFAULT_FLAG_PREVIOUS_DEVICES;
|
||||
this.createCorrelationProperties = CentralRepoIngestModule.DEFAULT_CREATE_CR_PROPERTIES;
|
||||
this.flagUniqueArtifacts = CentralRepoIngestModule.DEFAULT_FLAG_UNIQUE_DEVICES;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,11 +50,14 @@ final class IngestSettings implements IngestModuleIngestJobSettings {
|
||||
* the Central Repository
|
||||
* @param createCorrelationProperties Create correlation properties in the
|
||||
* central repository
|
||||
* @param flagUniqueArtifacts Flag unique artifacts that have not
|
||||
* been seen in any other cases
|
||||
*/
|
||||
IngestSettings(boolean flagTaggedNotableItems, boolean flagPreviousDevices, boolean createCorrelationProperties) {
|
||||
IngestSettings(boolean flagTaggedNotableItems, boolean flagPreviousDevices, boolean createCorrelationProperties, boolean flagUniqueArtifacts) {
|
||||
this.flagTaggedNotableItems = flagTaggedNotableItems;
|
||||
this.flagPreviousDevices = flagPreviousDevices;
|
||||
this.createCorrelationProperties = createCorrelationProperties;
|
||||
this.flagUniqueArtifacts = flagUniqueArtifacts;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,4 +91,14 @@ final class IngestSettings implements IngestModuleIngestJobSettings {
|
||||
boolean shouldCreateCorrelationProperties() {
|
||||
return createCorrelationProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are artifacts (apps, domains) previously unseen in other cases to be
|
||||
* flagged?
|
||||
*
|
||||
* @return True if flagging; otherwise false.
|
||||
*/
|
||||
public boolean isFlagUniqueArtifacts() {
|
||||
return flagUniqueArtifacts;
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +26,11 @@
|
||||
<Component id="flagTaggedNotableItemsCheckbox" max="32767" attributes="0"/>
|
||||
<Component id="flagPreviouslySeenDevicesCheckbox" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="createCorrelationPropertiesCheckbox" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="flagUniqueAppsCheckbox" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<EmptySpace pref="16" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -44,7 +45,9 @@
|
||||
<Component id="flagTaggedNotableItemsCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="flagPreviouslySeenDevicesCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="47" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="flagUniqueAppsCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="24" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -83,5 +86,12 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="flagUniqueAppsCheckbox">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties" key="IngestSettingsPanel.flagUniqueAppsCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Copyright 2018-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -44,11 +44,13 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
|
||||
flagTaggedNotableItemsCheckbox.setSelected(settings.isFlagTaggedNotableItems());
|
||||
flagPreviouslySeenDevicesCheckbox.setSelected(settings.isFlagPreviousDevices());
|
||||
createCorrelationPropertiesCheckbox.setSelected(settings.shouldCreateCorrelationProperties());
|
||||
flagUniqueAppsCheckbox.setSelected(settings.isFlagUniqueArtifacts());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngestModuleIngestJobSettings getSettings() {
|
||||
return new IngestSettings(flagTaggedNotableItemsCheckbox.isSelected(), flagPreviouslySeenDevicesCheckbox.isSelected(), createCorrelationPropertiesCheckbox.isSelected());
|
||||
return new IngestSettings(flagTaggedNotableItemsCheckbox.isSelected(), flagPreviouslySeenDevicesCheckbox.isSelected(),
|
||||
createCorrelationPropertiesCheckbox.isSelected(), flagUniqueAppsCheckbox.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,6 +66,7 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
|
||||
flagTaggedNotableItemsCheckbox = new javax.swing.JCheckBox();
|
||||
flagPreviouslySeenDevicesCheckbox = new javax.swing.JCheckBox();
|
||||
createCorrelationPropertiesCheckbox = new javax.swing.JCheckBox();
|
||||
flagUniqueAppsCheckbox = new javax.swing.JCheckBox();
|
||||
|
||||
ingestSettingsLabel.setFont(ingestSettingsLabel.getFont().deriveFont(ingestSettingsLabel.getFont().getStyle() | java.awt.Font.BOLD));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(ingestSettingsLabel, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ingestSettingsLabel.text")); // NOI18N
|
||||
@ -74,6 +77,8 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(createCorrelationPropertiesCheckbox, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.createCorrelationPropertiesCheckbox.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(flagUniqueAppsCheckbox, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.flagUniqueAppsCheckbox.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
@ -87,8 +92,9 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(flagTaggedNotableItemsCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(flagPreviouslySeenDevicesCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(createCorrelationPropertiesCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addComponent(createCorrelationPropertiesCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(flagUniqueAppsCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
|
||||
.addContainerGap(16, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@ -101,7 +107,9 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
|
||||
.addComponent(flagTaggedNotableItemsCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(flagPreviouslySeenDevicesCheckbox)
|
||||
.addContainerGap(47, Short.MAX_VALUE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(flagUniqueAppsCheckbox)
|
||||
.addContainerGap(24, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
@ -109,6 +117,7 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
|
||||
private javax.swing.JCheckBox createCorrelationPropertiesCheckbox;
|
||||
private javax.swing.JCheckBox flagPreviouslySeenDevicesCheckbox;
|
||||
private javax.swing.JCheckBox flagTaggedNotableItemsCheckbox;
|
||||
private javax.swing.JCheckBox flagUniqueAppsCheckbox;
|
||||
private javax.swing.JLabel ingestSettingsLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
|
@ -15,9 +15,6 @@
|
||||
# governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
AnnotationsContentViewer.onEmpty=No annotations were found for this particular item.
|
||||
AnnotationsContentViewer.title=Annotations
|
||||
AnnotationsContentViewer.toolTip=Displays tags and comments associated with the selected content.
|
||||
ApplicationContentViewer.title=Application
|
||||
ApplicationContentViewer.toolTip=Displays file contents.
|
||||
FXVideoPanel.pauseButton.infoLabel.playbackErr=Unable to play video.
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.contentviewers.analysisresults;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.SwingWorker;
|
||||
@ -28,24 +29,21 @@ import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.autopsy.datamodel.TskContentItem;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.autopsy.datamodel.AnalysisResultItem;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Displays a list of analysis results as a content viewer.
|
||||
* A content viewer that displays the analysis results for a Content object.
|
||||
*/
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 7)
|
||||
public class AnalysisResultsContentViewer implements DataContentViewer {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AnalysisResultsContentPanel.class.getName());
|
||||
|
||||
// isPreferred value
|
||||
private static final int PREFERRED_VALUE = 3;
|
||||
|
||||
private final AnalysisResultsViewModel viewModel = new AnalysisResultsViewModel();
|
||||
private final AnalysisResultsContentPanel panel = new AnalysisResultsContentPanel();
|
||||
|
||||
@ -125,26 +123,24 @@ public class AnalysisResultsContentViewer implements DataContentViewer {
|
||||
|
||||
@Override
|
||||
public boolean isSupported(Node node) {
|
||||
if (node == null) {
|
||||
if (Objects.isNull(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There needs to either be a file with an AnalysisResult or an AnalysisResult in the lookup.
|
||||
for (Content content : node.getLookup().lookupAll(Content.class)) {
|
||||
if (content instanceof AnalysisResult) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (content == null || content instanceof BlackboardArtifact) {
|
||||
continue;
|
||||
}
|
||||
AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class);
|
||||
if (Objects.nonNull(analysisResultItem)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TskContentItem<?> contentItem = node.getLookup().lookup(TskContentItem.class);
|
||||
if (!Objects.isNull(contentItem)) {
|
||||
Content content = contentItem.getTskContent();
|
||||
try {
|
||||
if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) {
|
||||
return true;
|
||||
}
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to get analysis results for file with obj id " + content.getId(), ex);
|
||||
logger.log(Level.SEVERE, String.format("Error getting analysis results for Content (object ID = %d)", content.getId()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,4 +151,5 @@ public class AnalysisResultsContentViewer implements DataContentViewer {
|
||||
public int isPreferred(Node node) {
|
||||
return PREFERRED_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 Basis Technology Corp.
|
||||
* Copyright 2021-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,9 +20,8 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -31,14 +30,14 @@ import java.util.stream.Stream;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.datamodel.AnalysisResultItem;
|
||||
import org.sleuthkit.autopsy.datamodel.TskContentItem;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Creates a representation of a list of analysis results gathered from a node.
|
||||
*/
|
||||
public class AnalysisResultsViewModel {
|
||||
@ -72,7 +71,7 @@ public class AnalysisResultsViewModel {
|
||||
* @return The attributes to display.
|
||||
*/
|
||||
List<Pair<String, String>> getAttributesToDisplay() {
|
||||
return attributesToDisplay;
|
||||
return Collections.unmodifiableList(attributesToDisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +117,7 @@ public class AnalysisResultsViewModel {
|
||||
* @return The analysis results to be displayed.
|
||||
*/
|
||||
List<ResultDisplayAttributes> getAnalysisResults() {
|
||||
return analysisResults;
|
||||
return Collections.unmodifiableList(analysisResults);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -238,58 +237,44 @@ public class AnalysisResultsViewModel {
|
||||
return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
Optional<Score> aggregateScore = Optional.empty();
|
||||
Optional<Content> nodeContent = Optional.empty();
|
||||
// maps id of analysis result to analysis result to prevent duplication
|
||||
Map<Long, AnalysisResult> allAnalysisResults = new HashMap<>();
|
||||
Optional<AnalysisResult> selectedResult = Optional.empty();
|
||||
|
||||
// Find first content that is not an artifact within node
|
||||
for (Content content : node.getLookup().lookupAll(Content.class)) {
|
||||
if (content == null || content instanceof BlackboardArtifact) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
nodeContent = Optional.of(content);
|
||||
|
||||
// get the aggregate score of that content
|
||||
aggregateScore = Optional.ofNullable(content.getAggregateScore());
|
||||
|
||||
// and add all analysis results to mapping
|
||||
content.getAllAnalysisResults().stream()
|
||||
.forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar));
|
||||
|
||||
break;
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to get analysis results for content with obj id " + content.getId(), ex);
|
||||
Content analyzedContent = null;
|
||||
AnalysisResult selectedAnalysisResult = null;
|
||||
Score aggregateScore = null;
|
||||
List<AnalysisResult> analysisResults = Collections.emptyList();
|
||||
long selectedObjectId = 0;
|
||||
try {
|
||||
AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class);
|
||||
if (Objects.nonNull(analysisResultItem)) {
|
||||
/*
|
||||
* The content represented by the Node is an analysis result.
|
||||
* Set this analysis result as the analysis result to be
|
||||
* selected in the content viewer and get the analyzed content
|
||||
* as the source of the analysis results to display.
|
||||
*/
|
||||
selectedAnalysisResult = analysisResultItem.getTskContent();
|
||||
selectedObjectId = selectedAnalysisResult.getId();
|
||||
analyzedContent = selectedAnalysisResult.getParent();
|
||||
} else {
|
||||
/*
|
||||
* The content represented by the Node is something other than
|
||||
* an analysis result. Use it as the source of the analysis
|
||||
* results to display.
|
||||
*/
|
||||
TskContentItem<?> contentItem = node.getLookup().lookup(TskContentItem.class);
|
||||
analyzedContent = contentItem.getTskContent();
|
||||
selectedObjectId = analyzedContent.getId();
|
||||
}
|
||||
aggregateScore = analyzedContent.getAggregateScore();
|
||||
analysisResults = analyzedContent.getAllAnalysisResults();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error getting analysis result data for selected Content (object ID=%d)", selectedObjectId), ex);
|
||||
}
|
||||
|
||||
// Find any analysis results in the node
|
||||
Collection<? extends AnalysisResult> analysisResults = node.getLookup().lookupAll(AnalysisResult.class);
|
||||
if (analysisResults.size() > 0) {
|
||||
|
||||
// get any items with a score
|
||||
List<AnalysisResult> filteredResults = analysisResults.stream()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// add them to the map to display
|
||||
filteredResults.forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar));
|
||||
|
||||
// the selected result will be the highest scored analysis result in the node.
|
||||
selectedResult = filteredResults.stream()
|
||||
.max((a, b) -> a.getScore().compareTo(b.getScore()));
|
||||
|
||||
// if no aggregate score determined at this point, use the selected result score.
|
||||
if (!aggregateScore.isPresent()) {
|
||||
aggregateScore = selectedResult.flatMap(selectedRes -> Optional.ofNullable(selectedRes.getScore()));
|
||||
}
|
||||
}
|
||||
|
||||
// get view model representation
|
||||
List<ResultDisplayAttributes> displayAttributes = getOrderedDisplayAttributes(allAnalysisResults.values());
|
||||
|
||||
return new NodeResults(displayAttributes, selectedResult, aggregateScore, nodeContent);
|
||||
/*
|
||||
* Use the data collected above to construct the view model.
|
||||
*/
|
||||
List<ResultDisplayAttributes> displayAttributes = getOrderedDisplayAttributes(analysisResults);
|
||||
return new NodeResults(displayAttributes, Optional.ofNullable(selectedAnalysisResult), Optional.ofNullable(aggregateScore), Optional.ofNullable(analyzedContent));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
AnalysisResultsContentPanel_aggregateScore_displayKey=Aggregate Score
|
||||
AnalysisResultsContentPanel_content_displayKey=Item
|
||||
# {0} - analysisResultsNumber
|
||||
AnalysisResultsContentPanel_result_headerKey=Analysis Result {0}
|
||||
AnalysisResultsContentViewer_setNode_errorMessage=There was an error loading results.
|
||||
|
@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.contentviewers.application;
|
||||
package org.sleuthkit.autopsy.contentviewers.annotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -53,76 +53,76 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* The business logic for the Annotations content panel.
|
||||
*/
|
||||
public class Annotations {
|
||||
public class AnnotationUtils {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"Annotations.title=Annotations",
|
||||
"Annotations.toolTip=Displays tags and comments associated with the selected content.",
|
||||
"Annotations.centralRepositoryEntry.title=Central Repository Comments",
|
||||
"Annotations.centralRepositoryEntryDataLabel.case=Case:",
|
||||
"Annotations.centralRepositoryEntryDataLabel.type=Type:",
|
||||
"Annotations.centralRepositoryEntryDataLabel.comment=Comment:",
|
||||
"Annotations.centralRepositoryEntryDataLabel.path=Path:",
|
||||
"Annotations.tagEntry.title=Tags",
|
||||
"Annotations.tagEntryDataLabel.tag=Tag:",
|
||||
"Annotations.tagEntryDataLabel.tagUser=Examiner:",
|
||||
"Annotations.tagEntryDataLabel.comment=Comment:",
|
||||
"Annotations.fileHitEntry.artifactCommentTitle=Artifact Comment",
|
||||
"Annotations.fileHitEntry.hashSetHitTitle=Hash Set Hit Comments",
|
||||
"Annotations.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments",
|
||||
"Annotations.fileHitEntry.setName=Set Name:",
|
||||
"Annotations.fileHitEntry.comment=Comment:",
|
||||
"Annotations.sourceFile.title=Source File",
|
||||
"Annotations.onEmpty=No annotations were found for this particular item."
|
||||
"AnnotationUtils.title=Annotations",
|
||||
"AnnotationUtils.toolTip=Displays tags and comments associated with the selected content.",
|
||||
"AnnotationUtils.centralRepositoryEntry.title=Central Repository Comments",
|
||||
"AnnotationUtils.centralRepositoryEntryDataLabel.case=Case:",
|
||||
"AnnotationUtils.centralRepositoryEntryDataLabel.type=Type:",
|
||||
"AnnotationUtils.centralRepositoryEntryDataLabel.comment=Comment:",
|
||||
"AnnotationUtils.centralRepositoryEntryDataLabel.path=Path:",
|
||||
"AnnotationUtils.tagEntry.title=Tags",
|
||||
"AnnotationUtils.tagEntryDataLabel.tag=Tag:",
|
||||
"AnnotationUtils.tagEntryDataLabel.tagUser=Examiner:",
|
||||
"AnnotationUtils.tagEntryDataLabel.comment=Comment:",
|
||||
"AnnotationUtils.fileHitEntry.artifactCommentTitle=Artifact Comment",
|
||||
"AnnotationUtils.fileHitEntry.hashSetHitTitle=Hash Set Hit Comments",
|
||||
"AnnotationUtils.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments",
|
||||
"AnnotationUtils.fileHitEntry.setName=Set Name:",
|
||||
"AnnotationUtils.fileHitEntry.comment=Comment:",
|
||||
"AnnotationUtils.sourceFile.title=Source File",
|
||||
"AnnotationUtils.onEmpty=No annotations were found for this particular item."
|
||||
})
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Annotations.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(AnnotationUtils.class.getName());
|
||||
|
||||
private static final String EMPTY_HTML = "<html><head></head><body></body></html>";
|
||||
|
||||
// describing table values for a tag
|
||||
private static final List<ItemEntry<Tag>> TAG_ENTRIES = Arrays.asList(
|
||||
new ItemEntry<>(Bundle.Annotations_tagEntryDataLabel_tag(),
|
||||
new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_tag(),
|
||||
(tag) -> (tag.getName() != null) ? tag.getName().getDisplayName() : null),
|
||||
new ItemEntry<>(Bundle.Annotations_tagEntryDataLabel_tagUser(), (tag) -> tag.getUserName()),
|
||||
new ItemEntry<>(Bundle.Annotations_tagEntryDataLabel_comment(), (tag) -> tag.getComment())
|
||||
new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_tagUser(), (tag) -> tag.getUserName()),
|
||||
new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_comment(), (tag) -> tag.getComment())
|
||||
);
|
||||
|
||||
private static final SectionConfig<Tag> TAG_CONFIG
|
||||
= new SectionConfig<>(Bundle.Annotations_tagEntry_title(), TAG_ENTRIES);
|
||||
= new SectionConfig<>(Bundle.AnnotationUtils_tagEntry_title(), TAG_ENTRIES);
|
||||
|
||||
// file set attributes and table configurations
|
||||
private static final List<ItemEntry<BlackboardArtifact>> FILESET_HIT_ENTRIES = Arrays.asList(
|
||||
new ItemEntry<>(Bundle.Annotations_fileHitEntry_setName(),
|
||||
new ItemEntry<>(Bundle.AnnotationUtils_fileHitEntry_setName(),
|
||||
(bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)),
|
||||
new ItemEntry<>(Bundle.Annotations_fileHitEntry_comment(),
|
||||
new ItemEntry<>(Bundle.AnnotationUtils_fileHitEntry_comment(),
|
||||
(bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT))
|
||||
);
|
||||
|
||||
private static final SectionConfig<BlackboardArtifact> INTERESTING_FILE_CONFIG
|
||||
= new SectionConfig<>(Bundle.Annotations_fileHitEntry_interestingFileHitTitle(), FILESET_HIT_ENTRIES);
|
||||
= new SectionConfig<>(Bundle.AnnotationUtils_fileHitEntry_interestingFileHitTitle(), FILESET_HIT_ENTRIES);
|
||||
|
||||
private static final SectionConfig<BlackboardArtifact> HASHSET_CONFIG
|
||||
= new SectionConfig<>(Bundle.Annotations_fileHitEntry_hashSetHitTitle(), FILESET_HIT_ENTRIES);
|
||||
= new SectionConfig<>(Bundle.AnnotationUtils_fileHitEntry_hashSetHitTitle(), FILESET_HIT_ENTRIES);
|
||||
|
||||
private static final SectionConfig<BlackboardArtifact> ARTIFACT_COMMENT_CONFIG
|
||||
= new SectionConfig<>(Bundle.Annotations_fileHitEntry_artifactCommentTitle(), FILESET_HIT_ENTRIES);
|
||||
= new SectionConfig<>(Bundle.AnnotationUtils_fileHitEntry_artifactCommentTitle(), FILESET_HIT_ENTRIES);
|
||||
|
||||
// central repository attributes and table configuration
|
||||
private static final List<ItemEntry<CorrelationAttributeInstance>> CR_COMMENTS_ENTRIES = Arrays.asList(
|
||||
new ItemEntry<>(Bundle.Annotations_centralRepositoryEntryDataLabel_case(),
|
||||
new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_case(),
|
||||
cai -> (cai.getCorrelationCase() != null) ? cai.getCorrelationCase().getDisplayName() : null),
|
||||
new ItemEntry<>(Bundle.Annotations_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()),
|
||||
new ItemEntry<>(Bundle.Annotations_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath())
|
||||
new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()),
|
||||
new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath())
|
||||
);
|
||||
|
||||
private static final SectionConfig<CorrelationAttributeInstance> CR_COMMENTS_CONFIG
|
||||
= new SectionConfig<>(Bundle.Annotations_centralRepositoryEntry_title(), CR_COMMENTS_ENTRIES);
|
||||
= new SectionConfig<>(Bundle.AnnotationUtils_centralRepositoryEntry_title(), CR_COMMENTS_ENTRIES);
|
||||
|
||||
/*
|
||||
* Private constructor for this utility class.
|
||||
*/
|
||||
private Annotations() {
|
||||
private AnnotationUtils() {
|
||||
|
||||
}
|
||||
|
||||
@ -205,7 +205,7 @@ public class Annotations {
|
||||
contentRendered = contentRendered || filesetRendered;
|
||||
}
|
||||
|
||||
Element sourceFileSection = appendSection(parent, Bundle.Annotations_sourceFile_title());
|
||||
Element sourceFileSection = appendSection(parent, Bundle.AnnotationUtils_sourceFile_title());
|
||||
sourceFileSection.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName());
|
||||
|
||||
Element sourceFileContainer = sourceFileSection.appendElement("div");
|
||||
@ -372,7 +372,7 @@ public class Annotations {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact)
|
||||
List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact)
|
||||
.stream()
|
||||
.map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue()))
|
||||
.collect(Collectors.toList());
|
||||
@ -464,7 +464,7 @@ public class Annotations {
|
||||
*
|
||||
* @return If there was actual content rendered for this set of entries.
|
||||
*/
|
||||
private static <T> boolean appendEntries(Element parent, Annotations.SectionConfig<T> config, List<? extends T> items,
|
||||
private static <T> boolean appendEntries(Element parent, AnnotationUtils.SectionConfig<T> config, List<? extends T> items,
|
||||
boolean isSubsection, boolean isFirstSection) {
|
||||
if (items == null || items.isEmpty()) {
|
||||
return false;
|
@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.contentviewers;
|
||||
package org.sleuthkit.autopsy.contentviewers.annotations;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@ -28,9 +28,6 @@ import org.openide.nodes.Node;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.contentviewers.application.Annotations;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles;
|
||||
@ -161,7 +158,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
|
||||
|
||||
@Override
|
||||
protected String doInBackground() throws Exception {
|
||||
Document doc = Annotations.buildDocument(node);
|
||||
Document doc = AnnotationUtils.buildDocument(node);
|
||||
|
||||
if(isCancelled()) {
|
||||
return null;
|
@ -0,0 +1,21 @@
|
||||
AnnotationsContentViewer.onEmpty=No annotations were found for this particular item.
|
||||
AnnotationsContentViewer.title=Annotations
|
||||
AnnotationsContentViewer.toolTip=Displays tags and comments associated with the selected content.
|
||||
AnnotationUtils.centralRepositoryEntry.title=Central Repository Comments
|
||||
AnnotationUtils.centralRepositoryEntryDataLabel.case=Case:
|
||||
AnnotationUtils.centralRepositoryEntryDataLabel.comment=Comment:
|
||||
AnnotationUtils.centralRepositoryEntryDataLabel.path=Path:
|
||||
AnnotationUtils.centralRepositoryEntryDataLabel.type=Type:
|
||||
AnnotationUtils.fileHitEntry.artifactCommentTitle=Artifact Comment
|
||||
AnnotationUtils.fileHitEntry.comment=Comment:
|
||||
AnnotationUtils.fileHitEntry.hashSetHitTitle=Hash Set Hit Comments
|
||||
AnnotationUtils.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments
|
||||
AnnotationUtils.fileHitEntry.setName=Set Name:
|
||||
AnnotationUtils.onEmpty=No annotations were found for this particular item.
|
||||
AnnotationUtils.sourceFile.title=Source File
|
||||
AnnotationUtils.tagEntry.title=Tags
|
||||
AnnotationUtils.tagEntryDataLabel.comment=Comment:
|
||||
AnnotationUtils.tagEntryDataLabel.tag=Tag:
|
||||
AnnotationUtils.tagEntryDataLabel.tagUser=Examiner:
|
||||
AnnotationUtils.title=Annotations
|
||||
AnnotationUtils.toolTip=Displays tags and comments associated with the selected content.
|
@ -0,0 +1,22 @@
|
||||
#Thu Jul 01 11:56:41 UTC 2021
|
||||
AnnotationUtils.centralRepositoryEntry.title=\u30bb\u30f3\u30c8\u30e9\u30eb\u30fb\u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u30b3\u30e1\u30f3\u30c8
|
||||
AnnotationUtils.centralRepositoryEntryDataLabel.case=\u30b1\u30fc\u30b9\:
|
||||
AnnotationUtils.centralRepositoryEntryDataLabel.comment=\u30b3\u30e1\u30f3\u30c8\:
|
||||
AnnotationUtils.centralRepositoryEntryDataLabel.path=\u30d1\u30b9\:
|
||||
AnnotationUtils.centralRepositoryEntryDataLabel.type=\u30bf\u30a4\u30d7\:
|
||||
AnnotationUtils.fileHitEntry.artifactCommentTitle=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30b3\u30e1\u30f3\u30c8
|
||||
AnnotationUtils.fileHitEntry.comment=\u30b3\u30e1\u30f3\u30c8\:
|
||||
AnnotationUtils.fileHitEntry.hashSetHitTitle=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u30fb\u30d2\u30c3\u30c8\u30b3\u30e1\u30f3\u30c8
|
||||
AnnotationUtils.fileHitEntry.interestingFileHitTitle=\u8208\u5473\u6df1\u3044\u30d5\u30a1\u30a4\u30eb\u30d2\u30c3\u30c8\u30b3\u30e1\u30f3\u30c8
|
||||
AnnotationUtils.fileHitEntry.setName=\u30bb\u30c3\u30c8\u540d\:
|
||||
AnnotationUtils.onEmpty=\u3053\u306e\u30a2\u30a4\u30c6\u30e0\u306e\u6ce8\u91c8\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002
|
||||
AnnotationUtils.sourceFile.title=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
|
||||
AnnotationUtils.tagEntry.title=\u30bf\u30b0
|
||||
AnnotationUtils.tagEntryDataLabel.comment=\u30b3\u30e1\u30f3\u30c8\:
|
||||
AnnotationUtils.tagEntryDataLabel.tag=\u30bf\u30b0\:
|
||||
AnnotationUtils.tagEntryDataLabel.tagUser=\u5be9\u67fb\u5b98\uff1a
|
||||
AnnotationUtils.title=\u30a2\u30ce\u30c6\u30fc\u30b7\u30e7\u30f3
|
||||
AnnotationUtils.toolTip=\u9078\u629e\u3057\u305f\u30b3\u30f3\u30c6\u30f3\u30c4\u3068\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u308b\u30bf\u30b0\u3068\u30b3\u30e1\u30f3\u30c8\u3092\u8868\u793a\u3057\u307e\u3059\u3002
|
||||
AnnotationsContentViewer.onEmpty=\u3053\u306e\u30a2\u30a4\u30c6\u30e0\u306e\u6ce8\u91c8\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002
|
||||
AnnotationsContentViewer.title=\u30a2\u30ce\u30c6\u30fc\u30b7\u30e7\u30f3
|
||||
AnnotationsContentViewer.toolTip=\u9078\u629e\u3057\u305f\u30b3\u30f3\u30c6\u30f3\u30c4\u3068\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u308b\u30bf\u30b0\u3068\u30b3\u30e1\u30f3\u30c8\u3092\u8868\u793a\u3057\u307e\u3059\u3002
|
@ -1,18 +0,0 @@
|
||||
Annotations.centralRepositoryEntry.title=Central Repository Comments
|
||||
Annotations.centralRepositoryEntryDataLabel.case=Case:
|
||||
Annotations.centralRepositoryEntryDataLabel.comment=Comment:
|
||||
Annotations.centralRepositoryEntryDataLabel.path=Path:
|
||||
Annotations.centralRepositoryEntryDataLabel.type=Type:
|
||||
Annotations.fileHitEntry.artifactCommentTitle=Artifact Comment
|
||||
Annotations.fileHitEntry.comment=Comment:
|
||||
Annotations.fileHitEntry.hashSetHitTitle=Hash Set Hit Comments
|
||||
Annotations.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments
|
||||
Annotations.fileHitEntry.setName=Set Name:
|
||||
Annotations.onEmpty=No annotations were found for this particular item.
|
||||
Annotations.sourceFile.title=Source File
|
||||
Annotations.tagEntry.title=Tags
|
||||
Annotations.tagEntryDataLabel.comment=Comment:
|
||||
Annotations.tagEntryDataLabel.tag=Tag:
|
||||
Annotations.tagEntryDataLabel.tagUser=Examiner:
|
||||
Annotations.title=Annotations
|
||||
Annotations.toolTip=Displays tags and comments associated with the selected content.
|
@ -1,19 +0,0 @@
|
||||
#Thu Jul 01 11:56:41 UTC 2021
|
||||
Annotations.centralRepositoryEntry.title=\u30bb\u30f3\u30c8\u30e9\u30eb\u30fb\u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u30b3\u30e1\u30f3\u30c8
|
||||
Annotations.centralRepositoryEntryDataLabel.case=\u30b1\u30fc\u30b9\:
|
||||
Annotations.centralRepositoryEntryDataLabel.comment=\u30b3\u30e1\u30f3\u30c8\:
|
||||
Annotations.centralRepositoryEntryDataLabel.path=\u30d1\u30b9\:
|
||||
Annotations.centralRepositoryEntryDataLabel.type=\u30bf\u30a4\u30d7\:
|
||||
Annotations.fileHitEntry.artifactCommentTitle=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30b3\u30e1\u30f3\u30c8
|
||||
Annotations.fileHitEntry.comment=\u30b3\u30e1\u30f3\u30c8\:
|
||||
Annotations.fileHitEntry.hashSetHitTitle=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u30fb\u30d2\u30c3\u30c8\u30b3\u30e1\u30f3\u30c8
|
||||
Annotations.fileHitEntry.interestingFileHitTitle=\u8208\u5473\u6df1\u3044\u30d5\u30a1\u30a4\u30eb\u30d2\u30c3\u30c8\u30b3\u30e1\u30f3\u30c8
|
||||
Annotations.fileHitEntry.setName=\u30bb\u30c3\u30c8\u540d\:
|
||||
Annotations.onEmpty=\u3053\u306e\u30a2\u30a4\u30c6\u30e0\u306e\u6ce8\u91c8\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002
|
||||
Annotations.sourceFile.title=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
|
||||
Annotations.tagEntry.title=\u30bf\u30b0
|
||||
Annotations.tagEntryDataLabel.comment=\u30b3\u30e1\u30f3\u30c8\:
|
||||
Annotations.tagEntryDataLabel.tag=\u30bf\u30b0\:
|
||||
Annotations.tagEntryDataLabel.tagUser=\u5be9\u67fb\u5b98\uff1a
|
||||
Annotations.title=\u30a2\u30ce\u30c6\u30fc\u30b7\u30e7\u30f3
|
||||
Annotations.toolTip=\u9078\u629e\u3057\u305f\u30b3\u30f3\u30c6\u30f3\u30c4\u3068\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u308b\u30bf\u30b0\u3068\u30b3\u30e1\u30f3\u30c8\u3092\u8868\u793a\u3057\u307e\u3059\u3002
|
@ -8,7 +8,7 @@ StringsContentPanel.selectAllMenuItem.text=Select All
|
||||
StringsContentPanel.currentPageLabel.text_1=1
|
||||
StringsContentPanel.copyMenuItem.text=Copy
|
||||
StringsContentPanel.ofLabel.text_1=of
|
||||
StringsContentPanel.totalPageLabel.text_1=100
|
||||
StringsContentPanel.totalPageLabel.text_1=1000
|
||||
StringsContentPanel.languageLabel.toolTipText=
|
||||
StringsContentPanel.languageLabel.text=Script:
|
||||
StringsContentPanel.languageCombo.toolTipText=Language to attempt when interpreting (extracting and decoding) strings from binary data
|
||||
|
@ -9,7 +9,7 @@ StringsContentPanel.selectAllMenuItem.text=Select All
|
||||
StringsContentPanel.currentPageLabel.text_1=1
|
||||
StringsContentPanel.copyMenuItem.text=Copy
|
||||
StringsContentPanel.ofLabel.text_1=of
|
||||
StringsContentPanel.totalPageLabel.text_1=100
|
||||
StringsContentPanel.totalPageLabel.text_1=1000
|
||||
StringsContentPanel.languageLabel.toolTipText=
|
||||
StringsContentPanel.languageLabel.text=Script:
|
||||
StringsContentPanel.languageCombo.toolTipText=Language to attempt when interpreting (extracting and decoding) strings from binary data
|
||||
|
@ -103,15 +103,6 @@
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/textcontentviewer/Bundle.properties" key="StringsContentPanel.currentPageLabel.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[18, 25]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[7, 25]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[18, 25]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSeparator" name="jSepMed2">
|
||||
@ -158,13 +149,13 @@
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/textcontentviewer/Bundle.properties" key="StringsContentPanel.totalPageLabel.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[21, 25]"/>
|
||||
<Dimension value="[25, 25]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[21, 25]"/>
|
||||
<Dimension value="[25, 25]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[21, 25]"/>
|
||||
<Dimension value="[25, 25]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
@ -95,12 +95,11 @@ public class StringsContentPanel extends javax.swing.JPanel {
|
||||
currentPage = 1;
|
||||
currentOffset = 0;
|
||||
this.dataSource = null;
|
||||
currentPageLabel.setText("");
|
||||
currentPageLabel.setText("1");
|
||||
totalPageLabel.setText("");
|
||||
prevPageButton.setEnabled(false);
|
||||
nextPageButton.setEnabled(false);
|
||||
outputViewPane.setText(""); // reset the output view
|
||||
setComponentsVisibility(false); // hides the components that not needed
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,9 +166,6 @@ public class StringsContentPanel extends javax.swing.JPanel {
|
||||
panelPageOfCount.add(jSepMed1);
|
||||
|
||||
currentPageLabel.setText(org.openide.util.NbBundle.getMessage(StringsContentPanel.class, "StringsContentPanel.currentPageLabel.text_1")); // NOI18N
|
||||
currentPageLabel.setMaximumSize(new java.awt.Dimension(18, 25));
|
||||
currentPageLabel.setMinimumSize(new java.awt.Dimension(7, 25));
|
||||
currentPageLabel.setPreferredSize(new java.awt.Dimension(18, 25));
|
||||
panelPageOfCount.add(currentPageLabel);
|
||||
|
||||
jSepMed2.setPreferredSize(new java.awt.Dimension(5, 0));
|
||||
@ -185,9 +181,9 @@ public class StringsContentPanel extends javax.swing.JPanel {
|
||||
panelPageOfCount.add(jSepMed3);
|
||||
|
||||
totalPageLabel.setText(org.openide.util.NbBundle.getMessage(StringsContentPanel.class, "StringsContentPanel.totalPageLabel.text_1")); // NOI18N
|
||||
totalPageLabel.setMaximumSize(new java.awt.Dimension(21, 25));
|
||||
totalPageLabel.setMinimumSize(new java.awt.Dimension(21, 25));
|
||||
totalPageLabel.setPreferredSize(new java.awt.Dimension(21, 25));
|
||||
totalPageLabel.setMaximumSize(new java.awt.Dimension(25, 25));
|
||||
totalPageLabel.setMinimumSize(new java.awt.Dimension(25, 25));
|
||||
totalPageLabel.setPreferredSize(new java.awt.Dimension(25, 25));
|
||||
panelPageOfCount.add(totalPageLabel);
|
||||
|
||||
jSepMed4.setPreferredSize(new java.awt.Dimension(5, 0));
|
||||
@ -409,24 +405,6 @@ public class StringsContentPanel extends javax.swing.JPanel {
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* To set the visibility of specific components in this class.
|
||||
*
|
||||
* @param isVisible whether to show or hide the specific components
|
||||
*/
|
||||
private void setComponentsVisibility(boolean isVisible) {
|
||||
currentPageLabel.setVisible(isVisible);
|
||||
totalPageLabel.setVisible(isVisible);
|
||||
ofLabel.setVisible(isVisible);
|
||||
prevPageButton.setVisible(isVisible);
|
||||
nextPageButton.setVisible(isVisible);
|
||||
pageLabel.setVisible(isVisible);
|
||||
pageLabel2.setVisible(isVisible);
|
||||
goToPageTextField.setVisible(isVisible);
|
||||
goToPageLabel.setVisible(isVisible);
|
||||
languageCombo.setVisible(isVisible);
|
||||
languageLabel.setVisible(isVisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Swingworker for getting the text from a content object.
|
||||
@ -509,9 +487,7 @@ public class StringsContentPanel extends javax.swing.JPanel {
|
||||
|
||||
int totalPage = Math.round((dataSource.getSize() - 1) / PAGE_LENGTH) + 1;
|
||||
totalPageLabel.setText(Integer.toString(totalPage));
|
||||
currentPageLabel.setText("1");
|
||||
outputViewPane.setText(text); // set the output view
|
||||
setComponentsVisibility(true); // shows the components that not needed
|
||||
outputViewPane.moveCaretPosition(0);
|
||||
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
@ -557,10 +533,7 @@ public class StringsContentPanel extends javax.swing.JPanel {
|
||||
prevPageButton.setEnabled(false);
|
||||
currentPage = 1;
|
||||
|
||||
totalPageLabel.setText("1");
|
||||
currentPageLabel.setText("1");
|
||||
outputViewPane.setText(text); // set the output view
|
||||
setComponentsVisibility(true); // shows the components that not needed
|
||||
outputViewPane.moveCaretPosition(0);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
|
||||
|
@ -24,6 +24,7 @@ import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
/**
|
||||
* A DataContentViewer that displays text with the TextViewers available.
|
||||
@ -91,14 +92,10 @@ public class TextContentViewer implements DataContentViewer {
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the node's File, if it has one
|
||||
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// disable the text content viewer for directories and empty files
|
||||
if (file.isDir() || file.getSize() == 0) {
|
||||
if (file != null && (file.isDir() || file.getSize() == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Copyright 2012-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -39,7 +39,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
@ -102,7 +101,7 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
||||
* @param content Underlying Content instances
|
||||
*/
|
||||
AbstractContentNode(T content) {
|
||||
this(content, Lookups.singleton(content));
|
||||
this(content, Lookups.fixed(content, new TskContentItem<>(content)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
41
Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java
Executable file
41
Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java
Executable file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021-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.datamodel;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
|
||||
/**
|
||||
* An Autopsy Data Model item with an underlying AnalysisResult Sleuth Kit Data
|
||||
* Model object.
|
||||
*/
|
||||
public class AnalysisResultItem extends BlackboardArtifactItem<AnalysisResult> {
|
||||
|
||||
/**
|
||||
* Constructs an Autopsy Data Model item with an underlying AnalysisResult
|
||||
* Sleuth Kit Data Model object.
|
||||
*
|
||||
* @param analysisResult The AnalysisResult object.
|
||||
*/
|
||||
@Beta
|
||||
AnalysisResultItem(AnalysisResult analysisResult) {
|
||||
super(analysisResult);
|
||||
}
|
||||
|
||||
}
|
44
Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactItem.java
Executable file
44
Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactItem.java
Executable file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021-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.datamodel;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
/**
|
||||
* An abstract super class for an Autopsy Data Model item class with an
|
||||
* underlying BlackboardArtifact Sleuth Kit Data Model object, i.e., a
|
||||
* DataArtifact or an AnalysisResult.
|
||||
*
|
||||
* @param <T> The concrete BlackboardArtifact sub class type.
|
||||
*/
|
||||
public abstract class BlackboardArtifactItem<T extends BlackboardArtifact> extends TskContentItem<T> {
|
||||
|
||||
/**
|
||||
* Constructs an Autopsy Data Model item with an underlying
|
||||
* BlackboardArtifact Sleuth Kit Data Model object.
|
||||
*
|
||||
* @param blackboardArtifact The BlackboardArtifact object.
|
||||
*/
|
||||
@Beta
|
||||
BlackboardArtifactItem(T blackboardArtifact) {
|
||||
super(blackboardArtifact);
|
||||
}
|
||||
|
||||
}
|
@ -87,13 +87,14 @@ import org.sleuthkit.datamodel.BlackboardArtifact.Category;
|
||||
import org.sleuthkit.datamodel.HostAddress;
|
||||
import org.sleuthkit.datamodel.OsAccount;
|
||||
import org.sleuthkit.datamodel.Pool;
|
||||
import org.sleuthkit.datamodel.DataArtifact;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
import org.sleuthkit.datamodel.Volume;
|
||||
import org.sleuthkit.datamodel.VolumeSystem;
|
||||
|
||||
/**
|
||||
* A BlackboardArtifactNode is an AbstractNode implementation that can be used
|
||||
* to represent an artifact of any type.
|
||||
* An AbstractNode implementation that can be used to represent an data artifact
|
||||
* or analysis result of any type.
|
||||
*/
|
||||
public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
|
||||
|
||||
@ -227,37 +228,38 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
private final PropertyChangeListener weakListener = WeakListeners.propertyChange(listener, null);
|
||||
|
||||
/**
|
||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
||||
* can be used to represent an artifact of any type.
|
||||
* Constructs an AbstractNode implementation that can be used to represent a
|
||||
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||
* contain the data artifact or analysis result and its parent content as
|
||||
* its source content.
|
||||
*
|
||||
* @param artifact The artifact to represent.
|
||||
* @param iconPath The path to the icon for the artifact type.
|
||||
* @param artifact The data artifact or analysis result.
|
||||
* @param iconPath The path to the icon for the data artifact or analysis
|
||||
* result type.
|
||||
*/
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
|
||||
super(artifact, createLookup(artifact, false));
|
||||
this.artifact = artifact;
|
||||
this.artifactType = getType(artifact);
|
||||
|
||||
for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
|
||||
if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
|
||||
srcContent = lookupContent;
|
||||
try {
|
||||
/*
|
||||
* Calling this getter causes the unique path of the source
|
||||
* content to be cached in the Content object. This is
|
||||
* advantageous as long as this node is constructed in a
|
||||
* background thread instead of a UI thread.
|
||||
*/
|
||||
srcContent.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, MessageFormat.format("Error getting the unique path of the source content (artifact objID={0})", artifact.getId()), ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
srcContent = getSourceContentFromLookup(artifact);
|
||||
|
||||
if (srcContent == null) {
|
||||
throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact));
|
||||
}
|
||||
|
||||
try {
|
||||
/*
|
||||
* Calling this getter causes the unique path of the source content
|
||||
* to be cached in the Content object. This is advantageous as long
|
||||
* as this node is constructed in a background thread instead of a
|
||||
* UI thread.
|
||||
*/
|
||||
srcContent.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, MessageFormat.format("Error getting the unique path of the source content (artifact objID={0})", artifact.getId()), ex);
|
||||
}
|
||||
|
||||
setName(Long.toString(artifact.getArtifactID()));
|
||||
String displayName = srcContent.getName();
|
||||
setDisplayName(displayName);
|
||||
@ -267,26 +269,28 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
||||
* can be used to represent an artifact of any type.
|
||||
* Constructs an AbstractNode implementation that can be used to represent a
|
||||
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||
* contain the data artifact or analysis result and its source content,
|
||||
* either the parent content or the associated file.
|
||||
*
|
||||
* @param artifact The artifact to represent.
|
||||
* @param lookupIsAssociatedFile True if the Content lookup should be made
|
||||
* for the associated file instead of the
|
||||
* parent file.
|
||||
* @param artifact The data artifact or analysis result.
|
||||
* @param useAssociatedFileInLookup True if the source content in the Lookup
|
||||
* should be the associated file instead of
|
||||
* the parent content.
|
||||
*/
|
||||
@Beta
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact, boolean lookupIsAssociatedFile) {
|
||||
super(artifact, createLookup(artifact, lookupIsAssociatedFile));
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact, boolean useAssociatedFileInLookup) {
|
||||
super(artifact, createLookup(artifact, useAssociatedFileInLookup));
|
||||
this.artifact = artifact;
|
||||
this.artifactType = getType(artifact);
|
||||
|
||||
try {
|
||||
//The lookup for a file may or may not exist so we define the srcContent as the parent.
|
||||
srcContent = artifact.getParent();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, MessageFormat.format("Error getting the parent of the artifact for (artifact objID={0})", artifact.getId()), ex);
|
||||
}
|
||||
|
||||
if (srcContent != null) {
|
||||
try {
|
||||
/*
|
||||
@ -302,6 +306,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
} else {
|
||||
throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact));
|
||||
}
|
||||
|
||||
setName(Long.toString(artifact.getArtifactID()));
|
||||
String displayName = srcContent.getName();
|
||||
setDisplayName(displayName);
|
||||
@ -312,10 +317,12 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
||||
* can be used to represent an artifact of any type.
|
||||
* Constructs an AbstractNode implementation that can be used to represent a
|
||||
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||
* contain the data artifact or analysis result and its parent content as
|
||||
* its source content.
|
||||
*
|
||||
* @param artifact The artifact to represent.
|
||||
* @param artifact The data artifact or analysis result.
|
||||
*/
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact) {
|
||||
this(artifact, IconsUtil.getIconFilePath(artifact.getArtifactTypeID()));
|
||||
@ -341,54 +348,82 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* Creates a Lookup object for this node and populates it with both the
|
||||
* artifact this node represents and its source content.
|
||||
*
|
||||
* @param artifact The artifact this node represents.
|
||||
* @param artifact The artifact this node represents.
|
||||
* @param useAssociatedFile True if the source content in the Lookup should
|
||||
* be the associated file instead of the parent
|
||||
* content.
|
||||
*
|
||||
* @return The Lookup.
|
||||
*/
|
||||
private static Lookup createLookup(BlackboardArtifact artifact) {
|
||||
final long objectID = artifact.getObjectID();
|
||||
private static Lookup createLookup(BlackboardArtifact artifact, boolean useAssociatedFile) {
|
||||
/*
|
||||
* Get the source content.
|
||||
*/
|
||||
Content content = null;
|
||||
try {
|
||||
Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID));
|
||||
if (content == null) {
|
||||
return Lookups.fixed(artifact);
|
||||
if (useAssociatedFile) {
|
||||
content = getPathIdFile(artifact);
|
||||
} else {
|
||||
return Lookups.fixed(artifact, content);
|
||||
long srcObjectID = artifact.getObjectID();
|
||||
content = contentCache.get(srcObjectID, () -> artifact.getSleuthkitCase().getContentById(srcObjectID));
|
||||
}
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS
|
||||
return Lookups.fixed(artifact);
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source/associated content (artifact object ID={0})", artifact.getId()), ex); //NON-NLS
|
||||
}
|
||||
|
||||
/*
|
||||
* Make an Autopsy Data Model wrapper for the artifact.
|
||||
*
|
||||
* NOTE: The creation of an Autopsy Data Model independent of the
|
||||
* NetBeans nodes is a work in progress. At the time this comment is
|
||||
* being written, this object is only being used to indicate the item
|
||||
* represented by this BlackboardArtifactNode.
|
||||
*/
|
||||
BlackboardArtifactItem<?> artifactItem;
|
||||
if (artifact instanceof AnalysisResult) {
|
||||
artifactItem = new AnalysisResultItem((AnalysisResult) artifact);
|
||||
} else {
|
||||
artifactItem = new DataArtifactItem((DataArtifact) artifact);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the Lookup.
|
||||
*
|
||||
* NOTE: For now, we are putting both the Autopsy Data Model item and
|
||||
* the Sleuth Kit Data Model item in the Lookup so that code that is not
|
||||
* aware of the new Autopsy Data Model will still function.
|
||||
*/
|
||||
if (content == null) {
|
||||
return Lookups.fixed(artifact, artifactItem);
|
||||
} else {
|
||||
return Lookups.fixed(artifact, artifactItem, content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Lookup object for this node and populates it with both the
|
||||
* artifact this node represents and its source content.
|
||||
* Finds the source content in the Lookup created by createLookup() method.
|
||||
*
|
||||
* @param artifact The artifact this node represents.
|
||||
* @param lookupIsAssociatedFile True if the Content lookup should be made
|
||||
* for the associated file instead of the
|
||||
* parent file.
|
||||
* @param artifact Artifact who's source Content we are trying to find.
|
||||
*
|
||||
* @return The Lookup.
|
||||
* @return Source Content of the input artifact, if one exists. Null
|
||||
* otherwise.
|
||||
*/
|
||||
private static Lookup createLookup(BlackboardArtifact artifact, boolean lookupIsAssociatedFile) {
|
||||
Content content = null;
|
||||
if (lookupIsAssociatedFile) {
|
||||
try {
|
||||
content = getPathIdFile(artifact);
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS
|
||||
content = null;
|
||||
private Content getSourceContentFromLookup(BlackboardArtifact artifact) {
|
||||
for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
|
||||
/*
|
||||
* NOTE: createLookup() saves the artifact and its source content
|
||||
* (if one exists). However, createLookup() has to be static because
|
||||
* it is being called by super(), therefore it can't store the
|
||||
* source content in this.srcContent class variable. That's why we
|
||||
* have to have the logic below, which reads the Lookup contents,
|
||||
* and decides that the source content is the entry in Lookup that
|
||||
* is NOT the input artifact.
|
||||
*/
|
||||
if ((lookupContent != null) && (lookupContent.getId() != artifact.getId())) {
|
||||
return lookupContent;
|
||||
}
|
||||
if (content == null) {
|
||||
return Lookups.fixed(artifact);
|
||||
} else {
|
||||
return Lookups.fixed(artifact, content);
|
||||
}
|
||||
} else {
|
||||
return createLookup(artifact);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
41
Core/src/org/sleuthkit/autopsy/datamodel/DataArtifactItem.java
Executable file
41
Core/src/org/sleuthkit/autopsy/datamodel/DataArtifactItem.java
Executable file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021-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.datamodel;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.sleuthkit.datamodel.DataArtifact;
|
||||
|
||||
/**
|
||||
* An Autopsy Data Model item with an underlying DataArtifact Sleuth Kit Data
|
||||
* Model object.
|
||||
*/
|
||||
public class DataArtifactItem extends BlackboardArtifactItem<DataArtifact> {
|
||||
|
||||
/**
|
||||
* Constructs an Autopsy Data Model item with an underlying DataArtifact
|
||||
* Sleuth Kit Data Model object.
|
||||
*
|
||||
* @param dataArtifact The DataArtifact object.
|
||||
*/
|
||||
@Beta
|
||||
DataArtifactItem(DataArtifact dataArtifact) {
|
||||
super(dataArtifact);
|
||||
}
|
||||
|
||||
}
|
@ -99,6 +99,7 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
||||
* operation on this artifact type and return some object as the result of
|
||||
* the operation.
|
||||
*
|
||||
* @param <T> The return type.
|
||||
* @param visitor The visitor, where the type parameter of the visitor is
|
||||
* the type of the object that will be returned as the result
|
||||
* of the visit operation.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2020 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -22,19 +22,13 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
|
||||
/**
|
||||
@ -46,7 +40,6 @@ class GetSCOTask implements Runnable {
|
||||
|
||||
private final WeakReference<AbstractContentNode<?>> weakNodeRef;
|
||||
private final PropertyChangeListener listener;
|
||||
private static final Logger logger = Logger.getLogger(GetSCOTask.class.getName());
|
||||
|
||||
GetSCOTask(WeakReference<AbstractContentNode<?>> weakContentRef, PropertyChangeListener listener) {
|
||||
this.weakNodeRef = weakContentRef;
|
||||
@ -59,7 +52,7 @@ class GetSCOTask implements Runnable {
|
||||
public void run() {
|
||||
AbstractContentNode<?> contentNode = weakNodeRef.get();
|
||||
|
||||
//Check for stale reference or if columns are disabled
|
||||
//Check for stale reference or if columns are disabled
|
||||
if (contentNode == null || UserPreferences.getHideSCOColumns()) {
|
||||
return;
|
||||
}
|
||||
@ -72,49 +65,18 @@ class GetSCOTask implements Runnable {
|
||||
//because the Comment column will reflect the presence of comments in the CR when the CR is enabled, but reflect tag comments regardless
|
||||
CorrelationAttributeInstance fileAttribute = contentNode.getCorrelationAttributeInstance();
|
||||
scoData.setComment(contentNode.getCommentProperty(tags, fileAttribute));
|
||||
|
||||
if (CentralRepository.isEnabled()) {
|
||||
Type type = null;
|
||||
String value = null;
|
||||
String description = Bundle.GetSCOTask_occurrences_defaultDescription();
|
||||
if (contentNode instanceof BlackboardArtifactNode) {
|
||||
BlackboardArtifact bbArtifact = ((BlackboardArtifactNode) contentNode).getArtifact();
|
||||
//for specific artifact types we still want to display information for the file instance correlation attribute
|
||||
if (bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()
|
||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID()
|
||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
|
||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()
|
||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
|
||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()
|
||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()
|
||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
|
||||
try {
|
||||
if (bbArtifact.getParent() instanceof AbstractFile) {
|
||||
type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID);
|
||||
value = ((AbstractFile) bbArtifact.getParent()).getMd5Hash();
|
||||
}
|
||||
} catch (TskCoreException | CentralRepoException ex) {
|
||||
logger.log(Level.WARNING, "Unable to get correlation type or value to determine value for O column for artifact", ex);
|
||||
}
|
||||
} else {
|
||||
List<CorrelationAttributeInstance> listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact);
|
||||
if (listOfPossibleAttributes.size() > 1) {
|
||||
//Don't display anything if there is more than 1 correlation property for an artifact but let the user know
|
||||
description = Bundle.GetSCOTask_occurrences_multipleProperties();
|
||||
} else if (!listOfPossibleAttributes.isEmpty()) {
|
||||
//there should only be one item in the list
|
||||
type = listOfPossibleAttributes.get(0).getCorrelationType();
|
||||
value = listOfPossibleAttributes.get(0).getCorrelationValue();
|
||||
}
|
||||
}
|
||||
} else if (contentNode.getContent() instanceof AbstractFile) {
|
||||
//use the file instance correlation attribute if the node is not a BlackboardArtifactNode
|
||||
try {
|
||||
type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID);
|
||||
value = ((AbstractFile) contentNode.getContent()).getMd5Hash();
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.WARNING, "Unable to get correlation type to determine value for O column for file", ex);
|
||||
}
|
||||
List<CorrelationAttributeInstance> listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForSearch(contentNode.getContent());
|
||||
if (listOfPossibleAttributes.size() > 1) {
|
||||
//Don't display anything if there is more than 1 correlation property for an artifact but let the user know
|
||||
description = Bundle.GetSCOTask_occurrences_multipleProperties();
|
||||
} else if (!listOfPossibleAttributes.isEmpty()) {
|
||||
//there should only be one item in the list
|
||||
type = listOfPossibleAttributes.get(0).getCorrelationType();
|
||||
value = listOfPossibleAttributes.get(0).getCorrelationValue();
|
||||
}
|
||||
scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(type, value, description));
|
||||
}
|
||||
|
58
Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java
Executable file
58
Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java
Executable file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021-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.datamodel;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* An Autopsy Data Model item with an underlying Sleuth Kit Data Model object
|
||||
* that implements the Sleuth Kit Data Model's Content interface.
|
||||
*
|
||||
* @param <T> The type of the underlying Sleuth Kit Data Model object.
|
||||
*/
|
||||
@Beta
|
||||
public class TskContentItem<T extends Content> {
|
||||
|
||||
private final T content;
|
||||
|
||||
/**
|
||||
* Constructs an Autopsy Data Model item with an underlying Sleuth Kit Data
|
||||
* Model object that implements the Sleuth Kit Data Model's Content
|
||||
* interface.
|
||||
*
|
||||
* @param content The Sleuth Kit Data Model object.
|
||||
*
|
||||
*/
|
||||
@Beta
|
||||
TskContentItem(T content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying Sleuth Kit Data Model object.
|
||||
*
|
||||
* @return The Sleuth Kit Data Model object.
|
||||
*/
|
||||
@Beta
|
||||
public T getTskContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
@ -1481,7 +1481,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
final private class CreditCardNumberFactory extends ObservingChildren<Long> {
|
||||
final private class CreditCardNumberFactory extends ObservingChildren<DataArtifact> {
|
||||
|
||||
private final BinResult bin;
|
||||
|
||||
@ -1502,10 +1502,10 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Long> list) {
|
||||
protected boolean createKeys(List<DataArtifact> list) {
|
||||
|
||||
String query
|
||||
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
||||
= "SELECT blackboard_artifacts.artifact_obj_id " //NON-NLS
|
||||
+ " FROM blackboard_artifacts " //NON-NLS
|
||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||
@ -1517,7 +1517,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
||||
ResultSet rs = results.getResultSet();) {
|
||||
while (rs.next()) {
|
||||
list.add(rs.getLong("artifact_id")); //NON-NLS
|
||||
list.add(skCase.getBlackboard().getDataArtifactById(rs.getLong("artifact_obj_id"))); //NON-NLS
|
||||
}
|
||||
} catch (TskCoreException | SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS
|
||||
@ -1527,18 +1527,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node[] createNodesForKey(Long artifactID) {
|
||||
if (skCase == null) {
|
||||
return new Node[0];
|
||||
}
|
||||
|
||||
try {
|
||||
DataArtifact art = skCase.getBlackboard().getDataArtifactById(artifactID);
|
||||
return new Node[]{new AccountArtifactNode(art)};
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error creating BlackboardArtifactNode for artifact with ID " + artifactID, ex); //NON-NLS
|
||||
return new Node[0];
|
||||
}
|
||||
protected Node[] createNodesForKey(DataArtifact artifact) {
|
||||
return new Node[]{new AccountArtifactNode(artifact)};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,12 @@ public final class IconsUtil {
|
||||
imageFile = "gps-area.png"; //NON-NLS
|
||||
} else if (typeID == ARTIFACT_TYPE.TSK_YARA_HIT.getTypeID()) {
|
||||
imageFile = "yara_16.png"; //NON-NLS
|
||||
} else if (typeID == ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID()) {
|
||||
imageFile = "previously-seen.png"; //NON-NLS
|
||||
} else if (typeID == ARTIFACT_TYPE.TSK_PREVIOUSLY_UNSEEN.getTypeID()) {
|
||||
imageFile = "previously-unseen.png"; //NON-NLS
|
||||
} else if (typeID == ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE.getTypeID()) {
|
||||
imageFile = "red-circle-exclamation.png"; //NON-NLS
|
||||
} else {
|
||||
imageFile = "artifact-icon.png"; //NON-NLS
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -25,41 +25,43 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Provides information about how a datasource relates to a previous case. NOTE:
|
||||
* This code is fragile and has certain expectations about how the central
|
||||
* Provides information about how a data source relates to a previous case.
|
||||
* NOTE: This code is fragile and has certain expectations about how the central
|
||||
* repository handles creating artifacts. So, if the central repository changes
|
||||
* ingest process, this code could break. This code expects that the central
|
||||
* repository ingest module:
|
||||
*
|
||||
* a) Creates a TSK_INTERESTING_FILE_HIT artifact for a file whose hash is in
|
||||
* the central repository as a notable file.
|
||||
* a) Creates a TSK_PREVIOUSLY_NOTABLE artifact for a file whose hash is in the
|
||||
* central repository as a notable file.
|
||||
*
|
||||
* b) Creates a TSK_INTERESTING_ARTIFACT_HIT artifact for a matching id in the
|
||||
* central repository.
|
||||
* b) Creates a TSK_PREVIOUSLY_SEEN artifact for a matching id in the central
|
||||
* repository.
|
||||
*
|
||||
* c) The created artifact will have a TSK_COMMENT attribute attached where one
|
||||
* of the sources for the attribute matches
|
||||
* c) The created artifact will have a TSK_OTHER_CASES attribute attached where
|
||||
* one of the sources for the attribute matches
|
||||
* CentralRepoIngestModuleFactory.getModuleName(). The module display name at
|
||||
* time of ingest will match CentralRepoIngestModuleFactory.getModuleName() as
|
||||
* well.
|
||||
*
|
||||
* d) The content of that TSK_COMMENT attribute will be of the form "Previous
|
||||
* Case: case1,case2...caseN"
|
||||
* d) The content of that TSK_OTHER_CASES attribute will be of the form
|
||||
* "case1,case2...caseN"
|
||||
*/
|
||||
public class PastCasesSummary {
|
||||
|
||||
@ -97,9 +99,13 @@ public class PastCasesSummary {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE.getTypeID()
|
||||
));
|
||||
|
||||
private static final String CENTRAL_REPO_INGEST_NAME = CentralRepoIngestModuleFactory.getModuleName().toUpperCase().trim();
|
||||
private static final BlackboardAttribute.Type TYPE_COMMENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COMMENT);
|
||||
private static final BlackboardAttribute.Type TYPE_ASSOCIATED_ARTIFACT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT);
|
||||
private static final BlackboardAttribute.Type TYPE_COMMENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_OTHER_CASES);
|
||||
|
||||
private static final Set<Integer> CR_DEVICE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(),
|
||||
@ -109,7 +115,6 @@ public class PastCasesSummary {
|
||||
));
|
||||
|
||||
private static final String CASE_SEPARATOR = ",";
|
||||
private static final String PREFIX_END = ":";
|
||||
|
||||
private final SleuthkitCaseProvider caseProvider;
|
||||
private final java.util.logging.Logger logger;
|
||||
@ -161,9 +166,8 @@ public class PastCasesSummary {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of cases from the TSK_COMMENT of an artifact. The cases
|
||||
* string is expected to be of a form of "Previous Case:
|
||||
* case1,case2...caseN".
|
||||
* Gets a list of cases from the TSK_OTHER_CASES of an artifact. The cases
|
||||
* string is expected to be of a form of "case1,case2...caseN".
|
||||
*
|
||||
* @param artifact The artifact.
|
||||
*
|
||||
@ -189,14 +193,7 @@ public class PastCasesSummary {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String commentStr = commentAttr.getValueString();
|
||||
|
||||
int prefixCharIdx = commentStr.indexOf(PREFIX_END);
|
||||
if (prefixCharIdx < 0 || prefixCharIdx >= commentStr.length() - 1) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String justCasesStr = commentStr.substring(prefixCharIdx + 1).trim();
|
||||
String justCasesStr = commentAttr.getValueString().trim();
|
||||
return Stream.of(justCasesStr.split(CASE_SEPARATOR))
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toList());
|
||||
@ -231,30 +228,24 @@ public class PastCasesSummary {
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an artifact with a TYPE_ASSOCIATED_ARTIFACT attribute, retrieves
|
||||
* the related artifact.
|
||||
* Given a TSK_PREVIOUSLY_SEEN or TSK_PREVIOUSLY_NOTABLE artifact, retrieves it's parent artifact.
|
||||
*
|
||||
* @param artifact The artifact with the TYPE_ASSOCIATED_ARTIFACT attribute.
|
||||
* @param artifact The input artifact.
|
||||
*
|
||||
* @return The artifact if found or null if not.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
private BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException {
|
||||
Long parentId = DataSourceInfoUtilities.getLongOrNull(artifact, TYPE_ASSOCIATED_ARTIFACT);
|
||||
if (parentId == null) {
|
||||
return null;
|
||||
}
|
||||
private BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException {
|
||||
|
||||
BlackboardArtifact sourceArtifact = null;
|
||||
SleuthkitCase skCase = caseProvider.get();
|
||||
try {
|
||||
return skCase.getArtifactByArtifactId(parentId);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
String.format("There was an error fetching the parent artifact of a TSK_INTERESTING_ARTIFACT_HIT (parent id: %d)", parentId),
|
||||
ex);
|
||||
return null;
|
||||
Content content = skCase.getContentById(artifact.getObjectID());
|
||||
if (content instanceof BlackboardArtifact) {
|
||||
sourceArtifact = (BlackboardArtifact) content;
|
||||
}
|
||||
return sourceArtifact;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -264,9 +255,10 @@ public class PastCasesSummary {
|
||||
*
|
||||
* @return True if there is a device associated artifact.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
private boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException {
|
||||
private boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException {
|
||||
BlackboardArtifact parent = getParentArtifact(artifact);
|
||||
if (parent == null) {
|
||||
return false;
|
||||
@ -284,6 +276,7 @@ public class PastCasesSummary {
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
public PastCasesResult getPastCasesData(DataSource dataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException {
|
||||
@ -296,26 +289,24 @@ public class PastCasesSummary {
|
||||
|
||||
List<String> deviceArtifactCases = new ArrayList<>();
|
||||
List<String> nonDeviceArtifactCases = new ArrayList<>();
|
||||
for (Integer typeId : ARTIFACT_UPDATE_TYPE_IDS) {
|
||||
for (BlackboardArtifact artifact : skCase.getBlackboard().getArtifacts(typeId, dataSource.getId())) {
|
||||
List<String> cases = getCasesFromArtifact(artifact);
|
||||
if (cases == null || cases.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (BlackboardArtifact artifact : skCase.getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(), dataSource.getId())) {
|
||||
List<String> cases = getCasesFromArtifact(artifact);
|
||||
if (cases == null || cases.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasDeviceAssociatedArtifact(artifact)) {
|
||||
deviceArtifactCases.addAll(cases);
|
||||
} else {
|
||||
nonDeviceArtifactCases.addAll(cases);
|
||||
if (hasDeviceAssociatedArtifact(artifact)) {
|
||||
deviceArtifactCases.addAll(cases);
|
||||
} else {
|
||||
nonDeviceArtifactCases.addAll(cases);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Stream<String> filesCases = skCase.getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), dataSource.getId()).stream()
|
||||
.flatMap((art) -> getCasesFromArtifact(art).stream());
|
||||
|
||||
return new PastCasesResult(
|
||||
getCaseCounts(deviceArtifactCases.stream()),
|
||||
getCaseCounts(Stream.concat(filesCases, nonDeviceArtifactCases.stream()))
|
||||
getCaseCounts(nonDeviceArtifactCases.stream())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
BIN
Core/src/org/sleuthkit/autopsy/images/previously-seen.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/previously-seen.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
BIN
Core/src/org/sleuthkit/autopsy/images/previously-unseen.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/previously-unseen.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
@ -44,10 +44,10 @@ final class DataArtifactIngestPipeline extends IngestTaskPipeline<DataArtifactIn
|
||||
@Override
|
||||
Optional<PipelineModule<DataArtifactIngestTask>> acceptModuleTemplate(IngestModuleTemplate template) {
|
||||
Optional<IngestTaskPipeline.PipelineModule<DataArtifactIngestTask>> module = Optional.empty();
|
||||
if (template.isDataArtifactIngestModuleTemplate()) {
|
||||
DataArtifactIngestModule ingestModule = template.createDataArtifactIngestModule();
|
||||
module = Optional.of(new DataArtifactIngestPipelineModule(ingestModule, template.getModuleName()));
|
||||
}
|
||||
// if (template.isDataArtifactIngestModuleTemplate()) {
|
||||
// DataArtifactIngestModule ingestModule = template.createDataArtifactIngestModule();
|
||||
// module = Optional.of(new DataArtifactIngestPipelineModule(ingestModule, template.getModuleName()));
|
||||
// }
|
||||
return module;
|
||||
}
|
||||
|
||||
|
@ -368,9 +368,9 @@ final class IngestJobPipeline {
|
||||
if (template.isFileIngestModuleTemplate()) {
|
||||
addModuleTemplateToSortingMap(javaFileModuleTemplates, jythonFileModuleTemplates, template);
|
||||
}
|
||||
if (template.isDataArtifactIngestModuleTemplate()) {
|
||||
addModuleTemplateToSortingMap(javaArtifactModuleTemplates, jythonArtifactModuleTemplates, template);
|
||||
}
|
||||
// if (template.isDataArtifactIngestModuleTemplate()) {
|
||||
// addModuleTemplateToSortingMap(javaArtifactModuleTemplates, jythonArtifactModuleTemplates, template);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -616,13 +616,13 @@ final class IngestJobPipeline {
|
||||
type = IngestModuleType.MULTIPLE;
|
||||
}
|
||||
}
|
||||
if (moduleTemplate.isDataArtifactIngestModuleTemplate()) {
|
||||
if (type == null) {
|
||||
type = IngestModuleType.DATA_ARTIFACT;
|
||||
} else {
|
||||
type = IngestModuleType.MULTIPLE;
|
||||
}
|
||||
}
|
||||
// if (moduleTemplate.isDataArtifactIngestModuleTemplate()) {
|
||||
// if (type == null) {
|
||||
// type = IngestModuleType.DATA_ARTIFACT;
|
||||
// } else {
|
||||
// type = IngestModuleType.MULTIPLE;
|
||||
// }
|
||||
// }
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -318,7 +318,7 @@ public final class IngestJobSettings {
|
||||
|
||||
// Add modules that are going to be used for this ingest depending on type.
|
||||
for (IngestModuleFactory moduleFactory : allModuleFactories) {
|
||||
if (moduleFactory.isDataArtifactIngestModuleFactory() || ingestType.equals(IngestType.ALL_MODULES)) {
|
||||
if (/*moduleFactory.isDataArtifactIngestModuleFactory() ||*/ ingestType.equals(IngestType.ALL_MODULES)) {
|
||||
moduleFactories.add(moduleFactory);
|
||||
} else if (this.ingestType.equals(IngestType.DATA_SOURCE_ONLY) && moduleFactory.isDataSourceIngestModuleFactory()) {
|
||||
moduleFactories.add(moduleFactory);
|
||||
|
@ -228,7 +228,7 @@ public interface IngestModuleFactory {
|
||||
*
|
||||
* @return A file ingest module instance.
|
||||
*/
|
||||
default FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) {
|
||||
default FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@ -238,9 +238,9 @@ public interface IngestModuleFactory {
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
default boolean isDataArtifactIngestModuleFactory() {
|
||||
return false;
|
||||
}
|
||||
// default boolean isDataArtifactIngestModuleFactory() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Creates a data artifact ingest module instance.
|
||||
@ -267,8 +267,8 @@ public interface IngestModuleFactory {
|
||||
*
|
||||
* @return A file ingest module instance.
|
||||
*/
|
||||
default DataArtifactIngestModule createDataArtifactIngestModule(IngestModuleIngestJobSettings settings) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
// default DataArtifactIngestModule createDataArtifactIngestModule(IngestModuleIngestJobSettings settings) {
|
||||
// throw new UnsupportedOperationException();
|
||||
// }
|
||||
|
||||
}
|
||||
|
@ -85,13 +85,13 @@ public final class IngestModuleTemplate {
|
||||
return moduleFactory.createFileIngestModule(settings);
|
||||
}
|
||||
|
||||
public boolean isDataArtifactIngestModuleTemplate() {
|
||||
return moduleFactory.isDataArtifactIngestModuleFactory();
|
||||
}
|
||||
// public boolean isDataArtifactIngestModuleTemplate() {
|
||||
// return moduleFactory.isDataArtifactIngestModuleFactory();
|
||||
// }
|
||||
|
||||
public DataArtifactIngestModule createDataArtifactIngestModule() {
|
||||
return moduleFactory.createDataArtifactIngestModule(settings);
|
||||
}
|
||||
// public DataArtifactIngestModule createDataArtifactIngestModule() {
|
||||
// return moduleFactory.createDataArtifactIngestModule(settings);
|
||||
// }
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
|
@ -337,6 +337,14 @@ final class CustomFileTypesManager {
|
||||
fileType = new FileType("application/x.android-hdb", signatureList);
|
||||
autopsyDefinedFileTypes.add(fileType);
|
||||
|
||||
/**
|
||||
* Add custom type for fixed-size VHDs.
|
||||
*/
|
||||
signatureList.clear();
|
||||
signatureList.add(new Signature("conectix", 511L, false)); //NON-NLS
|
||||
fileType = new FileType("application/x-vhd", signatureList); //NON-NLS
|
||||
autopsyDefinedFileTypes.add(fileType);
|
||||
|
||||
} catch (IllegalArgumentException ex) {
|
||||
/*
|
||||
* parseHexBinary() throws this if the argument passed in is not hex
|
||||
|
@ -394,6 +394,15 @@ public class HTMLReport implements TableReportModule {
|
||||
case TSK_YARA_HIT:
|
||||
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/yara_16.png"); //NON-NLS
|
||||
break;
|
||||
case TSK_PREVIOUSLY_SEEN:
|
||||
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/previously-seen.png"); //NON-NLS
|
||||
break;
|
||||
case TSK_PREVIOUSLY_UNSEEN:
|
||||
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/previously-unseen.png"); //NON-NLS
|
||||
break;
|
||||
case TSK_PREVIOUSLY_NOTABLE:
|
||||
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"); //NON-NLS
|
||||
break;
|
||||
default:
|
||||
logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = {0}", dataType); //NON-NLS
|
||||
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -30,23 +30,33 @@ import javax.annotation.concurrent.Immutable;
|
||||
public final class Manifest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final Path filePath;
|
||||
|
||||
// NOTE: Path is not Serializable. That's why we have to have a String as well,
|
||||
// for scenarios when we send Manifest via ActiveMQ to other nodes.
|
||||
private transient Path filePath;
|
||||
private final String filePathString;
|
||||
private transient Path dataSourcePath;
|
||||
private final String dataSourcePathString;
|
||||
|
||||
private final Date dateFileCreated;
|
||||
private final String caseName;
|
||||
private final String deviceId;
|
||||
private final Path dataSourcePath;
|
||||
private final String dataSourceFileName;
|
||||
private final Map<String, String> manifestProperties;
|
||||
|
||||
public Manifest(Path manifestFilePath, Date dateFileCreated, String caseName, String deviceId, Path dataSourcePath, Map<String, String> manifestProperties) {
|
||||
this.filePath = Paths.get(manifestFilePath.toString());
|
||||
this.filePathString = manifestFilePath.toString();
|
||||
this.filePath = Paths.get(filePathString);
|
||||
|
||||
this.dateFileCreated = new Date(dateFileCreated.getTime());
|
||||
this.caseName = caseName;
|
||||
this.deviceId = deviceId;
|
||||
if (null != dataSourcePath) {
|
||||
this.dataSourcePath = Paths.get(dataSourcePath.toString());
|
||||
this.dataSourcePathString = dataSourcePath.toString();
|
||||
this.dataSourcePath = Paths.get(dataSourcePathString);
|
||||
dataSourceFileName = dataSourcePath.getFileName().toString();
|
||||
} else {
|
||||
this.dataSourcePathString = "";
|
||||
this.dataSourcePath = Paths.get("");
|
||||
dataSourceFileName = "";
|
||||
}
|
||||
@ -54,6 +64,10 @@ public final class Manifest implements Serializable {
|
||||
}
|
||||
|
||||
public Path getFilePath() {
|
||||
// after potential deserialization Path will be null because it is transient
|
||||
if (filePath == null) {
|
||||
this.filePath = Paths.get(filePathString);
|
||||
}
|
||||
return this.filePath;
|
||||
}
|
||||
|
||||
@ -70,6 +84,10 @@ public final class Manifest implements Serializable {
|
||||
}
|
||||
|
||||
public Path getDataSourcePath() {
|
||||
// after potential deserialization Path will be null because it is transient
|
||||
if (dataSourcePath == null) {
|
||||
this.dataSourcePath = Paths.get(dataSourcePathString);
|
||||
}
|
||||
return dataSourcePath;
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,12 @@
|
||||
package org.sleuthkit.autopsy.recentactivity;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
@ -63,7 +65,7 @@ class ShellBagParser {
|
||||
|
||||
ShellBagParser sbparser = new ShellBagParser();
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(regfile), StandardCharsets.UTF_8))) {
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
line = line.trim();
|
||||
|
24
thirdparty/rr-full/plugins/shellbags.pl
vendored
24
thirdparty/rr-full/plugins/shellbags.pl
vendored
@ -779,7 +779,7 @@ sub parseFolderEntry {
|
||||
$tag = 0;
|
||||
}
|
||||
else {
|
||||
$str .= $s;
|
||||
$str .= $s;
|
||||
$cnt++;
|
||||
}
|
||||
}
|
||||
@ -799,7 +799,7 @@ sub parseFolderEntry {
|
||||
$tag = 0;
|
||||
}
|
||||
else {
|
||||
$str .= $s;
|
||||
$str .= $s;
|
||||
$cnt++;
|
||||
}
|
||||
}
|
||||
@ -858,13 +858,12 @@ sub parseFolderEntry {
|
||||
|
||||
my $str = substr($data,$ofs,length($data) - 30);
|
||||
my $longname = (split(/\00\00/,$str,2))[0];
|
||||
$longname =~ s/\00//g;
|
||||
|
||||
if ($longname ne "") {
|
||||
$item{name} = $longname;
|
||||
$item{name} = Utf16ToUtf8($longname);
|
||||
}
|
||||
else {
|
||||
$item{name} = $shortname;
|
||||
$item{name} = UTF16ToUtf8($shortname);
|
||||
}
|
||||
}
|
||||
return %item;
|
||||
@ -957,7 +956,7 @@ sub parseFolderEntry2 {
|
||||
|
||||
$item{name} = (split(/\00\00/,$str,2))[0];
|
||||
$item{name} =~ s/\13\20/\2D\00/;
|
||||
$item{name} =~ s/\00//g;
|
||||
$item{name} = Utf16ToUtf8($item{name});
|
||||
|
||||
return %item;
|
||||
}
|
||||
@ -1024,7 +1023,7 @@ sub shellItem0x52 {
|
||||
$tag = 0;
|
||||
}
|
||||
else {
|
||||
$item{name} .= $d;
|
||||
$item{name} .= $d;
|
||||
$cnt += 2;
|
||||
}
|
||||
}
|
||||
@ -1119,4 +1118,15 @@ sub getNum48 {
|
||||
}
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Utf16ToUtf8()
|
||||
#---------------------------------------------------------------------
|
||||
sub Utf16ToUtf8 {
|
||||
my $str = $_[0];
|
||||
Encode::from_to($str,'UTF-16LE','utf8');
|
||||
$str = Encode::decode_utf8($str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
1;
|
5
thirdparty/rr-full/plugins/shellbags_test.pl
vendored
5
thirdparty/rr-full/plugins/shellbags_test.pl
vendored
@ -411,12 +411,13 @@ sub parseFolderItem {
|
||||
$longname =~ s/\x00//g;
|
||||
|
||||
if ($longname ne "") {
|
||||
$item{name} = $longname;
|
||||
$item{name} = Utf16ToUtf8($longname);
|
||||
}
|
||||
else {
|
||||
$item{name} = $shortname;
|
||||
$item{name} = Utf16ToUtf8($shortname);
|
||||
}
|
||||
return %item;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
18
thirdparty/rr-full/plugins/shellbags_xp.pl
vendored
18
thirdparty/rr-full/plugins/shellbags_xp.pl
vendored
@ -776,13 +776,13 @@ sub parseFolderEntry {
|
||||
|
||||
$str = substr($data,$ofs,length($data) - 30);
|
||||
my $longname = (split(/\x00\x00/,$str,2))[0];
|
||||
$longname =~ s/\x00//g;
|
||||
$longname = $longname.chr 0x00;
|
||||
|
||||
if ($longname ne "") {
|
||||
$item{name} = $longname;
|
||||
$item{name} = Utf16ToUtf8($longname);
|
||||
}
|
||||
else {
|
||||
$item{name} = $shortname;
|
||||
$item{name} = Utf16ToUtf8($shortname);
|
||||
}
|
||||
return %item;
|
||||
}
|
||||
@ -871,7 +871,7 @@ sub parseFolderEntry2 {
|
||||
|
||||
$item{name} = (split(/\x00\x00/,$str,2))[0];
|
||||
$item{name} =~ s/\x13\x20/\x2D\x00/;
|
||||
$item{name} =~ s/\x00//g;
|
||||
$item{name} = Utf16ToUtf8($item{name});
|
||||
|
||||
return %item;
|
||||
}
|
||||
@ -931,4 +931,14 @@ sub printData {
|
||||
return @display;
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Utf16ToUtf8()
|
||||
#---------------------------------------------------------------------
|
||||
sub Utf16ToUtf8 {
|
||||
my $str = $_[0];
|
||||
Encode::from_to($str,'UTF-16LE','utf8');
|
||||
my $str2 = Encode::decode_utf8($str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
1;
|
||||
|
17
thirdparty/rr-full/shellitems.pl
vendored
17
thirdparty/rr-full/shellitems.pl
vendored
@ -27,6 +27,7 @@
|
||||
# Author: H. Carvey, keydet89@yahoo.com
|
||||
#-----------------------------------------------------------
|
||||
use Time::Local;
|
||||
use Encode::Unicode;
|
||||
|
||||
my %guids = ("{bb64f8a7-bee7-4e1a-ab8d-7d8273f7fdb6}" => "Action Center",
|
||||
"{7a979262-40ce-46ff-aeee-7884ac3b6136}" => "Add Hardware",
|
||||
@ -634,10 +635,10 @@ sub parseFolderEntry {
|
||||
$longname =~ s/\x00//g;
|
||||
|
||||
if ($longname ne "") {
|
||||
$item{name} = $longname;
|
||||
$item{name} = Utf16ToUtf8($longname);
|
||||
}
|
||||
else {
|
||||
$item{name} = $shortname;
|
||||
$item{name} = Utf16ToUtf8($shortname);
|
||||
}
|
||||
return %item;
|
||||
}
|
||||
@ -716,7 +717,7 @@ sub parseFolderEntry2 {
|
||||
|
||||
$item{name} = (split(/\x00\x00/,$str,2))[0];
|
||||
$item{name} =~ s/\x13\x20/\x2D\x00/;
|
||||
$item{name} =~ s/\x00//g;
|
||||
$item{name} = Utf16ToUtf8($item{name});
|
||||
|
||||
return %item;
|
||||
}
|
||||
@ -837,4 +838,14 @@ sub getNum48 {
|
||||
}
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Utf16ToUtf8()
|
||||
#---------------------------------------------------------------------
|
||||
sub Utf16ToUtf8 {
|
||||
my $str = $_[0];
|
||||
Encode::from_to($str,'UTF-16LE','utf8');
|
||||
$str = Encode::decode_utf8($str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user