mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
Merge pull request #6515 from dannysmyda/7063-crPreviouslyNotable
7063 cr previously notable
This commit is contained in:
commit
ac0963e55c
@ -10,6 +10,7 @@ DiscoveryAttributes.GroupingAttributeType.none.displayName=None
|
|||||||
DiscoveryAttributes.GroupingAttributeType.numberOfVisits.displayName=Number of Visits
|
DiscoveryAttributes.GroupingAttributeType.numberOfVisits.displayName=Number of Visits
|
||||||
DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected
|
DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected
|
||||||
DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder
|
DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder
|
||||||
|
DiscoveryAttributes.GroupingAttributeType.previouslyNotable.displayName=Previous Notability
|
||||||
DiscoveryAttributes.GroupingAttributeType.size.displayName=File Size
|
DiscoveryAttributes.GroupingAttributeType.size.displayName=File Size
|
||||||
DiscoveryAttributes.GroupingAttributeType.tag.displayName=Tag
|
DiscoveryAttributes.GroupingAttributeType.tag.displayName=Tag
|
||||||
# {0} - Data source name
|
# {0} - Data source name
|
||||||
@ -87,6 +88,8 @@ SearchData.Frequency.rare.displayName=Rare (2-10)
|
|||||||
SearchData.Frequency.unique.displayName=Unique (1)
|
SearchData.Frequency.unique.displayName=Unique (1)
|
||||||
SearchData.Frequency.unknown.displayName=Unknown
|
SearchData.Frequency.unknown.displayName=Unknown
|
||||||
SearchData.Frequency.verycommon.displayName=Very Common (100+)
|
SearchData.Frequency.verycommon.displayName=Very Common (100+)
|
||||||
|
SearchData.notPrevNotable.displayName=Previously Not Notable
|
||||||
|
SearchData.prevNotable.displayName=Previously Notable
|
||||||
SearchData.Score.interesting.displayName=Interesting
|
SearchData.Score.interesting.displayName=Interesting
|
||||||
SearchData.Score.notable.displayName=Notable
|
SearchData.Score.notable.displayName=Notable
|
||||||
SearchData.Score.unknown.displayName=Unknown
|
SearchData.Score.unknown.displayName=Unknown
|
||||||
@ -128,6 +131,7 @@ SearchFiltering.ParentSearchTerm.excludeString=\ (exclude)
|
|||||||
SearchFiltering.ParentSearchTerm.fullString=\ (exact)
|
SearchFiltering.ParentSearchTerm.fullString=\ (exact)
|
||||||
SearchFiltering.ParentSearchTerm.includeString=\ (include)
|
SearchFiltering.ParentSearchTerm.includeString=\ (include)
|
||||||
SearchFiltering.ParentSearchTerm.subString=\ (substring)
|
SearchFiltering.ParentSearchTerm.subString=\ (substring)
|
||||||
|
SearchFiltering.PreviouslyNotableFilter.desc=Previously marked as notable in central repository
|
||||||
# {0} - filters
|
# {0} - filters
|
||||||
SearchFiltering.ScoreFilter.desc=Score(s) of : {0}
|
SearchFiltering.ScoreFilter.desc=Score(s) of : {0}
|
||||||
# {0} - filters
|
# {0} - filters
|
||||||
|
@ -216,6 +216,141 @@ public class DiscoveryAttributes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organizes the domain instances by normalized domain value.
|
||||||
|
* This helps reduce the complexity of updating ResultDomain instances
|
||||||
|
* after the query has been executed.
|
||||||
|
*
|
||||||
|
* Example: query for notable status of google.com. Result: notable
|
||||||
|
* With this map, all domain instances that represent google.com can
|
||||||
|
* be updated after one simple lookup.
|
||||||
|
*/
|
||||||
|
private static Map<String, List<ResultDomain>> organizeByValue(List<ResultDomain> domainsBatch, CorrelationAttributeInstance.Type attributeType) {
|
||||||
|
final Map<String, List<ResultDomain>> resultDomainTable = new HashMap<>();
|
||||||
|
for (ResultDomain domainInstance : domainsBatch) {
|
||||||
|
try {
|
||||||
|
final String domainValue = domainInstance.getDomain();
|
||||||
|
final String normalizedDomain = CorrelationAttributeNormalizer.normalize(attributeType, domainValue);
|
||||||
|
final List<ResultDomain> bucket = resultDomainTable.getOrDefault(normalizedDomain, new ArrayList<>());
|
||||||
|
bucket.add(domainInstance);
|
||||||
|
resultDomainTable.put(normalizedDomain, bucket);
|
||||||
|
} catch (CorrelationAttributeNormalizationException ex) {
|
||||||
|
logger.log(Level.INFO, String.format("Domain [%s] failed normalization, skipping...", domainInstance.getDomain()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultDomainTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to create a string of comma separated values.
|
||||||
|
* Each value is wrapped in `'`. This method is used to bundle up
|
||||||
|
* a collection of values for use in a SQL WHERE IN (...) clause.
|
||||||
|
*/
|
||||||
|
private static String createCSV(Set<String> values) {
|
||||||
|
StringJoiner joiner = new StringJoiner(", ");
|
||||||
|
for (String value : values) {
|
||||||
|
joiner.add("'" + value + "'");
|
||||||
|
}
|
||||||
|
return joiner.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute for grouping/sorting by notability in the CR.
|
||||||
|
*/
|
||||||
|
static class PreviouslyNotableAttribute extends AttributeType {
|
||||||
|
|
||||||
|
static final int DOMAIN_BATCH_SIZE = 500; // Number of domains to look up at one time
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) {
|
||||||
|
return new DiscoveryKeyUtils.PreviouslyNotableGroupKey(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||||
|
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||||
|
|
||||||
|
if (centralRepoDb != null) {
|
||||||
|
processFilesWithCr(results, centralRepoDb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processFilesWithCr(List<Result> results, CentralRepository centralRepo) throws DiscoveryException {
|
||||||
|
|
||||||
|
List<ResultDomain> domainsBatch = new ArrayList<>();
|
||||||
|
for (Result result : results) {
|
||||||
|
if (result.getType() == SearchData.Type.DOMAIN) {
|
||||||
|
domainsBatch.add((ResultDomain) result);
|
||||||
|
if (domainsBatch.size() == DOMAIN_BATCH_SIZE) {
|
||||||
|
queryPreviouslyNotable(domainsBatch, centralRepo);
|
||||||
|
domainsBatch.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queryPreviouslyNotable(domainsBatch, centralRepo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryPreviouslyNotable(List<ResultDomain> domainsBatch, CentralRepository centralRepo) throws DiscoveryException {
|
||||||
|
if (domainsBatch.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final CorrelationAttributeInstance.Type attributeType = centralRepo.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID);
|
||||||
|
final Map<String, List<ResultDomain>> resultDomainTable = organizeByValue(domainsBatch, attributeType);
|
||||||
|
final String values = createCSV(resultDomainTable.keySet());
|
||||||
|
|
||||||
|
final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType);
|
||||||
|
final String domainFrequencyQuery = " value AS domain_name "
|
||||||
|
+ "FROM " + tableName + " "
|
||||||
|
+ "WHERE value IN (" + values + ") "
|
||||||
|
+ "AND known_status = " + TskData.FileKnown.BAD.getFileKnownValue();
|
||||||
|
|
||||||
|
final DomainPreviouslyNotableCallback previouslyNotableCallback = new DomainPreviouslyNotableCallback(resultDomainTable);
|
||||||
|
centralRepo.processSelectClause(domainFrequencyQuery, previouslyNotableCallback);
|
||||||
|
|
||||||
|
if (previouslyNotableCallback.getCause() != null) {
|
||||||
|
throw previouslyNotableCallback.getCause();
|
||||||
|
}
|
||||||
|
} catch (CentralRepoException | SQLException ex) {
|
||||||
|
throw new DiscoveryException("Fatal exception encountered querying the CR.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DomainPreviouslyNotableCallback implements InstanceTableCallback {
|
||||||
|
|
||||||
|
private final Map<String, List<ResultDomain>> domainLookup;
|
||||||
|
private SQLException sqlCause;
|
||||||
|
|
||||||
|
private DomainPreviouslyNotableCallback(Map<String, List<ResultDomain>> domainLookup) {
|
||||||
|
this.domainLookup = domainLookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(ResultSet resultSet) {
|
||||||
|
try {
|
||||||
|
while (resultSet.next()) {
|
||||||
|
String domain = resultSet.getString("domain_name");
|
||||||
|
List<ResultDomain> domainInstances = domainLookup.get(domain);
|
||||||
|
for (ResultDomain domainInstance : domainInstances) {
|
||||||
|
domainInstance.markAsPreviouslyNotableInCR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
this.sqlCause = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the SQL exception if one occurred during this callback.
|
||||||
|
*/
|
||||||
|
SQLException getCause() {
|
||||||
|
return this.sqlCause;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute for grouping/sorting by frequency in the central repository.
|
* Attribute for grouping/sorting by frequency in the central repository.
|
||||||
*/
|
*/
|
||||||
@ -307,27 +442,14 @@ public class DiscoveryAttributes {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final Map<String, List<ResultDomain>> resultDomainTable = new HashMap<>();
|
|
||||||
final StringJoiner joiner = new StringJoiner(", ");
|
|
||||||
|
|
||||||
final CorrelationAttributeInstance.Type attributeType = centralRepository.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID);
|
final CorrelationAttributeInstance.Type attributeType = centralRepository.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID);
|
||||||
for (ResultDomain domainInstance : domainsToQuery) {
|
final Map<String, List<ResultDomain>> resultDomainTable = organizeByValue(domainsToQuery, attributeType);
|
||||||
try {
|
final String values = createCSV(resultDomainTable.keySet());
|
||||||
final String domainValue = domainInstance.getDomain();
|
|
||||||
final String normalizedDomain = CorrelationAttributeNormalizer.normalize(attributeType, domainValue);
|
|
||||||
final List<ResultDomain> bucket = resultDomainTable.getOrDefault(normalizedDomain, new ArrayList<>());
|
|
||||||
bucket.add(domainInstance);
|
|
||||||
resultDomainTable.put(normalizedDomain, bucket);
|
|
||||||
joiner.add("'" + normalizedDomain + "'");
|
|
||||||
} catch (CorrelationAttributeNormalizationException ex) {
|
|
||||||
logger.log(Level.INFO, String.format("Domain [%s] failed normalization, skipping...", domainInstance.getDomain()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType);
|
final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType);
|
||||||
final String domainFrequencyQuery = " value AS domain_name, COUNT(*) AS frequency "
|
final String domainFrequencyQuery = " value AS domain_name, COUNT(*) AS frequency "
|
||||||
+ "FROM " + tableName + " "
|
+ "FROM " + tableName + " "
|
||||||
+ "WHERE value IN (" + joiner + ") "
|
+ "WHERE value IN (" + values + ") "
|
||||||
+ "GROUP BY value";
|
+ "GROUP BY value";
|
||||||
|
|
||||||
final DomainFrequencyCallback frequencyCallback = new DomainFrequencyCallback(resultDomainTable);
|
final DomainFrequencyCallback frequencyCallback = new DomainFrequencyCallback(resultDomainTable);
|
||||||
@ -743,7 +865,8 @@ public class DiscoveryAttributes {
|
|||||||
"DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date",
|
"DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date",
|
||||||
"DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date",
|
"DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date",
|
||||||
"DiscoveryAttributes.GroupingAttributeType.numberOfVisits.displayName=Number of Visits",
|
"DiscoveryAttributes.GroupingAttributeType.numberOfVisits.displayName=Number of Visits",
|
||||||
"DiscoveryAttributes.GroupingAttributeType.none.displayName=None"})
|
"DiscoveryAttributes.GroupingAttributeType.none.displayName=None",
|
||||||
|
"DiscoveryAttributes.GroupingAttributeType.previouslyNotable.displayName=Previous Notability"})
|
||||||
public enum GroupingAttributeType {
|
public enum GroupingAttributeType {
|
||||||
FILE_SIZE(new FileSizeAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_size_displayName()),
|
FILE_SIZE(new FileSizeAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_size_displayName()),
|
||||||
FREQUENCY(new FrequencyAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_frequency_displayName()),
|
FREQUENCY(new FrequencyAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_frequency_displayName()),
|
||||||
@ -757,7 +880,8 @@ public class DiscoveryAttributes {
|
|||||||
MOST_RECENT_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_mostRecentDate_displayName()),
|
MOST_RECENT_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_mostRecentDate_displayName()),
|
||||||
FIRST_DATE(new FirstActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_firstDate_displayName()),
|
FIRST_DATE(new FirstActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_firstDate_displayName()),
|
||||||
NUMBER_OF_VISITS(new NumberOfVisitsAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_numberOfVisits_displayName()),
|
NUMBER_OF_VISITS(new NumberOfVisitsAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_numberOfVisits_displayName()),
|
||||||
NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName());
|
NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName()),
|
||||||
|
PREVIOUSLY_NOTABLE(new PreviouslyNotableAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_previouslyNotable_displayName());
|
||||||
|
|
||||||
private final AttributeType attributeType;
|
private final AttributeType attributeType;
|
||||||
private final String displayName;
|
private final String displayName;
|
||||||
@ -799,12 +923,12 @@ public class DiscoveryAttributes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of enums that are valid for grouping files.
|
* Get the list of enums that are valid for grouping domains.
|
||||||
*
|
*
|
||||||
* @return Enums that can be used to group files.
|
* @return Enums that can be used to group files.
|
||||||
*/
|
*/
|
||||||
public static List<GroupingAttributeType> getOptionsForGroupingForDomains() {
|
public static List<GroupingAttributeType> getOptionsForGroupingForDomains() {
|
||||||
return Arrays.asList(FREQUENCY, MOST_RECENT_DATE, FIRST_DATE, NUMBER_OF_VISITS);
|
return Arrays.asList(FREQUENCY, MOST_RECENT_DATE, FIRST_DATE, NUMBER_OF_VISITS, PREVIOUSLY_NOTABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -889,4 +1013,4 @@ public class DiscoveryAttributes {
|
|||||||
private DiscoveryAttributes() {
|
private DiscoveryAttributes() {
|
||||||
// Class should not be instantiated
|
// Class should not be instantiated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -793,6 +793,50 @@ public class DiscoveryKeyUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key representing a central repository notable status.
|
||||||
|
*/
|
||||||
|
static class PreviouslyNotableGroupKey extends GroupKey {
|
||||||
|
|
||||||
|
private final SearchData.PreviouslyNotable notableStatus;
|
||||||
|
|
||||||
|
PreviouslyNotableGroupKey(Result result) {
|
||||||
|
this.notableStatus = result.getPreviouslyNotableInCR();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getDisplayName() {
|
||||||
|
return this.notableStatus.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object otherKey) {
|
||||||
|
if (otherKey instanceof GroupKey) {
|
||||||
|
return compareTo((GroupKey) otherKey) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getStatus().getRanking());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(GroupKey otherGroupKey) {
|
||||||
|
if (otherGroupKey instanceof PreviouslyNotableGroupKey) {
|
||||||
|
PreviouslyNotableGroupKey otherFrequencyGroupKey = (PreviouslyNotableGroupKey) otherGroupKey;
|
||||||
|
return Integer.compare(getStatus().getRanking(), otherFrequencyGroupKey.getStatus().getRanking());
|
||||||
|
} else {
|
||||||
|
return compareClassNames(otherGroupKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchData.PreviouslyNotable getStatus() {
|
||||||
|
return notableStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key representing a central repository frequency group.
|
* Key representing a central repository frequency group.
|
||||||
*/
|
*/
|
||||||
|
@ -31,6 +31,7 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
public abstract class Result {
|
public abstract class Result {
|
||||||
|
|
||||||
private SearchData.Frequency frequency = SearchData.Frequency.UNKNOWN;
|
private SearchData.Frequency frequency = SearchData.Frequency.UNKNOWN;
|
||||||
|
private SearchData.PreviouslyNotable notabilityStatus = SearchData.PreviouslyNotable.NOT_PREVIOUSLY_NOTABLE;
|
||||||
private final List<String> tagNames = new ArrayList<>();
|
private final List<String> tagNames = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,12 +51,28 @@ public abstract class Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the known status of the result.
|
* Get the known status of the result (known status being NSRL).
|
||||||
*
|
*
|
||||||
* @return The Known status of the result.
|
* @return The Known status of the result.
|
||||||
*/
|
*/
|
||||||
public abstract TskData.FileKnown getKnown();
|
public abstract TskData.FileKnown getKnown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the result as being previously notable in the CR.
|
||||||
|
*/
|
||||||
|
final public void markAsPreviouslyNotableInCR() {
|
||||||
|
this.notabilityStatus = SearchData.PreviouslyNotable.PREVIOUSLY_NOTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the previously notable value of this result.
|
||||||
|
*
|
||||||
|
* @return The previously notable status enum.
|
||||||
|
*/
|
||||||
|
final public SearchData.PreviouslyNotable getPreviouslyNotableInCR() {
|
||||||
|
return this.notabilityStatus;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the frequency of this result in the central repository.
|
* Set the frequency of this result in the central repository.
|
||||||
*
|
*
|
||||||
|
@ -38,6 +38,35 @@ public final class SearchData {
|
|||||||
private final static long BYTES_PER_MB = 1000000;
|
private final static long BYTES_PER_MB = 1000000;
|
||||||
private static final Set<BlackboardArtifact.ARTIFACT_TYPE> DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY);
|
private static final Set<BlackboardArtifact.ARTIFACT_TYPE> DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing the notability of the result in the Central Repository.
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"SearchData.prevNotable.displayName=Previously Notable",
|
||||||
|
"SearchData.notPrevNotable.displayName=Previously Not Notable"
|
||||||
|
})
|
||||||
|
public enum PreviouslyNotable {
|
||||||
|
PREVIOUSLY_NOTABLE(0, Bundle.SearchData_prevNotable_displayName()),
|
||||||
|
NOT_PREVIOUSLY_NOTABLE(1, Bundle.SearchData_notPrevNotable_displayName());
|
||||||
|
|
||||||
|
private final int ranking;
|
||||||
|
private final String displayName;
|
||||||
|
|
||||||
|
PreviouslyNotable(int ranking, String displayName) {
|
||||||
|
this.ranking = ranking;
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRanking() {
|
||||||
|
return ranking;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Enum representing how often the result occurs in the Central Repository.
|
* Enum representing how often the result occurs in the Central Repository.
|
||||||
*/
|
*/
|
||||||
|
@ -690,6 +690,46 @@ public class SearchFiltering {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filter for previously notable content in the central repository.
|
||||||
|
*/
|
||||||
|
public static class PreviouslyNotableFilter extends AbstractFilter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWhereClause() {
|
||||||
|
throw new UnsupportedOperationException("Not supported, this is an alternative filter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useAlternateFilter() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
|
||||||
|
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||||
|
DiscoveryAttributes.PreviouslyNotableAttribute previouslyNotableAttr = new DiscoveryAttributes.PreviouslyNotableAttribute();
|
||||||
|
previouslyNotableAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb);
|
||||||
|
|
||||||
|
List<Result> filteredResults = new ArrayList<>();
|
||||||
|
for (Result file : currentResults) {
|
||||||
|
if (file.getPreviouslyNotableInCR() == SearchData.PreviouslyNotable.PREVIOUSLY_NOTABLE) {
|
||||||
|
filteredResults.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"SearchFiltering.PreviouslyNotableFilter.desc=Previously marked as notable in central repository"
|
||||||
|
})
|
||||||
|
@Override
|
||||||
|
public String getDesc() {
|
||||||
|
return Bundle.SearchFiltering_PreviouslyNotableFilter_desc();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A filter for specifying hash set names. A file must match one of the
|
* A filter for specifying hash set names. A file must match one of the
|
||||||
* given sets to pass.
|
* given sets to pass.
|
||||||
|
@ -114,8 +114,8 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li
|
|||||||
constraints.weightx = LABEL_WEIGHT;
|
constraints.weightx = LABEL_WEIGHT;
|
||||||
constraints.weighty = LABEL_WEIGHT;
|
constraints.weighty = LABEL_WEIGHT;
|
||||||
constraints.gridwidth = LABEL_WIDTH;
|
constraints.gridwidth = LABEL_WIDTH;
|
||||||
addToGridBagLayout(filterPanel.getCheckbox(), filterPanel.getAdditionalLabel(), column);
|
|
||||||
if (filterPanel.hasPanel()) {
|
if (filterPanel.hasPanel()) {
|
||||||
|
addToGridBagLayout(filterPanel.getCheckbox(), filterPanel.getAdditionalLabel(), column);
|
||||||
constraints.gridx += constraints.gridwidth;
|
constraints.gridx += constraints.gridwidth;
|
||||||
constraints.fill = GridBagConstraints.BOTH;
|
constraints.fill = GridBagConstraints.BOTH;
|
||||||
constraints.gridheight = PANEL_HEIGHT;
|
constraints.gridheight = PANEL_HEIGHT;
|
||||||
@ -123,6 +123,11 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li
|
|||||||
constraints.weighty = PANEL_WEIGHT;
|
constraints.weighty = PANEL_WEIGHT;
|
||||||
constraints.gridwidth = PANEL_WIDTH;
|
constraints.gridwidth = PANEL_WIDTH;
|
||||||
addToGridBagLayout(filterPanel, null, column);
|
addToGridBagLayout(filterPanel, null, column);
|
||||||
|
} else {
|
||||||
|
constraints.weightx = PANEL_WEIGHT;
|
||||||
|
constraints.fill = GridBagConstraints.BOTH;
|
||||||
|
constraints.gridwidth = PANEL_WIDTH + LABEL_WIDTH;
|
||||||
|
addToGridBagLayout(filterPanel.getCheckbox(), filterPanel.getAdditionalLabel(), column);
|
||||||
}
|
}
|
||||||
if (column == 0) {
|
if (column == 0) {
|
||||||
firstColumnY += constraints.gridheight;
|
firstColumnY += constraints.gridheight;
|
||||||
|
@ -60,3 +60,4 @@ DomainSummaryPanel.totalVisitsLabel.text=
|
|||||||
FileDetailsPanel.instancesList.border.title=Instances
|
FileDetailsPanel.instancesList.border.title=Instances
|
||||||
CookieDetailsPanel.jLabel1.text=Artifact:
|
CookieDetailsPanel.jLabel1.text=Artifact:
|
||||||
CookieDetailsPanel.jLabel2.text=
|
CookieDetailsPanel.jLabel2.text=
|
||||||
|
PreviouslyNotableFilterPanel.text_1=Include only previously notable domains
|
||||||
|
@ -147,6 +147,7 @@ DomainSummaryPanel.totalVisitsLabel.text=
|
|||||||
FileDetailsPanel.instancesList.border.title=Instances
|
FileDetailsPanel.instancesList.border.title=Instances
|
||||||
CookieDetailsPanel.jLabel1.text=Artifact:
|
CookieDetailsPanel.jLabel1.text=Artifact:
|
||||||
CookieDetailsPanel.jLabel2.text=
|
CookieDetailsPanel.jLabel2.text=
|
||||||
|
PreviouslyNotableFilterPanel.text_1=Include only previously notable domains
|
||||||
VideoThumbnailPanel.bytes.text=bytes
|
VideoThumbnailPanel.bytes.text=bytes
|
||||||
VideoThumbnailPanel.deleted.text=All instances of file are deleted.
|
VideoThumbnailPanel.deleted.text=All instances of file are deleted.
|
||||||
VideoThumbnailPanel.gigaBytes.text=GB
|
VideoThumbnailPanel.gigaBytes.text=GB
|
||||||
|
@ -40,6 +40,7 @@ public class DomainFilterPanel extends AbstractFiltersPanel {
|
|||||||
super();
|
super();
|
||||||
initComponents();
|
initComponents();
|
||||||
addFilter(new DataSourceFilterPanel(), false, null, 0);
|
addFilter(new DataSourceFilterPanel(), false, null, 0);
|
||||||
|
addFilter(new PreviouslyNotableFilterPanel(), false, null, 1);
|
||||||
addFilter(new ArtifactTypeFilterPanel(), false, null, 1);
|
addFilter(new ArtifactTypeFilterPanel(), false, null, 1);
|
||||||
addFilter(new DateFilterPanel(), false, null, 1);
|
addFilter(new DateFilterPanel(), false, null, 1);
|
||||||
int[] pastOccurrencesIndices = null;
|
int[] pastOccurrencesIndices = null;
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<NonVisualComponents>
|
||||||
|
<Component class="javax.swing.JCheckBox" name="previouslyNotableCheckbox">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/discovery/ui/Bundle.properties" key="PreviouslyNotableFilterPanel.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="[255, 25]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[0, 25]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
||||||
|
<Property name="opaque" type="boolean" value="false"/>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[255, 25]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="requestFocusEnabled" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</NonVisualComponents>
|
||||||
|
<Properties>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[0, 30]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[255, 30]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<EmptySpace min="0" pref="42" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
</Form>
|
120
Core/src/org/sleuthkit/autopsy/discovery/ui/PreviouslyNotableFilterPanel.java
Executable file
120
Core/src/org/sleuthkit/autopsy/discovery/ui/PreviouslyNotableFilterPanel.java
Executable file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy
|
||||||
|
*
|
||||||
|
* Copyright 2020 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.discovery.ui;
|
||||||
|
|
||||||
|
import org.sleuthkit.autopsy.discovery.search.AbstractFilter;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
|
import org.sleuthkit.autopsy.discovery.search.SearchFiltering;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel to allow configuration of the previously notable (in CR) filter.
|
||||||
|
*/
|
||||||
|
final class PreviouslyNotableFilterPanel extends AbstractDiscoveryFilterPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
|
PreviouslyNotableFilterPanel() {
|
||||||
|
initComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from within the constructor to initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
* regenerated by the Form Editor.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
previouslyNotableCheckbox = new javax.swing.JCheckBox();
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(previouslyNotableCheckbox, org.openide.util.NbBundle.getMessage(PreviouslyNotableFilterPanel.class, "PreviouslyNotableFilterPanel.text_1")); // NOI18N
|
||||||
|
previouslyNotableCheckbox.setMaximumSize(new java.awt.Dimension(255, 25));
|
||||||
|
previouslyNotableCheckbox.setMinimumSize(new java.awt.Dimension(0, 25));
|
||||||
|
previouslyNotableCheckbox.setName(""); // NOI18N
|
||||||
|
previouslyNotableCheckbox.setOpaque(false);
|
||||||
|
previouslyNotableCheckbox.setPreferredSize(new java.awt.Dimension(255, 25));
|
||||||
|
previouslyNotableCheckbox.setRequestFocusEnabled(false);
|
||||||
|
|
||||||
|
setMinimumSize(new java.awt.Dimension(0, 30));
|
||||||
|
setPreferredSize(new java.awt.Dimension(255, 30));
|
||||||
|
setVerifyInputWhenFocusTarget(false);
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
|
this.setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGap(0, 300, Short.MAX_VALUE)
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGap(0, 42, Short.MAX_VALUE)
|
||||||
|
);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
|
@Override
|
||||||
|
void configurePanel(boolean selected, int[] indicesSelected) {
|
||||||
|
previouslyNotableCheckbox.setSelected(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
|
@Override
|
||||||
|
JCheckBox getCheckbox() {
|
||||||
|
return previouslyNotableCheckbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
JLabel getAdditionalLabel() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String checkForError() {
|
||||||
|
//this filter currently has no errors it generates
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JCheckBox previouslyNotableCheckbox;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
@Override
|
||||||
|
JList<?> getList() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
|
@Override
|
||||||
|
AbstractFilter getFilter() {
|
||||||
|
if (previouslyNotableCheckbox.isSelected()) {
|
||||||
|
return new SearchFiltering.PreviouslyNotableFilter();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean hasPanel() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user