mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into 6459-Package-CASE-json-exporter
This commit is contained in:
commit
aa6d70060f
@ -54,6 +54,11 @@
|
||||
<fileset dir="${thirdparty.dir}/7-Zip"/>
|
||||
</copy>
|
||||
|
||||
<!--Copy InterestingFileSetRules to release-->
|
||||
<copy todir="${basedir}/release/InterestingFileSetRules" >
|
||||
<fileset dir="${thirdparty.dir}/InterestingFileSetRules"/>
|
||||
</copy>
|
||||
|
||||
<!-- The 'libgstlibav.dll' file is too big to store on GitHub, so we
|
||||
have it stored in a ZIP file. We'll extract it in place and remove
|
||||
the ZIP file afterward. -->
|
||||
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||
OpenIDE-Module: org.sleuthkit.autopsy.core/10
|
||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
|
||||
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
|
||||
OpenIDE-Module-Implementation-Version: 31
|
||||
OpenIDE-Module-Implementation-Version: 32
|
||||
OpenIDE-Module-Requires: org.openide.windows.WindowManager
|
||||
AutoUpdate-Show-In-Client: true
|
||||
AutoUpdate-Essential-Module: true
|
||||
|
@ -139,5 +139,5 @@ nbm.homepage=http://www.sleuthkit.org/
|
||||
nbm.module.author=Brian Carrier
|
||||
nbm.needs.restart=true
|
||||
source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
|
||||
spec.version.base=10.19
|
||||
spec.version.base=10.20
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -139,7 +139,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
if (!tagNamesMap.isEmpty()) {
|
||||
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
|
||||
TagName tagName = entry.getValue();
|
||||
TagSet tagSet = tagName.getTagSet();
|
||||
TagSet tagSet = tagsManager.getTagSet(tagName);
|
||||
|
||||
// Show custom tags before predefined tags in the menu
|
||||
if (tagSet != null) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -23,7 +23,6 @@ import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -36,7 +35,6 @@ import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.KeyStroke;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
@ -150,7 +148,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
try {
|
||||
TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
|
||||
List<String> standardTagNames = TagsManager.getStandardTagNames();
|
||||
Map<String, TagName> tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap());
|
||||
@ -161,7 +159,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
tagNamesMap.entrySet().stream().map((entry) -> entry.getValue()).forEachOrdered((tagName) -> {
|
||||
TagSet tagSet = null;
|
||||
try {
|
||||
tagSet = tagName.getTagSet();
|
||||
tagSet = tagsManager.getTagSet(tagName);
|
||||
} catch (TskCoreException ex) {
|
||||
Logger.getLogger(GetTagNameAndCommentDialog.class
|
||||
.getName()).log(Level.SEVERE, "Failed to get tag set", ex); //NON-NLS
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Copyright 2018-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -131,7 +131,7 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
||||
if (!tagNamesMap.isEmpty()) {
|
||||
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
|
||||
TagName tagName = entry.getValue();
|
||||
TagSet tagSet = tagName.getTagSet();
|
||||
TagSet tagSet = tagsManager.getTagSet(tagName);
|
||||
|
||||
// Show custom tags before predefined tags in the menu
|
||||
if (tagSet != null) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2020 Basis Technology Corp.
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -56,7 +56,7 @@ public class TagsManager implements Closeable {
|
||||
private final SleuthkitCase caseDb;
|
||||
|
||||
private static String DEFAULT_TAG_SET_NAME = "Project VIC";
|
||||
|
||||
|
||||
private static final Object lock = new Object();
|
||||
|
||||
static {
|
||||
@ -235,16 +235,16 @@ public class TagsManager implements Closeable {
|
||||
public static String getNotableTagDisplayName() {
|
||||
return TagNameDefinition.getNotableTagDisplayName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new TagSetDefinition file.
|
||||
*
|
||||
*
|
||||
* @param tagSetDef The tag set definition.
|
||||
*
|
||||
* @throws IOException
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void addTagSetDefinition(TagSetDefinition tagSetDef) throws IOException {
|
||||
synchronized(lock) {
|
||||
synchronized (lock) {
|
||||
TagSetDefinition.writeTagSetDefinition(tagSetDef);
|
||||
}
|
||||
}
|
||||
@ -267,20 +267,20 @@ public class TagsManager implements Closeable {
|
||||
caseDb.addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus());
|
||||
}
|
||||
//Assume new case and add tag sets
|
||||
for(TagSetDefinition setDef: TagSetDefinition.readTagSetDefinitions()) {
|
||||
for (TagSetDefinition setDef : TagSetDefinition.readTagSetDefinitions()) {
|
||||
List<TagName> tagNameList = new ArrayList<>();
|
||||
for(TagNameDefinition tagNameDef: setDef.getTagNameDefinitions()) {
|
||||
for (TagNameDefinition tagNameDef : setDef.getTagNameDefinitions()) {
|
||||
tagNameList.add(caseDb.addOrUpdateTagName(tagNameDef.getDisplayName(), tagNameDef.getDescription(), tagNameDef.getColor(), tagNameDef.getKnownStatus()));
|
||||
}
|
||||
|
||||
if(!tagNameList.isEmpty()) {
|
||||
|
||||
if (!tagNameList.isEmpty()) {
|
||||
taggingMgr.addTagSet(setDef.getName(), tagNameList);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error updating standard tag name and tag set definitions", ex);
|
||||
} catch(IOException ex) {
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error loading tag set JSON files", ex);
|
||||
}
|
||||
|
||||
@ -288,28 +288,41 @@ public class TagsManager implements Closeable {
|
||||
tagName.saveToCase(caseDb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of all tag sets currently in the case database.
|
||||
*
|
||||
*
|
||||
* @return A list, possibly empty, of TagSet objects.
|
||||
*
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<TagSet> getAllTagSets() throws TskCoreException {
|
||||
return caseDb.getTaggingManager().getTagSets();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the tag set a tag name (tag definition) belongs to, if any.
|
||||
*
|
||||
* @param tagName The tag name.
|
||||
*
|
||||
* @return A TagSet object or null.
|
||||
*
|
||||
* @throws TskCoreException If there is an error querying the case database.
|
||||
*/
|
||||
public TagSet getTagSet(TagName tagName) throws TskCoreException {
|
||||
return caseDb.getTaggingManager().getTagSet(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new TagSet to the case database. Tags will be ranked in the order
|
||||
* which they are passed to this method.
|
||||
*
|
||||
* @param name Tag set name.
|
||||
*
|
||||
* @param name Tag set name.
|
||||
* @param tagNameList List of TagName in rank order.
|
||||
*
|
||||
*
|
||||
* @return A new TagSet object.
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public TagSet addTagSet(String name, List<TagName> tagNameList) throws TskCoreException {
|
||||
return caseDb.getTaggingManager().addTagSet(name, tagNameList);
|
||||
@ -501,7 +514,7 @@ public class TagsManager implements Closeable {
|
||||
* name to the case database.
|
||||
*/
|
||||
public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException {
|
||||
synchronized(lock) {
|
||||
synchronized (lock) {
|
||||
try {
|
||||
TagName tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus);
|
||||
Set<TagNameDefinition> customTypes = TagNameDefinition.getTagNameDefinitions();
|
||||
|
@ -1,9 +1,9 @@
|
||||
OpenIDE-Module-Name=Central Repository
|
||||
OpenIDE-Module-Display-Category=Ingest Module
|
||||
OpenIDE-Module-Short-Description=Correlation Engine Ingest Module
|
||||
OpenIDE-Module-Short-Description=Central Repository Ingest Module
|
||||
OpenIDE-Module-Long-Description=\
|
||||
Correlation Engine ingest module and central database. \n\n\
|
||||
The Correlation Engine ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\
|
||||
Central Repository ingest module and central database. \n\n\
|
||||
The Central Repository ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\
|
||||
Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest.
|
||||
CentralRepoCommentDialog.commentLabel.text=Comment:
|
||||
CentralRepoCommentDialog.okButton.text=&OK
|
||||
|
@ -4,10 +4,10 @@ AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoCommentNoMD5=Add/
|
||||
CentralRepoCommentDialog.title.addEditCentralRepoComment=Add/Edit Central Repository Comment
|
||||
OpenIDE-Module-Name=Central Repository
|
||||
OpenIDE-Module-Display-Category=Ingest Module
|
||||
OpenIDE-Module-Short-Description=Correlation Engine Ingest Module
|
||||
OpenIDE-Module-Short-Description=Central Repository Ingest Module
|
||||
OpenIDE-Module-Long-Description=\
|
||||
Correlation Engine ingest module and central database. \n\n\
|
||||
The Correlation Engine ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\
|
||||
Central Repository ingest module and central database. \n\n\
|
||||
The Central Repository ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\
|
||||
Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest.
|
||||
CentralRepoCommentDialog.commentLabel.text=Comment:
|
||||
CentralRepoCommentDialog.okButton.text=&OK
|
||||
|
@ -28,7 +28,7 @@ import org.sleuthkit.datamodel.TskDataException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Stores information about a Data Source in the correlation engine
|
||||
* Stores information about a Data Source in the Central Repository
|
||||
*
|
||||
*/
|
||||
public class CorrelationDataSource implements Serializable {
|
||||
|
@ -234,7 +234,7 @@ public class Persona {
|
||||
private static Persona createPersona(String name, String comment, PersonaStatus status) throws CentralRepoException {
|
||||
// generate a UUID for the persona
|
||||
String uuidStr = UUID.randomUUID().toString();
|
||||
CentralRepoExaminer examiner = CentralRepository.getInstance().getOrInsertExaminer(System.getProperty("user.name"));
|
||||
CentralRepoExaminer examiner = getCRInstance().getOrInsertExaminer(System.getProperty("user.name"));
|
||||
|
||||
Instant instant = Instant.now();
|
||||
Long timeStampMillis = instant.toEpochMilli();
|
||||
@ -248,22 +248,22 @@ public class Persona {
|
||||
+ examiner.getId()
|
||||
+ ")";
|
||||
|
||||
CentralRepository.getInstance().executeInsertSQL(insertClause);
|
||||
getCRInstance().executeInsertSQL(insertClause);
|
||||
return getPersonaByUUID(uuidStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the comment of this persona.
|
||||
*
|
||||
* @param name The new comment.
|
||||
* @param comment The new comment.
|
||||
*
|
||||
* @throws CentralRepoException If there is an error.
|
||||
*/
|
||||
public void setComment(String comment) throws CentralRepoException {
|
||||
String updateClause = "UPDATE personas SET comment = \"" + comment + "\" WHERE id = " + id;
|
||||
String updateClause = "UPDATE personas SET comment = '" + comment + "' WHERE id = " + id;
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
if (cr != null) {
|
||||
cr.executeUpdateSQL(updateClause);
|
||||
getCRInstance().executeUpdateSQL(updateClause);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,7 +275,7 @@ public class Persona {
|
||||
* @throws CentralRepoException If there is an error.
|
||||
*/
|
||||
public void setName(String name) throws CentralRepoException {
|
||||
String updateClause = "UPDATE personas SET name = \"" + name + "\" WHERE id = " + id;
|
||||
String updateClause = "UPDATE personas SET name = '" + name + "' WHERE id = " + id;
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
if (cr != null) {
|
||||
cr.executeUpdateSQL(updateClause);
|
||||
@ -313,7 +313,9 @@ public class Persona {
|
||||
/**
|
||||
* Modifies the confidence / justification of the given PersonaAccount
|
||||
*
|
||||
* @param account account to modify
|
||||
* @param account Account to modify.
|
||||
* @param confidence Level of confidence.
|
||||
* @param justification Justification.
|
||||
*
|
||||
* @throws CentralRepoException If there is an error in querying the
|
||||
* Personas table.
|
||||
@ -329,7 +331,7 @@ public class Persona {
|
||||
String deleteSQL = "UPDATE personas SET status_id = " + PersonaStatus.DELETED.status_id + " WHERE id = " + this.id;
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
if (cr != null) {
|
||||
cr.executeDeleteSQL(deleteSQL);
|
||||
cr.executeUpdateSQL(deleteSQL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,7 +397,7 @@ public class Persona {
|
||||
+ "WHERE p.uuid = '" + uuid + "'";
|
||||
|
||||
PersonaQueryCallback queryCallback = new PersonaQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
Collection<Persona> personas = queryCallback.getPersonas();
|
||||
|
||||
@ -420,7 +422,7 @@ public class Persona {
|
||||
" AND LOWER(p.name) LIKE " + "LOWER('%" + partialName + "%')" ;
|
||||
|
||||
PersonaQueryCallback queryCallback = new PersonaQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
return queryCallback.getPersonas();
|
||||
}
|
||||
@ -485,7 +487,9 @@ public class Persona {
|
||||
/**
|
||||
* Modifies the given alias.
|
||||
*
|
||||
* @param alias alias to modify
|
||||
* @param key Key for the alias to modify.
|
||||
* @param confidence Level of confidence.
|
||||
* @param justification Justification.
|
||||
*
|
||||
* @throws CentralRepoException If there is an error in querying the
|
||||
* Personas table.
|
||||
@ -535,7 +539,9 @@ public class Persona {
|
||||
/**
|
||||
* Modifies the given metadata.
|
||||
*
|
||||
* @param metadata metadata to modify
|
||||
* @param key Key for the metadata to modify.
|
||||
* @param confidence Level of confidence.
|
||||
* @param justification Justification.
|
||||
*
|
||||
* @throws CentralRepoException If there is an error in querying the
|
||||
* Personas table.
|
||||
@ -580,7 +586,7 @@ public class Persona {
|
||||
|
||||
while (resultSet.next()) {
|
||||
// get Case for case_id
|
||||
CorrelationCase correlationCase = CentralRepository.getInstance().getCaseById(resultSet.getInt("case_id"));
|
||||
CorrelationCase correlationCase = getCRInstance().getCaseById(resultSet.getInt("case_id"));
|
||||
correlationCases.add(correlationCase);
|
||||
}
|
||||
}
|
||||
@ -605,14 +611,14 @@ public class Persona {
|
||||
Collection<CentralRepoAccount> accounts = PersonaAccount.getAccountsForPersona(this.getId());
|
||||
for (CentralRepoAccount account : accounts) {
|
||||
int corrTypeId = account.getAccountType().getCorrelationTypeId();
|
||||
CorrelationAttributeInstance.Type correlationType = CentralRepository.getInstance().getCorrelationTypeById(corrTypeId);
|
||||
CorrelationAttributeInstance.Type correlationType = getCRInstance().getCorrelationTypeById(corrTypeId);
|
||||
|
||||
String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(correlationType);
|
||||
String querySql = "SELECT DISTINCT case_id FROM " + tableName
|
||||
+ " WHERE account_id = " + account.getId();
|
||||
|
||||
CaseForAccountInstanceQueryCallback queryCallback = new CaseForAccountInstanceQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(querySql, queryCallback);
|
||||
getCRInstance().executeSelectSQL(querySql, queryCallback);
|
||||
|
||||
// Add any cases that aren't already on the list.
|
||||
for (CorrelationCase corrCase : queryCallback.getCases()) {
|
||||
@ -639,8 +645,8 @@ public class Persona {
|
||||
while (resultSet.next()) {
|
||||
// get Case for case_id
|
||||
|
||||
CorrelationCase correlationCase = CentralRepository.getInstance().getCaseById(resultSet.getInt("case_id"));
|
||||
CorrelationDataSource correlationDatasource = CentralRepository.getInstance().getDataSourceById(correlationCase, resultSet.getInt("data_source_id"));
|
||||
CorrelationCase correlationCase = getCRInstance().getCaseById(resultSet.getInt("case_id"));
|
||||
CorrelationDataSource correlationDatasource = getCRInstance().getDataSourceById(correlationCase, resultSet.getInt("data_source_id"));
|
||||
|
||||
// Add data source to list if not already on it.
|
||||
if (!correlationDataSources.stream().anyMatch(p -> Objects.equals(p.getDataSourceObjectID(), correlationDatasource.getDataSourceObjectID()))) {
|
||||
@ -668,14 +674,14 @@ public class Persona {
|
||||
Collection<CentralRepoAccount> accounts = PersonaAccount.getAccountsForPersona(this.getId());
|
||||
for (CentralRepoAccount account : accounts) {
|
||||
int corrTypeId = account.getAccountType().getCorrelationTypeId();
|
||||
CorrelationAttributeInstance.Type correlationType = CentralRepository.getInstance().getCorrelationTypeById(corrTypeId);
|
||||
CorrelationAttributeInstance.Type correlationType = getCRInstance().getCorrelationTypeById(corrTypeId);
|
||||
|
||||
String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(correlationType);
|
||||
String querySql = "SELECT case_id, data_source_id FROM " + tableName
|
||||
+ " WHERE account_id = " + account.getId();
|
||||
|
||||
DatasourceForAccountInstanceQueryCallback queryCallback = new DatasourceForAccountInstanceQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(querySql, queryCallback);
|
||||
getCRInstance().executeSelectSQL(querySql, queryCallback);
|
||||
|
||||
// Add any data sources that aren't already on the list.
|
||||
for (CorrelationDataSource correlationDatasource : queryCallback.getDataSources()) {
|
||||
@ -738,7 +744,7 @@ public class Persona {
|
||||
private static String getPersonaFromInstanceTableQueryTemplate(CentralRepoAccount.CentralRepoAccountType crAccountType) throws CentralRepoException {
|
||||
|
||||
int corrTypeId = crAccountType.getCorrelationTypeId();
|
||||
CorrelationAttributeInstance.Type correlationType = CentralRepository.getInstance().getCorrelationTypeById(corrTypeId);
|
||||
CorrelationAttributeInstance.Type correlationType = getCRInstance().getCorrelationTypeById(corrTypeId);
|
||||
|
||||
String instanceTableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(correlationType);
|
||||
return "SELECT " + instanceTableName + ".account_id, case_id, data_source_id, "
|
||||
@ -762,7 +768,7 @@ public class Persona {
|
||||
public static Collection<Persona> getPersonasForCase(CorrelationCase correlationCase) throws CentralRepoException {
|
||||
Collection<Persona> personaList = new ArrayList<>();
|
||||
|
||||
Collection<CentralRepoAccount.CentralRepoAccountType> accountTypes = CentralRepository.getInstance().getAllAccountTypes();
|
||||
Collection<CentralRepoAccount.CentralRepoAccountType> accountTypes = getCRInstance().getAllAccountTypes();
|
||||
for (CentralRepoAccount.CentralRepoAccountType crAccountType : accountTypes) {
|
||||
|
||||
String querySql = getPersonaFromInstanceTableQueryTemplate(crAccountType)
|
||||
@ -770,7 +776,7 @@ public class Persona {
|
||||
+ "AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId();
|
||||
|
||||
PersonaFromAccountInstanceQueryCallback queryCallback = new PersonaFromAccountInstanceQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(querySql, queryCallback);
|
||||
getCRInstance().executeSelectSQL(querySql, queryCallback);
|
||||
|
||||
// Add persona that aren't already on the list.
|
||||
for (Persona persona : queryCallback.getPersonasList()) {
|
||||
@ -794,7 +800,7 @@ public class Persona {
|
||||
public static Collection<Persona> getPersonasForDataSource(CorrelationDataSource dataSource) throws CentralRepoException {
|
||||
Collection<Persona> personaList = new ArrayList<>();
|
||||
|
||||
Collection<CentralRepoAccount.CentralRepoAccountType> accountTypes = CentralRepository.getInstance().getAllAccountTypes();
|
||||
Collection<CentralRepoAccount.CentralRepoAccountType> accountTypes = getCRInstance().getAllAccountTypes();
|
||||
for (CentralRepoAccount.CentralRepoAccountType crAccountType : accountTypes) {
|
||||
|
||||
String querySql = getPersonaFromInstanceTableQueryTemplate(crAccountType)
|
||||
@ -802,7 +808,7 @@ public class Persona {
|
||||
+ "AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId();
|
||||
|
||||
PersonaFromAccountInstanceQueryCallback queryCallback = new PersonaFromAccountInstanceQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(querySql, queryCallback);
|
||||
getCRInstance().executeSelectSQL(querySql, queryCallback);
|
||||
|
||||
// Add persona that aren't already on the list.
|
||||
for (Persona persona : queryCallback.getPersonasList()) {
|
||||
@ -814,4 +820,23 @@ public class Persona {
|
||||
}
|
||||
return personaList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wraps the call to CentralRepository.getInstance() throwing an
|
||||
* exception if instance is null;
|
||||
*
|
||||
* @return Instance of CentralRepository
|
||||
*
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
private static CentralRepository getCRInstance() throws CentralRepoException {
|
||||
CentralRepository instance = CentralRepository.getInstance();
|
||||
|
||||
if(instance == null) {
|
||||
throw new CentralRepoException("Failed to get instance of CentralRespository, CR was null");
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
@ -121,23 +121,18 @@ public class PersonaAccount {
|
||||
/**
|
||||
* Creates an account for the specified Persona.
|
||||
*
|
||||
* @param persona Persona for which the account is being added.
|
||||
* @param account Account.
|
||||
* @param persona Persona for which the account is being added.
|
||||
* @param account Account.
|
||||
* @param justification Reason for assigning the alias, may be null.
|
||||
* @param confidence Confidence level.
|
||||
* @param confidence Confidence level.
|
||||
*
|
||||
* @return PersonaAccount
|
||||
*
|
||||
* @throws CentralRepoException If there is an error in creating the
|
||||
* account.
|
||||
* account.
|
||||
*/
|
||||
static PersonaAccount addPersonaAccount(Persona persona, CentralRepoAccount account, String justification, Persona.Confidence confidence) throws CentralRepoException {
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
|
||||
if(cr == null) {
|
||||
throw new CentralRepoException("Failed to add Persona, Central Repository is not enable");
|
||||
}
|
||||
|
||||
CentralRepoExaminer currentExaminer = cr.getOrInsertExaminer(System.getProperty("user.name"));
|
||||
CentralRepoExaminer currentExaminer = getCRInstance().getOrInsertExaminer(System.getProperty("user.name"));
|
||||
|
||||
Instant instant = Instant.now();
|
||||
Long timeStampMillis = instant.toEpochMilli();
|
||||
@ -151,14 +146,14 @@ public class PersonaAccount {
|
||||
+ currentExaminer.getId()
|
||||
+ ")";
|
||||
|
||||
CentralRepository.getInstance().executeInsertSQL(insertClause);
|
||||
getCRInstance().executeInsertSQL(insertClause);
|
||||
|
||||
String queryClause = PERSONA_ACCOUNTS_QUERY_CLAUSE
|
||||
+ "WHERE persona_id = " + persona.getId()
|
||||
+ " AND account_type_id = " + account.getAccountType().getAccountTypeId()
|
||||
+ " AND account_unique_identifier = \"" + account.getIdentifier() + "\"";
|
||||
+ " AND account_unique_identifier = '" + account.getIdentifier() + "'";
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
Collection<PersonaAccount> accounts = queryCallback.getPersonaAccountsList();
|
||||
if (accounts.size() != 1) {
|
||||
@ -203,7 +198,7 @@ public class PersonaAccount {
|
||||
);
|
||||
|
||||
// create account
|
||||
CentralRepoAccount.CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(rs.getString("type_name"));
|
||||
CentralRepoAccount.CentralRepoAccountType crAccountType = getCRInstance().getAccountTypeByName(rs.getString("type_name"));
|
||||
CentralRepoAccount account = new CentralRepoAccount(
|
||||
rs.getInt("account_id"),
|
||||
crAccountType,
|
||||
@ -249,19 +244,13 @@ public class PersonaAccount {
|
||||
* persona_account.
|
||||
*/
|
||||
static Collection<PersonaAccount> getPersonaAccountsForPersona(long personaId) throws CentralRepoException {
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
String queryClause = PERSONA_ACCOUNTS_QUERY_CLAUSE
|
||||
+ " WHERE persona_accounts.persona_id = " + personaId;
|
||||
|
||||
if (cr != null) {
|
||||
String queryClause = PERSONA_ACCOUNTS_QUERY_CLAUSE
|
||||
+ " WHERE persona_accounts.persona_id = " + personaId;
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
cr.executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
return queryCallback.getPersonaAccountsList();
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
return queryCallback.getPersonaAccountsList();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -279,16 +268,9 @@ public class PersonaAccount {
|
||||
+ " WHERE persona_accounts.account_id = " + accountId
|
||||
+ " AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId();
|
||||
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
|
||||
if (cr != null) {
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
cr.executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
return queryCallback.getPersonaAccountsList();
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
return queryCallback.getPersonaAccountsList();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -308,15 +290,10 @@ public class PersonaAccount {
|
||||
+ " WHERE LOWER(accounts.account_unique_identifier) LIKE LOWER('%" + accountIdentifierSubstring + "%')"
|
||||
+ " AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId();
|
||||
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
if (cr != null) {
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
cr.executeSelectSQL(queryClause, queryCallback);
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
return queryCallback.getPersonaAccountsList();
|
||||
|
||||
return queryCallback.getPersonaAccountsList();
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -335,14 +312,9 @@ public class PersonaAccount {
|
||||
+ " AND type_name = '" + account.getAccountType().getTypeName() + "' "
|
||||
+ " AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId();
|
||||
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
if (cr != null) {
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
cr.executeSelectSQL(queryClause, queryCallback);
|
||||
return queryCallback.getPersonaAccountsList();
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
return queryCallback.getPersonaAccountsList();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -351,36 +323,24 @@ public class PersonaAccount {
|
||||
* @param id row id for the account to be removed
|
||||
*
|
||||
* @throws CentralRepoException If there is an error in removing the
|
||||
* account.
|
||||
* account.
|
||||
*/
|
||||
static void removePersonaAccount(long id) throws CentralRepoException {
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
|
||||
if(cr == null) {
|
||||
throw new CentralRepoException("Failed to remove persona account, Central Repo is not enabled");
|
||||
}
|
||||
|
||||
String deleteClause = " DELETE FROM persona_accounts WHERE id = " + id;
|
||||
cr.executeDeleteSQL(deleteClause);
|
||||
getCRInstance().executeDeleteSQL(deleteClause);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Modifies the PersonaAccount row by the given id
|
||||
*
|
||||
* @param id row id for the account to be removed
|
||||
*
|
||||
* @throws CentralRepoException If there is an error in removing the
|
||||
* account.
|
||||
* account.
|
||||
*/
|
||||
static void modifyPersonaAccount(long id, Persona.Confidence confidence, String justification) throws CentralRepoException {
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
|
||||
if (cr == null) {
|
||||
throw new CentralRepoException("Failed to modify persona account, Central Repo is not enabled");
|
||||
}
|
||||
|
||||
String updateClause = "UPDATE persona_accounts SET confidence_id = " + confidence.getLevelId() + ", justification = \"" + justification + "\" WHERE id = " + id;
|
||||
cr.executeUpdateSQL(updateClause);
|
||||
String updateClause = "UPDATE persona_accounts SET confidence_id = " + confidence.getLevelId() + ", justification = '" + justification + "' WHERE id = " + id;
|
||||
getCRInstance().executeUpdateSQL(updateClause);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -397,7 +357,7 @@ public class PersonaAccount {
|
||||
while (rs.next()) {
|
||||
|
||||
// create account
|
||||
CentralRepoAccount.CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(rs.getString("type_name"));
|
||||
CentralRepoAccount.CentralRepoAccountType crAccountType = getCRInstance().getAccountTypeByName(rs.getString("type_name"));
|
||||
CentralRepoAccount account = new CentralRepoAccount(
|
||||
rs.getInt("account_id"),
|
||||
crAccountType,
|
||||
@ -418,28 +378,41 @@ public class PersonaAccount {
|
||||
* @param personaId Id of the persona to look for.
|
||||
*
|
||||
* @return Collection of all accounts associated with the given persona, may
|
||||
* be empty.
|
||||
* be empty.
|
||||
*
|
||||
* @throws CentralRepoException If there is an error in getting the
|
||||
* accounts.
|
||||
* accounts.
|
||||
*/
|
||||
static Collection<CentralRepoAccount> getAccountsForPersona(long personaId) throws CentralRepoException {
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
String queryClause = "SELECT account_id, "
|
||||
+ " accounts.account_type_id as account_type_id, accounts.account_unique_identifier as account_unique_identifier,"
|
||||
+ " account_types.type_name as type_name "
|
||||
+ " FROM persona_accounts "
|
||||
+ " JOIN accounts as accounts on persona_accounts.account_id = accounts.id "
|
||||
+ " JOIN account_types as account_types on accounts.account_type_id = account_types.id "
|
||||
+ " WHERE persona_accounts.persona_id = " + personaId;
|
||||
|
||||
if (cr != null) {
|
||||
String queryClause = "SELECT account_id, "
|
||||
+ " accounts.account_type_id as account_type_id, accounts.account_unique_identifier as account_unique_identifier,"
|
||||
+ " account_types.type_name as type_name "
|
||||
+ " FROM persona_accounts "
|
||||
+ " JOIN accounts as accounts on persona_accounts.account_id = accounts.id "
|
||||
+ " JOIN account_types as account_types on accounts.account_type_id = account_types.id "
|
||||
+ " WHERE persona_accounts.persona_id = " + personaId;
|
||||
AccountsForPersonaQueryCallback queryCallback = new AccountsForPersonaQueryCallback();
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
AccountsForPersonaQueryCallback queryCallback = new AccountsForPersonaQueryCallback();
|
||||
cr.executeSelectSQL(queryClause, queryCallback);
|
||||
return queryCallback.getAccountsList();
|
||||
}
|
||||
|
||||
return queryCallback.getAccountsList();
|
||||
/**
|
||||
* Wraps the call to CentralRepository.getInstance() throwing an exception
|
||||
* if instance is null;
|
||||
*
|
||||
* @return Instance of CentralRepository
|
||||
*
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
private static CentralRepository getCRInstance() throws CentralRepoException {
|
||||
CentralRepository instance = CentralRepository.getInstance();
|
||||
|
||||
if (instance == null) {
|
||||
throw new CentralRepoException("Failed to get instance of CentralRespository, CR was null");
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public class PersonaAlias {
|
||||
*/
|
||||
static PersonaAlias addPersonaAlias(Persona persona, String alias, String justification, Persona.Confidence confidence) throws CentralRepoException {
|
||||
|
||||
CentralRepoExaminer examiner = CentralRepository.getInstance().getOrInsertExaminer(System.getProperty("user.name"));
|
||||
CentralRepoExaminer examiner = getCRInstance().getOrInsertExaminer(System.getProperty("user.name"));
|
||||
|
||||
Instant instant = Instant.now();
|
||||
Long timeStampMillis = instant.toEpochMilli();
|
||||
@ -113,16 +113,16 @@ public class PersonaAlias {
|
||||
+ examiner.getId()
|
||||
+ ")";
|
||||
|
||||
CentralRepository.getInstance().executeInsertSQL(insertClause);
|
||||
getCRInstance().executeInsertSQL(insertClause);
|
||||
|
||||
String queryClause = SELECT_QUERY_BASE
|
||||
+ "WHERE pa.persona_id = " + persona.getId()
|
||||
+ " AND pa.alias = \"" + alias + "\""
|
||||
+ " AND pa.alias = '" + alias + "'"
|
||||
+ " AND pa.date_added = " + timeStampMillis
|
||||
+ " AND pa.examiner_id = " + examiner.getId();
|
||||
|
||||
PersonaAliasesQueryCallback queryCallback = new PersonaAliasesQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
Collection<PersonaAlias> aliases = queryCallback.getAliases();
|
||||
if (aliases.size() != 1) {
|
||||
@ -141,7 +141,7 @@ public class PersonaAlias {
|
||||
*/
|
||||
static void removePersonaAlias(PersonaAlias alias) throws CentralRepoException {
|
||||
String deleteClause = " DELETE FROM persona_alias WHERE id = " + alias.getId();
|
||||
CentralRepository.getInstance().executeDeleteSQL(deleteClause);
|
||||
getCRInstance().executeDeleteSQL(deleteClause);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -158,7 +158,7 @@ public class PersonaAlias {
|
||||
throw new CentralRepoException("Failed to modify persona alias, Central Repo is not enabled");
|
||||
}
|
||||
|
||||
String updateClause = "UPDATE persona_alias SET confidence_id = " + confidence.getLevelId() + ", justification = \"" + justification + "\" WHERE id = " + alias.id;
|
||||
String updateClause = "UPDATE persona_alias SET confidence_id = " + confidence.getLevelId() + ", justification = '" + justification + "' WHERE id = " + alias.id;
|
||||
cr.executeUpdateSQL(updateClause);
|
||||
}
|
||||
|
||||
@ -208,9 +208,26 @@ public class PersonaAlias {
|
||||
String queryClause = SELECT_QUERY_BASE + "WHERE pa.persona_id = " + personaId;
|
||||
|
||||
PersonaAliasesQueryCallback queryCallback = new PersonaAliasesQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
return queryCallback.getAliases();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the call to CentralRepository.getInstance() throwing an
|
||||
* exception if instance is null;
|
||||
*
|
||||
* @return Instance of CentralRepository
|
||||
*
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
private static CentralRepository getCRInstance() throws CentralRepoException {
|
||||
CentralRepository instance = CentralRepository.getInstance();
|
||||
|
||||
if(instance == null) {
|
||||
throw new CentralRepoException("Failed to get instance of CentralRespository, CR was null");
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ public class PersonaMetadata {
|
||||
*/
|
||||
static PersonaMetadata addPersonaMetadata(long personaId, String name, String value, String justification, Persona.Confidence confidence) throws CentralRepoException {
|
||||
|
||||
CentralRepoExaminer examiner = CentralRepository.getInstance().getOrInsertExaminer(System.getProperty("user.name"));
|
||||
CentralRepoExaminer examiner = getCRInstance().getOrInsertExaminer(System.getProperty("user.name"));
|
||||
|
||||
Instant instant = Instant.now();
|
||||
Long timeStampMillis = instant.toEpochMilli();
|
||||
@ -123,17 +123,17 @@ public class PersonaMetadata {
|
||||
+ examiner.getId()
|
||||
+ ")";
|
||||
|
||||
CentralRepository.getInstance().executeInsertSQL(insertClause);
|
||||
getCRInstance().executeInsertSQL(insertClause);
|
||||
|
||||
String queryClause = SELECT_QUERY_BASE
|
||||
+ "WHERE pmd.persona_id = " + personaId
|
||||
+ " AND pmd.name = \"" + name + "\""
|
||||
+ " AND pmd.value = \"" + value + "\""
|
||||
+ " AND pmd.name = '" + name + "'"
|
||||
+ " AND pmd.value = '" + value + "'"
|
||||
+ " AND pmd.date_added = " + timeStampMillis
|
||||
+ " AND pmd.examiner_id = " + examiner.getId();
|
||||
|
||||
PersonaMetadataQueryCallback queryCallback = new PersonaMetadataQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
Collection<PersonaMetadata> metadata = queryCallback.getMetadataList();
|
||||
if (metadata.size() != 1) {
|
||||
@ -152,7 +152,7 @@ public class PersonaMetadata {
|
||||
*/
|
||||
static void removePersonaMetadata(PersonaMetadata metadata) throws CentralRepoException {
|
||||
String deleteClause = " DELETE FROM persona_metadata WHERE id = " + metadata.getId();
|
||||
CentralRepository.getInstance().executeDeleteSQL(deleteClause);
|
||||
getCRInstance().executeDeleteSQL(deleteClause);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,7 +169,7 @@ public class PersonaMetadata {
|
||||
throw new CentralRepoException("Failed to modify persona metadata, Central Repo is not enabled");
|
||||
}
|
||||
|
||||
String updateClause = "UPDATE persona_metadata SET confidence_id = " + confidence.getLevelId() + ", justification = \"" + justification + "\" WHERE id = " + metadata.id;
|
||||
String updateClause = "UPDATE persona_metadata SET confidence_id = " + confidence.getLevelId() + ", justification = '" + justification + "' WHERE id = " + metadata.id;
|
||||
cr.executeUpdateSQL(updateClause);
|
||||
}
|
||||
|
||||
@ -219,10 +219,27 @@ public class PersonaMetadata {
|
||||
String queryClause = SELECT_QUERY_BASE + "WHERE pmd.persona_id = " + personaId;
|
||||
|
||||
PersonaMetadataQueryCallback queryCallback = new PersonaMetadataQueryCallback();
|
||||
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
getCRInstance().executeSelectSQL(queryClause, queryCallback);
|
||||
|
||||
return queryCallback.getMetadataList();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the call to CentralRepository.getInstance() throwing an
|
||||
* exception if instance is null;
|
||||
*
|
||||
* @return Instance of CentralRepository
|
||||
*
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
private static CentralRepository getCRInstance() throws CentralRepoException {
|
||||
CentralRepository instance = CentralRepository.getInstance();
|
||||
|
||||
if(instance == null) {
|
||||
throw new CentralRepoException("Failed to get instance of CentralRespository, CR was null");
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
@ -1679,7 +1679,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
|
||||
bulkArtifacts.get(tableName).clear();
|
||||
}
|
||||
|
||||
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
|
||||
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Central Repository: Bulk insert");
|
||||
HealthMonitor.submitTimingMetric(timingMetric);
|
||||
|
||||
// Reset state
|
||||
|
@ -1,5 +1,5 @@
|
||||
caseeventlistener.evidencetag=Evidence
|
||||
IngestEventsListener.ingestmodule.name=Correlation Engine
|
||||
IngestEventsListener.ingestmodule.name=Central Repository
|
||||
IngestEventsListener.prevCaseComment.text=Previous Case:
|
||||
# {0} - typeName
|
||||
# {1} - count
|
||||
|
@ -73,7 +73,7 @@ import org.sleuthkit.datamodel.CommunicationsUtils;
|
||||
* Listen for ingest events and update entries in the Central Repository
|
||||
* database accordingly
|
||||
*/
|
||||
@NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Correlation Engine"})
|
||||
@NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Central Repository"})
|
||||
public class IngestEventsListener {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName());
|
||||
@ -116,24 +116,24 @@ public class IngestEventsListener {
|
||||
|
||||
/**
|
||||
* Increase the number of IngestEventsListeners adding contents to the
|
||||
* Correlation Engine.
|
||||
* Central Repository.
|
||||
*/
|
||||
public synchronized static void incrementCorrelationEngineModuleCount() {
|
||||
correlationModuleInstanceCount++; //Should be called once in the Correlation Engine module's startup method.
|
||||
correlationModuleInstanceCount++; //Should be called once in the Central Repository module's startup method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease the number of IngestEventsListeners adding contents to the
|
||||
* Correlation Engine.
|
||||
* Central Repository.
|
||||
*/
|
||||
public synchronized static void decrementCorrelationEngineModuleCount() {
|
||||
if (getCeModuleInstanceCount() > 0) { //prevent it ingestJobCounter from going negative
|
||||
correlationModuleInstanceCount--; //Should be called once in the Correlation Engine module's shutdown method.
|
||||
correlationModuleInstanceCount--; //Should be called once in the Central Repository module's shutdown method.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the counter which keeps track of if the Correlation Engine Module
|
||||
* Reset the counter which keeps track of if the Central Repository Module
|
||||
* is being run during injest to 0.
|
||||
*/
|
||||
synchronized static void resetCeModuleInstanceCount() {
|
||||
@ -141,10 +141,10 @@ public class IngestEventsListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the Correlation Engine Module is enabled for any of the
|
||||
* Whether or not the Central Repository Module is enabled for any of the
|
||||
* currently running ingest jobs.
|
||||
*
|
||||
* @return boolean True for Correlation Engine enabled, False for disabled
|
||||
* @return boolean True for Central Repository enabled, False for disabled
|
||||
*/
|
||||
public synchronized static int getCeModuleInstanceCount() {
|
||||
return correlationModuleInstanceCount;
|
||||
@ -282,7 +282,7 @@ public class IngestEventsListener {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
//if ingest is running we want there to check if there is a Correlation Engine module running
|
||||
//if ingest is running we want there to check if there is a Central Repository module running
|
||||
//sometimes artifacts are generated by DSPs or other sources while ingest is not running
|
||||
//in these cases we still want to create correlation attributesForNewArtifact for those artifacts when appropriate
|
||||
if (!IngestManager.getInstance().isIngestRunning() || getCeModuleInstanceCount() > 0) {
|
||||
@ -349,7 +349,7 @@ public class IngestEventsListener {
|
||||
if (getCeModuleInstanceCount() == 0) {
|
||||
recentlyAddedCeArtifacts.clear();
|
||||
}
|
||||
//else another instance of the Correlation Engine Module is still being run.
|
||||
//else another instance of the Central Repository Module is still being run.
|
||||
|
||||
/*
|
||||
* Ensure the data source in the Central Repository has hash values
|
||||
|
@ -1,6 +1,6 @@
|
||||
CentralRepoIngestModel_name_header=Name:<br>
|
||||
CentralRepoIngestModel_previous_case_header=<br>Previous Cases:<br>
|
||||
CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Correlation Engine ingest module.
|
||||
CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Central Repository ingest module.
|
||||
CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized
|
||||
CentralRepoIngestModule.prevCaseComment.text=Previous Case:
|
||||
CentralRepoIngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)
|
||||
@ -8,7 +8,7 @@ CentralRepoIngestModule_notable_message_header=<html>A file in this data source
|
||||
# {0} - Name of file that is Notable
|
||||
CentralRepoIngestModule_postToBB_knownBadMsg=Notable: {0}
|
||||
CentralRepoIngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation
|
||||
CentralRepoIngestModuleFactory.ingestmodule.name=Correlation Engine
|
||||
CentralRepoIngestModuleFactory.ingestmodule.name=Central Repository
|
||||
IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings
|
||||
IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable
|
||||
IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag devices previously seen in other cases
|
||||
|
@ -85,7 +85,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
private final boolean createCorrelationProperties;
|
||||
|
||||
/**
|
||||
* Instantiate the Correlation Engine ingest module.
|
||||
* Instantiate the Central Repository ingest module.
|
||||
*
|
||||
* @param settings The ingest settings for the module instance.
|
||||
*/
|
||||
@ -147,7 +147,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
*/
|
||||
if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
|
||||
try {
|
||||
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Notable artifact query");
|
||||
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Central Repository: Notable artifact query");
|
||||
List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
|
||||
HealthMonitor.submitTimingMetric(timingMetric);
|
||||
if (!caseDisplayNamesList.isEmpty()) {
|
||||
@ -220,7 +220,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
// see ArtifactManagerTimeTester for details
|
||||
@Messages({
|
||||
"CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized",
|
||||
"CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Correlation Engine ingest module."
|
||||
"CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Central Repository ingest module."
|
||||
})
|
||||
@Override
|
||||
public void startUp(IngestJobContext context) throws IngestModuleException {
|
||||
@ -235,7 +235,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
* posited.
|
||||
*
|
||||
* Note: Flagging cannot be disabled if any other instances of the
|
||||
* Correlation Engine module are running. This restriction is to prevent
|
||||
* Central Repository module are running. This restriction is to prevent
|
||||
* missing results in the case where the first module is flagging
|
||||
* notable items, and the proceeding module (with flagging disabled)
|
||||
* causes the first to stop flagging.
|
||||
@ -276,7 +276,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
// Don't allow sqlite central repo databases to be used for multi user cases
|
||||
if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE)
|
||||
&& (CentralRepoDbManager.getSavedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE)) {
|
||||
logger.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository.");
|
||||
logger.log(Level.SEVERE, "Cannot run Central Repository ingest module on a multi-user case with a SQLite central repository.");
|
||||
throw new IngestModuleException("Cannot run on a multi-user case with a SQLite central repository."); // NON-NLS
|
||||
}
|
||||
jobId = context.getJobId();
|
||||
|
@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.ingest.NoIngestModuleIngestJobSettings;
|
||||
* Factory for Central Repository ingest modules
|
||||
*/
|
||||
@ServiceProvider(service = org.sleuthkit.autopsy.ingest.IngestModuleFactory.class)
|
||||
@NbBundle.Messages({"CentralRepoIngestModuleFactory.ingestmodule.name=Correlation Engine",
|
||||
@NbBundle.Messages({"CentralRepoIngestModuleFactory.ingestmodule.name=Central Repository",
|
||||
"CentralRepoIngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation"})
|
||||
public class CentralRepoIngestModuleFactory extends IngestModuleFactoryAdapter {
|
||||
|
||||
|
@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.centralrepository.ingestmodule;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
|
||||
|
||||
/**
|
||||
* Ingest job settings for the Correlation Engine module.
|
||||
* Ingest job settings for the Central Repository module.
|
||||
*/
|
||||
final class IngestSettings implements IngestModuleIngestJobSettings {
|
||||
|
||||
|
@ -22,7 +22,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
|
||||
|
||||
/**
|
||||
* Ingest job settings panel for the Correlation Engine module.
|
||||
* Ingest job settings panel for the Central Repository module.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
|
||||
|
@ -1,15 +1,6 @@
|
||||
CTL_OpenPersonaManager=Persona Manager
|
||||
CTL_PersonaManagerTopComponentAction=Persona Manager
|
||||
CTL_OpenPersonas=Personas
|
||||
CTL_PersonasTopComponentAction=Personas
|
||||
CTL_PersonaDetailsTopComponent=Persona Details
|
||||
PersonaManagerTopComponent.createBtn.text=New Persona
|
||||
PersonaManagerTopComponent.searchBtn.text=Search
|
||||
PersonaManagerTopComponent.resultsTable.columnModel.title1=Name
|
||||
PersonaManagerTopComponent.resultsTable.columnModel.title0=ID
|
||||
PersonaManagerTopComponent.resultsTable.toolTipText=
|
||||
PersonaManagerTopComponent.searchAccountRadio.text=Account
|
||||
PersonaManagerTopComponent.searchNameRadio.text=Name
|
||||
PersonaManagerTopComponent.searchField.text=
|
||||
PersonaManagerTopComponent.editBtn.text=Edit Persona
|
||||
PersonaDetailsDialog.cancelBtn.text=Cancel
|
||||
PersonaDetailsDialog.okBtn.text=OK
|
||||
PersonaDetailsPanel.casesLbl.text=Cases found in:
|
||||
@ -27,7 +18,6 @@ PersonaDetailsPanel.nameLbl.text=Name:
|
||||
AddAliasDialog.accountsLbl.text=Account:
|
||||
AddAliasDialog.okBtn.text=OK
|
||||
AddAliasDialog.cancelBtn.text=Cancel
|
||||
PersonaManagerTopComponent.deleteBtn.text=Delete Persona
|
||||
PersonaDetailsPanel.casesLbl.text=Cases found in:
|
||||
PersonaDetailsPanel.deleteAliasBtn.text=Delete
|
||||
PersonaDetailsPanel.addAliasBtn.text=Add
|
||||
@ -73,3 +63,20 @@ PersonaMetadataDialog.cancelBtn.text=Cancel
|
||||
PersonaDetailsPanel.editAccountBtn.text=Edit
|
||||
PersonaDetailsPanel.editMetadataBtn.text=Edit
|
||||
PersonaDetailsPanel.editAliasBtn.text=Edit
|
||||
PersonasTopComponent.searchAccountRadio.text=Account
|
||||
PersonasTopComponent.searchNameRadio.text=Name
|
||||
PersonasTopComponent.searchField.text=
|
||||
PersonasTopComponent.deleteBtn.text=Delete Persona
|
||||
PersonasTopComponent.editBtn.text=Edit Persona
|
||||
PersonasTopComponent.createBtn.text=New Persona
|
||||
PersonasTopComponent.createAccountBtn.text=Create Account
|
||||
PersonasTopComponent.searchBtn.text=Search
|
||||
PersonasTopComponent.resultsTable.columnModel.title1=Name
|
||||
PersonasTopComponent.resultsTable.columnModel.title0=ID
|
||||
PersonasTopComponent.resultsTable.toolTipText=
|
||||
CreatePersonaAccountDialog.cancelBtn.text=Cancel
|
||||
CreatePersonaAccountDialog.typeLbl.text=Type:
|
||||
CreatePersonaAccountDialog.identifierTextField.text=
|
||||
CreatePersonaAccountDialog.identiferLbl.text=Identifier:
|
||||
CreatePersonaAccountDialog.okBtn.text=OK
|
||||
PersonasTopComponent.introText.text=Personas represent an online identity. They span cases and are stored in the Central Repository based on accounts that were found in artifacts. You can create, edit, and delete personas here.
|
||||
|
@ -3,10 +3,15 @@ AddMetadataDialog_dup_msg=A metadata entry with this name has already been added
|
||||
AddMetadataDialog_dup_Title=Metadata add failure
|
||||
AddMetadataDialog_empty_name_msg=A metadata entry cannot have an empty name or value.
|
||||
AddMetadataDialog_empty_name_Title=Missing field(s)
|
||||
CTL_OpenPersonaManager=Persona Manager
|
||||
CTL_PersonaManagerTopComponentAction=Persona Manager
|
||||
CreatePersonaAccountDialog.title.text=Create Account
|
||||
CreatePersonaAccountDialog_error_msg=Failed to create account.
|
||||
CreatePersonaAccountDialog_error_title=Account failure
|
||||
CreatePersonaAccountDialog_success_msg=Account added.
|
||||
CreatePersonaAccountDialog_success_title=Account added
|
||||
CTL_OpenPersonas=Personas
|
||||
CTL_PersonasTopComponentAction=Personas
|
||||
CTL_PersonaDetailsTopComponent=Persona Details
|
||||
OpenPersonasAction.displayName=Persona Manager
|
||||
OpenPersonasAction.displayName=Personas
|
||||
PersonaAccountDialog.title.text=Add Account
|
||||
PersonaAccountDialog_dup_msg=This account is already added to the persona.
|
||||
PersonaAccountDialog_dup_Title=Account add failure
|
||||
@ -23,32 +28,11 @@ PersonaAliasDialog_dup_msg=This alias has already been added to this persona.
|
||||
PersonaAliasDialog_dup_Title=Alias add failure
|
||||
PersonaAliasDialog_empty_msg=An alias cannot be empty.
|
||||
PersonaAliasDialog_empty_Title=Empty alias
|
||||
PersonaDetailsDialog.cancelBtn.text=Cancel
|
||||
PersonaDetailsDialog.okBtn.text=OK
|
||||
PersonaDetailsDialogCreateTitle=Create Persona
|
||||
PersonaDetailsDialogEditTitle=Edit Persona
|
||||
PersonaDetailsDialogViewTitle=View Persona
|
||||
PersonaDetailsPanel_CentralRepoErr_msg=Failure to write to Central Repository.
|
||||
PersonaDetailsPanel_CentralRepoErr_Title=Central Repository failure
|
||||
PersonaDetailsPanel_empty_justification_msg=The justification field cannot be empty
|
||||
PersonaDetailsPanel_empty_justification_Title=Empty justification
|
||||
PersonaDetailsPanel_EmptyComment_msg=Persona comment cannot be empty.
|
||||
PersonaDetailsPanel_EmptyComment_Title=Empty persona comment
|
||||
PersonaDetailsPanel_EmptyName_msg=Persona name cannot be empty.
|
||||
PersonaDetailsPanel_EmptyName_Title=Empty persona name
|
||||
PersonaDetailsPanel_load_exception_msg=Failed to load persona.
|
||||
PersonaDetailsPanel_load_exception_Title=Initialization failure
|
||||
PersonaDetailsPanel_NotEnoughAccounts_msg=A persona needs at least one account.
|
||||
PersonaDetailsPanel_NotEnoughAccounts_Title=Missing account
|
||||
PersonaManagerTopComponent.createBtn.text=New Persona
|
||||
PersonaManagerTopComponent.searchBtn.text=Search
|
||||
PersonaManagerTopComponent.resultsTable.columnModel.title1=Name
|
||||
PersonaManagerTopComponent.resultsTable.columnModel.title0=ID
|
||||
PersonaManagerTopComponent.resultsTable.toolTipText=
|
||||
PersonaManagerTopComponent.searchAccountRadio.text=Account
|
||||
PersonaManagerTopComponent.searchNameRadio.text=Name
|
||||
PersonaManagerTopComponent.searchField.text=
|
||||
PersonaManagerTopComponent.editBtn.text=Edit Persona
|
||||
PersonaDetailsDialog.cancelBtn.text=Cancel
|
||||
PersonaDetailsDialog.okBtn.text=OK
|
||||
PersonaDetailsPanel.casesLbl.text=Cases found in:
|
||||
PersonaDetailsPanel.deleteAliasBtn.text=Delete
|
||||
PersonaDetailsPanel.addAliasBtn.text=Add
|
||||
@ -64,7 +48,6 @@ PersonaDetailsPanel.nameLbl.text=Name:
|
||||
AddAliasDialog.accountsLbl.text=Account:
|
||||
AddAliasDialog.okBtn.text=OK
|
||||
AddAliasDialog.cancelBtn.text=Cancel
|
||||
PersonaManagerTopComponent.deleteBtn.text=Delete Persona
|
||||
PersonaDetailsPanel.casesLbl.text=Cases found in:
|
||||
PersonaDetailsPanel.deleteAliasBtn.text=Delete
|
||||
PersonaDetailsPanel.addAliasBtn.text=Add
|
||||
@ -98,6 +81,18 @@ PersonaAliasDialog.justificationLbl.text=Justification:
|
||||
PersonaAliasDialog.aliasTextField.text=
|
||||
PersonaAliasDialog.aliasLbl.text=Alias:
|
||||
PersonaAliasDialog.okBtn.text_1=OK
|
||||
PersonaDetailsPanel_CentralRepoErr_msg=Failure to write to Central Repository.
|
||||
PersonaDetailsPanel_CentralRepoErr_Title=Central Repository failure
|
||||
PersonaDetailsPanel_empty_justification_msg=The justification field cannot be empty
|
||||
PersonaDetailsPanel_empty_justification_Title=Empty justification
|
||||
PersonaDetailsPanel_EmptyComment_msg=Persona comment cannot be empty.
|
||||
PersonaDetailsPanel_EmptyComment_Title=Empty persona comment
|
||||
PersonaDetailsPanel_EmptyName_msg=Persona name cannot be empty.
|
||||
PersonaDetailsPanel_EmptyName_Title=Empty persona name
|
||||
PersonaDetailsPanel_load_exception_msg=Failed to load persona.
|
||||
PersonaDetailsPanel_load_exception_Title=Initialization failure
|
||||
PersonaDetailsPanel_NotEnoughAccounts_msg=A persona needs at least one account.
|
||||
PersonaDetailsPanel_NotEnoughAccounts_Title=Missing account
|
||||
PersonaMetadataDialog.confidenceLbl.text=Confidence:
|
||||
PersonaMetadataDialog.justificationTextField.text=
|
||||
PersonaMetadataDialog.justificationLbl.text=Justification:
|
||||
@ -110,10 +105,27 @@ PersonaMetadataDialog.cancelBtn.text=Cancel
|
||||
PersonaDetailsPanel.editAccountBtn.text=Edit
|
||||
PersonaDetailsPanel.editMetadataBtn.text=Edit
|
||||
PersonaDetailsPanel.editAliasBtn.text=Edit
|
||||
PMTopComponent_delete_confirmation_msg=Are you sure you want to delete this persona?
|
||||
PMTopComponent_delete_confirmation_Title=Are you sure?
|
||||
PMTopComponent_delete_exception_msg=Failed to delete persona.
|
||||
PMTopComponent_delete_exception_Title=Delete failure
|
||||
PMTopComponent_Name=Persona Manager
|
||||
PMTopComponent_search_exception_msg=Failed to search personas.
|
||||
PMTopComponent_search_exception_Title=Search failure
|
||||
PersonasTopComponent.searchAccountRadio.text=Account
|
||||
PersonasTopComponent.searchNameRadio.text=Name
|
||||
PersonasTopComponent.searchField.text=
|
||||
PersonasTopComponent.deleteBtn.text=Delete Persona
|
||||
PersonasTopComponent.editBtn.text=Edit Persona
|
||||
PersonasTopComponent.createBtn.text=New Persona
|
||||
PersonasTopComponent.createAccountBtn.text=Create Account
|
||||
PersonasTopComponent.searchBtn.text=Search
|
||||
PersonasTopComponent.resultsTable.columnModel.title1=Name
|
||||
PersonasTopComponent.resultsTable.columnModel.title0=ID
|
||||
PersonasTopComponent.resultsTable.toolTipText=
|
||||
CreatePersonaAccountDialog.cancelBtn.text=Cancel
|
||||
CreatePersonaAccountDialog.typeLbl.text=Type:
|
||||
CreatePersonaAccountDialog.identifierTextField.text=
|
||||
CreatePersonaAccountDialog.identiferLbl.text=Identifier:
|
||||
CreatePersonaAccountDialog.okBtn.text=OK
|
||||
PersonasTopComponent.introText.text=Personas represent an online identity. They span cases and are stored in the Central Repository based on accounts that were found in artifacts. You can create, edit, and delete personas here.
|
||||
PersonasTopComponent_delete_confirmation_msg=Are you sure you want to delete this persona?
|
||||
PersonasTopComponent_delete_confirmation_Title=Are you sure?
|
||||
PersonasTopComponent_delete_exception_msg=Failed to delete persona.
|
||||
PersonasTopComponent_delete_exception_Title=Delete failure
|
||||
PersonasTopComponent_Name=Personas
|
||||
PersonasTopComponent_search_exception_msg=Failed to search personas.
|
||||
PersonasTopComponent_search_exception_Title=Search failure
|
||||
|
@ -8,3 +8,5 @@ PersonaAliasDialog.cancelBtn.text_1=\u53d6\u308a\u6d88\u3057
|
||||
PersonaAliasDialog.okBtn.text_1=OK
|
||||
PersonaMetadataDialog.okBtn.text=OK
|
||||
PersonaMetadataDialog.cancelBtn.text=\u53d6\u308a\u6d88\u3057
|
||||
CreatePersonaAccountDialog.okBtn.text=OK
|
||||
CreatePersonaAccountDialog.cancelBtn.text=\u53d6\u308a\u6d88\u3057
|
||||
|
@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="2"/>
|
||||
<Property name="resizable" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||
</SyntheticProperties>
|
||||
<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">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace pref="194" max="32767" attributes="0"/>
|
||||
<Component id="okBtn" linkSize="2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="cancelBtn" linkSize="2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="settingsPanel" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="settingsPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="okBtn" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="cancelBtn" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="settingsPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="typeLbl" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="typeComboBox" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="identiferLbl" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="identifierTextField" pref="281" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="identiferLbl" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="identifierTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="typeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="typeLbl" alignment="3" min="-2" pref="9" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="identiferLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="CreatePersonaAccountDialog.identiferLbl.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="identifierTextField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="CreatePersonaAccountDialog.identifierTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="identifierTextFieldActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="typeLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="CreatePersonaAccountDialog.typeLbl.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="typeComboBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new javax.swing.DefaultComboBoxModel<>(getAllAccountTypes())" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JButton" name="cancelBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="CreatePersonaAccountDialog.cancelBtn.text" 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="[79, 23]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[79, 23]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[79, 23]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelBtnActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="okBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="CreatePersonaAccountDialog.okBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okBtnActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* 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.centralrepository.persona;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* Configuration dialog for creating an account.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
public class CreatePersonaAccountDialog extends JDialog {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CreatePersonaAccountDialog.class.getName());
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final TypeChoiceRenderer TYPE_CHOICE_RENDERER = new TypeChoiceRenderer();
|
||||
|
||||
/**
|
||||
* Creates new create account dialog.
|
||||
*/
|
||||
@Messages({"CreatePersonaAccountDialog.title.text=Create Account",})
|
||||
public CreatePersonaAccountDialog(PersonaDetailsPanel pdp) {
|
||||
super(SwingUtilities.windowForComponent(pdp),
|
||||
Bundle.PersonaAccountDialog_title_text(),
|
||||
ModalityType.APPLICATION_MODAL);
|
||||
|
||||
initComponents();
|
||||
typeComboBox.setRenderer(TYPE_CHOICE_RENDERER);
|
||||
display();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class handles displaying and rendering drop down menu for account
|
||||
* choices.
|
||||
*/
|
||||
private class TypeChoiceRenderer extends JLabel implements ListCellRenderer<CentralRepoAccountType>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(
|
||||
JList<? extends CentralRepoAccountType> list, CentralRepoAccountType value,
|
||||
int index, boolean isSelected, boolean cellHasFocus) {
|
||||
setText(value.getAcctType().getDisplayName());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private CentralRepoAccountType[] getAllAccountTypes() {
|
||||
Collection<CentralRepoAccountType> allAccountTypes;
|
||||
try {
|
||||
allAccountTypes = CentralRepository.getInstance().getAllAccountTypes();
|
||||
} catch (CentralRepoException e) {
|
||||
logger.log(Level.SEVERE, "Failed to access central repository", e);
|
||||
JOptionPane.showMessageDialog(this,
|
||||
Bundle.PersonaAccountDialog_get_types_exception_Title(),
|
||||
Bundle.PersonaAccountDialog_get_types_exception_msg(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return new CentralRepoAccountType[0];
|
||||
}
|
||||
return allAccountTypes.toArray(new CentralRepoAccountType[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
settingsPanel = new javax.swing.JPanel();
|
||||
identiferLbl = new javax.swing.JLabel();
|
||||
identifierTextField = new javax.swing.JTextField();
|
||||
typeLbl = new javax.swing.JLabel();
|
||||
typeComboBox = new javax.swing.JComboBox<>();
|
||||
cancelBtn = new javax.swing.JButton();
|
||||
okBtn = new javax.swing.JButton();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
||||
setResizable(false);
|
||||
|
||||
settingsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(identiferLbl, org.openide.util.NbBundle.getMessage(CreatePersonaAccountDialog.class, "CreatePersonaAccountDialog.identiferLbl.text")); // NOI18N
|
||||
|
||||
identifierTextField.setText(org.openide.util.NbBundle.getMessage(CreatePersonaAccountDialog.class, "CreatePersonaAccountDialog.identifierTextField.text")); // NOI18N
|
||||
identifierTextField.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
identifierTextFieldActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(typeLbl, org.openide.util.NbBundle.getMessage(CreatePersonaAccountDialog.class, "CreatePersonaAccountDialog.typeLbl.text")); // NOI18N
|
||||
|
||||
typeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(getAllAccountTypes()));
|
||||
|
||||
javax.swing.GroupLayout settingsPanelLayout = new javax.swing.GroupLayout(settingsPanel);
|
||||
settingsPanel.setLayout(settingsPanelLayout);
|
||||
settingsPanelLayout.setHorizontalGroup(
|
||||
settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(settingsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(settingsPanelLayout.createSequentialGroup()
|
||||
.addComponent(typeLbl)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(typeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGroup(settingsPanelLayout.createSequentialGroup()
|
||||
.addComponent(identiferLbl)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(identifierTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 281, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
settingsPanelLayout.setVerticalGroup(
|
||||
settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(settingsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(identiferLbl)
|
||||
.addComponent(identifierTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(typeLbl, javax.swing.GroupLayout.PREFERRED_SIZE, 9, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cancelBtn, org.openide.util.NbBundle.getMessage(CreatePersonaAccountDialog.class, "CreatePersonaAccountDialog.cancelBtn.text")); // NOI18N
|
||||
cancelBtn.setMaximumSize(new java.awt.Dimension(79, 23));
|
||||
cancelBtn.setMinimumSize(new java.awt.Dimension(79, 23));
|
||||
cancelBtn.setPreferredSize(new java.awt.Dimension(79, 23));
|
||||
cancelBtn.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
cancelBtnActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(okBtn, org.openide.util.NbBundle.getMessage(CreatePersonaAccountDialog.class, "CreatePersonaAccountDialog.okBtn.text")); // NOI18N
|
||||
okBtn.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
okBtnActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap(194, Short.MAX_VALUE)
|
||||
.addComponent(okBtn)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
.addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelBtn, okBtn});
|
||||
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(settingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(okBtn)
|
||||
.addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void display() {
|
||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"CreatePersonaAccountDialog_error_title=Account failure",
|
||||
"CreatePersonaAccountDialog_error_msg=Failed to create account.",
|
||||
})
|
||||
private CentralRepoAccount createAccount(CentralRepoAccount.CentralRepoAccountType type, String identifier) {
|
||||
CentralRepoAccount ret = null;
|
||||
try {
|
||||
CentralRepository cr = CentralRepository.getInstance();
|
||||
if (cr != null) {
|
||||
ret = cr.getOrCreateAccount(type, identifier);
|
||||
}
|
||||
} catch (CentralRepoException e) {
|
||||
logger.log(Level.SEVERE, "Failed to create account", e);
|
||||
JOptionPane.showMessageDialog(this,
|
||||
Bundle.CreatePersonaAccountDialog_error_title(),
|
||||
Bundle.CreatePersonaAccountDialog_error_msg(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"CreatePersonaAccountDialog_success_title=Account added",
|
||||
"CreatePersonaAccountDialog_success_msg=Account added.",
|
||||
})
|
||||
private void okBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okBtnActionPerformed
|
||||
if (identifierTextField.getText().isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
Bundle.PersonaAccountDialog_identifier_empty_msg(),
|
||||
Bundle.PersonaAccountDialog_identifier_empty_Title(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
CentralRepoAccount.CentralRepoAccountType type =
|
||||
(CentralRepoAccount.CentralRepoAccountType) typeComboBox.getSelectedItem();
|
||||
String identifier = identifierTextField.getText();
|
||||
|
||||
if (createAccount(type, identifier) != null) {
|
||||
// show account created message
|
||||
JOptionPane.showMessageDialog(this,
|
||||
Bundle.CreatePersonaAccountDialog_success_msg(),
|
||||
Bundle.CreatePersonaAccountDialog_success_title(),
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
|
||||
dispose();
|
||||
}
|
||||
}//GEN-LAST:event_okBtnActionPerformed
|
||||
|
||||
private void cancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelBtnActionPerformed
|
||||
dispose();
|
||||
}//GEN-LAST:event_cancelBtnActionPerformed
|
||||
|
||||
private void identifierTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_identifierTextFieldActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_identifierTextFieldActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton cancelBtn;
|
||||
private javax.swing.JLabel identiferLbl;
|
||||
private javax.swing.JTextField identifierTextField;
|
||||
private javax.swing.JButton okBtn;
|
||||
private javax.swing.JPanel settingsPanel;
|
||||
private javax.swing.JComboBox<org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType> typeComboBox;
|
||||
private javax.swing.JLabel typeLbl;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -35,18 +35,18 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
* An Action that opens the Persona Search window.
|
||||
*/
|
||||
|
||||
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.centralrepository.persona.OpenPersonaManagerAction")
|
||||
@ActionRegistration(displayName = "#CTL_OpenPersonaManager", lazy = false)
|
||||
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.centralrepository.persona.OpenPersonasAction")
|
||||
@ActionRegistration(displayName = "#CTL_OpenPersonas", lazy = false)
|
||||
@ActionReferences(value = {
|
||||
@ActionReference(path = "Menu/Tools", position = 105)
|
||||
})
|
||||
public final class OpenPersonaManagerAction extends CallableSystemAction {
|
||||
public final class OpenPersonasAction extends CallableSystemAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final JMenuItem menuItem;
|
||||
|
||||
public OpenPersonaManagerAction() {
|
||||
public OpenPersonasAction() {
|
||||
menuItem = super.getMenuPresenter();
|
||||
this.setEnabled(CentralRepository.isEnabled());
|
||||
}
|
||||
@ -54,7 +54,7 @@ public final class OpenPersonaManagerAction extends CallableSystemAction {
|
||||
@Override
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public void performAction() {
|
||||
final TopComponent topComponent = WindowManager.getDefault().findTopComponent("PersonaManagerTopComponent");
|
||||
final TopComponent topComponent = WindowManager.getDefault().findTopComponent("PersonasTopComponent");
|
||||
if (topComponent != null) {
|
||||
if (topComponent.isOpened() == false) {
|
||||
topComponent.open();
|
||||
@ -65,7 +65,7 @@ public final class OpenPersonaManagerAction extends CallableSystemAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages("OpenPersonasAction.displayName=Persona Manager")
|
||||
@NbBundle.Messages("OpenPersonasAction.displayName=Personas")
|
||||
public String getName() {
|
||||
return Bundle.OpenPersonasAction_displayName();
|
||||
}
|
@ -1,35 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
|
||||
-->
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<NonVisualComponents>
|
||||
<Component class="javax.swing.ButtonGroup" name="searchButtonGroup">
|
||||
</Component>
|
||||
</NonVisualComponents>
|
||||
<Properties>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[400, 400]"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
@ -46,17 +23,52 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jSplitPane1" alignment="0" pref="692" max="32767" attributes="0"/>
|
||||
<Component id="introTextScrollPane" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="mainSplitPane" alignment="0" pref="724" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jSplitPane1" alignment="0" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="introTextScrollPane" min="-2" pref="49" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="mainSplitPane" pref="470" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JSplitPane" name="jSplitPane1">
|
||||
<Container class="javax.swing.JScrollPane" name="introTextScrollPane">
|
||||
<Properties>
|
||||
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTextArea" name="introText">
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection component="Form" name="getBackground" type="method"/>
|
||||
</Property>
|
||||
<Property name="columns" type="int" value="20"/>
|
||||
<Property name="lineWrap" type="boolean" value="true"/>
|
||||
<Property name="rows" type="int" value="5"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.introText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="wrapStyleWord" type="boolean" value="true"/>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JSplitPane" name="mainSplitPane">
|
||||
<Properties>
|
||||
<Property name="dividerLocation" type="int" value="400"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
@ -70,16 +82,10 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="createBtn" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="editBtn" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="deleteBtn" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="createButtonSeparator" max="32767" attributes="0"/>
|
||||
<Component id="resultsPane" pref="0" max="32767" attributes="0"/>
|
||||
<Component id="searchField" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
@ -89,6 +95,19 @@
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="searchBtn" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="createAccountBtn" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="createBtn" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="editBtn" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="deleteBtn" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -106,7 +125,7 @@
|
||||
<Component id="searchBtn" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="resultsPane" pref="528" max="32767" attributes="0"/>
|
||||
<Component id="resultsPane" pref="300" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="editBtn" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
@ -114,6 +133,10 @@
|
||||
<Component id="deleteBtn" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="createButtonSeparator" min="-2" pref="4" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="createAccountBtn" min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -122,7 +145,7 @@
|
||||
<Component class="javax.swing.JTextField" name="searchField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.searchField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.searchField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
@ -133,7 +156,7 @@
|
||||
</Property>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.searchNameRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.searchNameRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
@ -143,7 +166,14 @@
|
||||
<ComponentRef name="searchButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.searchAccountRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.searchAccountRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="searchBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.searchBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
@ -157,20 +187,20 @@
|
||||
<Component class="javax.swing.JTable" name="resultsTable">
|
||||
<Properties>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.resultsTable.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.resultsTable.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
|
||||
<TableColumnModel selectionModel="0">
|
||||
<Column maxWidth="25" minWidth="-1" prefWidth="-1" resizable="true">
|
||||
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.resultsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.resultsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Title>
|
||||
<Editor/>
|
||||
<Renderer/>
|
||||
</Column>
|
||||
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
|
||||
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.resultsTable.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.resultsTable.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Title>
|
||||
<Editor/>
|
||||
<Renderer/>
|
||||
@ -184,48 +214,59 @@
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JButton" name="searchBtn">
|
||||
<Component class="javax.swing.JButton" name="createAccountBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.searchBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="editBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.editBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="createBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.createBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.createAccountBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="deleteBtn">
|
||||
<Component class="javax.swing.JButton" name="editBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.deleteBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.editBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="deleteBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.deleteBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSeparator" name="createButtonSeparator">
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="createBtn">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.createBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel" name="detailsPanel">
|
||||
<Container class="javax.swing.JScrollPane" name="detailsScrollPane">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||
<JSplitPaneConstraints position="right"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel" name="detailsPanel">
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
@ -44,27 +44,29 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
* Top component for the Personas tool
|
||||
*
|
||||
*/
|
||||
@TopComponent.Description(preferredID = "PersonaManagerTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER)
|
||||
@TopComponent.Registration(mode = "personamanager", openAtStartup = false)
|
||||
@RetainLocation("personamanager")
|
||||
@TopComponent.Description(preferredID = "PersonasTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER)
|
||||
@TopComponent.Registration(mode = "personas", openAtStartup = false)
|
||||
@RetainLocation("personas")
|
||||
@SuppressWarnings("PMD.SingularField")
|
||||
public final class PersonaManagerTopComponent extends TopComponent {
|
||||
public final class PersonasTopComponent extends TopComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PersonaManagerTopComponent.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(PersonasTopComponent.class.getName());
|
||||
|
||||
private List<Persona> currentResults = null;
|
||||
private Persona selectedPersona = null;
|
||||
|
||||
@Messages({
|
||||
"PMTopComponent_Name=Persona Manager",
|
||||
"PMTopComponent_delete_exception_Title=Delete failure",
|
||||
"PMTopComponent_delete_exception_msg=Failed to delete persona.",
|
||||
"PMTopComponent_delete_confirmation_Title=Are you sure?",
|
||||
"PMTopComponent_delete_confirmation_msg=Are you sure you want to delete this persona?",
|
||||
"PersonasTopComponent_Name=Personas",
|
||||
"PersonasTopComponent_delete_exception_Title=Delete failure",
|
||||
"PersonasTopComponent_delete_exception_msg=Failed to delete persona.",
|
||||
"PersonasTopComponent_delete_confirmation_Title=Are you sure?",
|
||||
"PersonasTopComponent_delete_confirmation_msg=Are you sure you want to delete this persona?",
|
||||
})
|
||||
public PersonaManagerTopComponent() {
|
||||
public PersonasTopComponent() {
|
||||
initComponents();
|
||||
setName(Bundle.PMTopComponent_Name());
|
||||
setName(Bundle.PersonasTopComponent_Name());
|
||||
executeSearch();
|
||||
|
||||
searchBtn.addActionListener(new ActionListener() {
|
||||
@ -77,7 +79,7 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
editBtn.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new PersonaDetailsDialog(PersonaManagerTopComponent.this,
|
||||
new PersonaDetailsDialog(PersonasTopComponent.this,
|
||||
PersonaDetailsMode.EDIT, selectedPersona, new CreateEditCallbackImpl());
|
||||
}
|
||||
});
|
||||
@ -85,7 +87,7 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
createBtn.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new PersonaDetailsDialog(PersonaManagerTopComponent.this,
|
||||
new PersonaDetailsDialog(PersonasTopComponent.this,
|
||||
PersonaDetailsMode.CREATE, selectedPersona, new CreateEditCallbackImpl());
|
||||
}
|
||||
});
|
||||
@ -94,8 +96,8 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
NotifyDescriptor confirm = new NotifyDescriptor.Confirmation(
|
||||
Bundle.PMTopComponent_delete_confirmation_msg(),
|
||||
Bundle.PMTopComponent_delete_confirmation_Title(),
|
||||
Bundle.PersonasTopComponent_delete_confirmation_msg(),
|
||||
Bundle.PersonasTopComponent_delete_confirmation_Title(),
|
||||
NotifyDescriptor.YES_NO_OPTION);
|
||||
DialogDisplayer.getDefault().notify(confirm);
|
||||
if (confirm.getValue().equals(NotifyDescriptor.YES_OPTION)) {
|
||||
@ -105,9 +107,9 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
}
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to delete persona: " + selectedPersona.getName(), ex);
|
||||
JOptionPane.showMessageDialog(PersonaManagerTopComponent.this,
|
||||
Bundle.PMTopComponent_delete_exception_msg(),
|
||||
Bundle.PMTopComponent_delete_exception_Title(),
|
||||
JOptionPane.showMessageDialog(PersonasTopComponent.this,
|
||||
Bundle.PersonasTopComponent_delete_exception_msg(),
|
||||
Bundle.PersonasTopComponent_delete_exception_Title(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
@ -132,6 +134,13 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
searchAccountRadio.addActionListener((ActionEvent e) -> {
|
||||
searchField.setText("");
|
||||
});
|
||||
|
||||
createAccountBtn.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new CreatePersonaAccountDialog(detailsPanel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,8 +223,8 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"PMTopComponent_search_exception_Title=Search failure",
|
||||
"PMTopComponent_search_exception_msg=Failed to search personas.",})
|
||||
"PersonasTopComponent_search_exception_Title=Search failure",
|
||||
"PersonasTopComponent_search_exception_msg=Failed to search personas.",})
|
||||
private void executeSearch() {
|
||||
Collection<Persona> results;
|
||||
try {
|
||||
@ -227,8 +236,8 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to search personas", ex);
|
||||
JOptionPane.showMessageDialog(this,
|
||||
Bundle.PMTopComponent_search_exception_Title(),
|
||||
Bundle.PMTopComponent_search_exception_msg(),
|
||||
Bundle.PersonasTopComponent_search_exception_Title(),
|
||||
Bundle.PersonasTopComponent_search_exception_msg(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
@ -254,49 +263,69 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
private void initComponents() {
|
||||
|
||||
searchButtonGroup = new javax.swing.ButtonGroup();
|
||||
jSplitPane1 = new javax.swing.JSplitPane();
|
||||
introTextScrollPane = new javax.swing.JScrollPane();
|
||||
introText = new javax.swing.JTextArea();
|
||||
mainSplitPane = new javax.swing.JSplitPane();
|
||||
searchPanel = new javax.swing.JPanel();
|
||||
searchField = new javax.swing.JTextField();
|
||||
searchNameRadio = new javax.swing.JRadioButton();
|
||||
searchAccountRadio = new javax.swing.JRadioButton();
|
||||
searchBtn = new javax.swing.JButton();
|
||||
resultsPane = new javax.swing.JScrollPane();
|
||||
resultsTable = new javax.swing.JTable();
|
||||
searchBtn = new javax.swing.JButton();
|
||||
createAccountBtn = new javax.swing.JButton();
|
||||
editBtn = new javax.swing.JButton();
|
||||
createBtn = new javax.swing.JButton();
|
||||
deleteBtn = new javax.swing.JButton();
|
||||
createButtonSeparator = new javax.swing.JSeparator();
|
||||
createBtn = new javax.swing.JButton();
|
||||
detailsScrollPane = new javax.swing.JScrollPane();
|
||||
detailsPanel = new org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel();
|
||||
|
||||
setMinimumSize(new java.awt.Dimension(400, 400));
|
||||
setName(""); // NOI18N
|
||||
|
||||
searchField.setText(org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.searchField.text")); // NOI18N
|
||||
introTextScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
|
||||
|
||||
introText.setBackground(getBackground());
|
||||
introText.setColumns(20);
|
||||
introText.setLineWrap(true);
|
||||
introText.setRows(5);
|
||||
introText.setText(org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.introText.text")); // NOI18N
|
||||
introText.setWrapStyleWord(true);
|
||||
introText.setFocusable(false);
|
||||
introTextScrollPane.setViewportView(introText);
|
||||
|
||||
mainSplitPane.setDividerLocation(400);
|
||||
|
||||
searchField.setText(org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.searchField.text")); // NOI18N
|
||||
|
||||
searchButtonGroup.add(searchNameRadio);
|
||||
searchNameRadio.setSelected(true);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(searchNameRadio, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.searchNameRadio.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(searchNameRadio, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.searchNameRadio.text")); // NOI18N
|
||||
|
||||
searchButtonGroup.add(searchAccountRadio);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(searchAccountRadio, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.searchAccountRadio.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(searchAccountRadio, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.searchAccountRadio.text")); // NOI18N
|
||||
|
||||
resultsTable.setToolTipText(org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.resultsTable.toolTipText")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(searchBtn, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.searchBtn.text")); // NOI18N
|
||||
|
||||
resultsTable.setToolTipText(org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.resultsTable.toolTipText")); // NOI18N
|
||||
resultsTable.getTableHeader().setReorderingAllowed(false);
|
||||
resultsPane.setViewportView(resultsTable);
|
||||
if (resultsTable.getColumnModel().getColumnCount() > 0) {
|
||||
resultsTable.getColumnModel().getColumn(0).setMaxWidth(25);
|
||||
resultsTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.resultsTable.columnModel.title0")); // NOI18N
|
||||
resultsTable.getColumnModel().getColumn(1).setHeaderValue(org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.resultsTable.columnModel.title1")); // NOI18N
|
||||
resultsTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.resultsTable.columnModel.title0")); // NOI18N
|
||||
resultsTable.getColumnModel().getColumn(1).setHeaderValue(org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.resultsTable.columnModel.title1")); // NOI18N
|
||||
}
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(searchBtn, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.searchBtn.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(createAccountBtn, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.createAccountBtn.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(editBtn, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.editBtn.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(editBtn, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.editBtn.text")); // NOI18N
|
||||
editBtn.setEnabled(false);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(createBtn, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.createBtn.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(deleteBtn, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.deleteBtn.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(deleteBtn, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.deleteBtn.text")); // NOI18N
|
||||
deleteBtn.setEnabled(false);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(createBtn, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.createBtn.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout searchPanelLayout = new javax.swing.GroupLayout(searchPanel);
|
||||
searchPanel.setLayout(searchPanelLayout);
|
||||
searchPanelLayout.setHorizontalGroup(
|
||||
@ -304,12 +333,7 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
.addGroup(searchPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(searchPanelLayout.createSequentialGroup()
|
||||
.addComponent(createBtn)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(editBtn)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(deleteBtn))
|
||||
.addComponent(createButtonSeparator)
|
||||
.addComponent(resultsPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
|
||||
.addComponent(searchField)
|
||||
.addGroup(searchPanelLayout.createSequentialGroup()
|
||||
@ -317,7 +341,17 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(searchAccountRadio)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(searchBtn)))
|
||||
.addComponent(searchBtn))
|
||||
.addGroup(searchPanelLayout.createSequentialGroup()
|
||||
.addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(createAccountBtn)
|
||||
.addGroup(searchPanelLayout.createSequentialGroup()
|
||||
.addComponent(createBtn)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(editBtn)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(deleteBtn)))
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
searchPanelLayout.setVerticalGroup(
|
||||
@ -331,36 +365,52 @@ public final class PersonaManagerTopComponent extends TopComponent {
|
||||
.addComponent(searchAccountRadio)
|
||||
.addComponent(searchBtn))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(resultsPane, javax.swing.GroupLayout.DEFAULT_SIZE, 528, Short.MAX_VALUE)
|
||||
.addComponent(resultsPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(editBtn)
|
||||
.addComponent(createBtn)
|
||||
.addComponent(deleteBtn))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(createButtonSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 4, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(createAccountBtn, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
jSplitPane1.setLeftComponent(searchPanel);
|
||||
jSplitPane1.setRightComponent(detailsPanel);
|
||||
mainSplitPane.setLeftComponent(searchPanel);
|
||||
|
||||
detailsScrollPane.setViewportView(detailsPanel);
|
||||
|
||||
mainSplitPane.setRightComponent(detailsScrollPane);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 692, Short.MAX_VALUE)
|
||||
.addComponent(introTextScrollPane)
|
||||
.addComponent(mainSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 724, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jSplitPane1)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(introTextScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(mainSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 470, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton createAccountBtn;
|
||||
private javax.swing.JButton createBtn;
|
||||
private javax.swing.JSeparator createButtonSeparator;
|
||||
private javax.swing.JButton deleteBtn;
|
||||
private org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel detailsPanel;
|
||||
private javax.swing.JScrollPane detailsScrollPane;
|
||||
private javax.swing.JButton editBtn;
|
||||
private javax.swing.JSplitPane jSplitPane1;
|
||||
private javax.swing.JTextArea introText;
|
||||
private javax.swing.JScrollPane introTextScrollPane;
|
||||
private javax.swing.JSplitPane mainSplitPane;
|
||||
private javax.swing.JScrollPane resultsPane;
|
||||
private javax.swing.JTable resultsTable;
|
||||
private javax.swing.JRadioButton searchAccountRadio;
|
@ -862,7 +862,7 @@ final class CommonAttributePanel extends javax.swing.JDialog implements Observer
|
||||
/**
|
||||
* If the settings reflect that a inter-case search is being performed,
|
||||
* checks that the data sources in the current case have been processed with
|
||||
* Correlation Engine enabled and exist in the central repository. Prompting
|
||||
* Central Repository enabled and exist in the central repository. Prompting
|
||||
* the user as to whether they still want to perform the search in the case
|
||||
* any data sources are unprocessed. If the settings reflect that a
|
||||
* intra-case search is being performed, it just performs the search.
|
||||
@ -870,7 +870,7 @@ final class CommonAttributePanel extends javax.swing.JDialog implements Observer
|
||||
* Notes: - Does not check that the data sources were processed into the
|
||||
* current central repository instead of another. - Does not check that the
|
||||
* appropriate modules to make all correlation types available were run. -
|
||||
* Does not check if the correlation engine was run with any of the
|
||||
* Does not check if the Central Repository was run with any of the
|
||||
* correlation properties properties disabled.
|
||||
*/
|
||||
@Messages({"CommonAttributePanel.incompleteResults.introText=Results may be incomplete. Not all data sources in the current case were ingested into the current Central Repository. The following data sources have not been processed:",
|
||||
@ -902,14 +902,14 @@ final class CommonAttributePanel extends javax.swing.JDialog implements Observer
|
||||
//if the datasource was previously processed we do not need to perform this check
|
||||
for (CorrelationDataSource correlatedDataSource : correlatedDataSources) {
|
||||
if (deviceID.equals(correlatedDataSource.getDeviceID())) {
|
||||
//if the datasource exists in the central repository it may of been processed with the correlation engine
|
||||
//if the datasource exists in the central repository it may of been processed with the Central Repository
|
||||
dataSourceCorrelationMap.put(dataSource, CorrelatedStatus.IN_CENTRAL_REPO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dataSourceCorrelationMap.get(dataSource) == CorrelatedStatus.IN_CENTRAL_REPO) {
|
||||
//if the data source was in the central repository check if any of the modules run on it were the correlation engine
|
||||
//if the data source was in the central repository check if any of the modules run on it were the Central Repository
|
||||
for (IngestModuleInfo ingestModuleInfo : jobInfo.getIngestModuleInfo()) {
|
||||
if (correlationEngineModuleName.equals(ingestModuleInfo.getDisplayName())) {
|
||||
dataSourceCorrelationMap.put(dataSource, CorrelatedStatus.CORRELATED);
|
||||
|
@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.communications.relationships;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.contentviewers.CallLogArtifactViewer;
|
||||
import org.sleuthkit.autopsy.contentviewers.artifactviewers.CallLogArtifactViewer;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
|
@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.communications.relationships;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.contentviewers.ContactArtifactViewer;
|
||||
import org.sleuthkit.autopsy.contentviewers.artifactviewers.ContactArtifactViewer;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
|
@ -25,7 +25,7 @@ import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.contentviewers.MessageArtifactViewer;
|
||||
import org.sleuthkit.autopsy.contentviewers.artifactviewers.MessageArtifactViewer;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
@ -939,46 +939,4 @@ manager.properties.lafError =\
|
||||
manager.properties.brokenProperty = Broken default property {0} value: {1}
|
||||
|
||||
manager.properties.missingProperty = Missing default property {0} value: {1}
|
||||
DefaultArtifactContentViewer.copyMenuItem.text=Copy
|
||||
DefaultArtifactContentViewer.selectAllMenuItem.text=Select All
|
||||
ContactArtifactViewer.contactNameLabel.text=Joanna Doe
|
||||
ContactArtifactViewer.phonesLabel.text=Phone
|
||||
ContactArtifactViewer.emailsLabel.text=Email
|
||||
ContactArtifactViewer.othersLabel.text=Other
|
||||
DefaultArtifactContentViewer.copyMenuItem.text=Copy
|
||||
DefaultArtifactContentViewer.selectAllMenuItem.text=Select All
|
||||
CallLogArtifactViewer.dataSourceNameLabel.text=data source name
|
||||
CallLogArtifactViewer.jLabel2.text=Device Id
|
||||
CallLogArtifactViewer.deviceIdLabel.text=device id
|
||||
CallLogArtifactViewer.localAccountIdLabel.text=local account
|
||||
CallLogArtifactViewer.localAccountLabel.text=Local Account
|
||||
CallLogArtifactViewer.jLabel4.text=Data Source Name
|
||||
CallLogArtifactViewer.otherInfoLabel.text=Other Information
|
||||
CallLogArtifactViewer.sourceSectionLabel.text=Source
|
||||
CallLogArtifactViewer.callDetailsLabel.text=Call Details
|
||||
CallLogArtifactViewer.durationLabel.text=Duration....
|
||||
CallLogArtifactViewer.dateTimeLabel.text=Date/Time.....
|
||||
CallLogArtifactViewer.directionLabel.text=Direction
|
||||
CallLogArtifactViewer.onLabel.text=On
|
||||
CallLogArtifactViewer.callLabel.text=call
|
||||
MessageArtifactViewer.fromText.text=from address goes here
|
||||
MessageArtifactViewer.datetimeText.text=date goes here
|
||||
MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle=Headers
|
||||
MessageArtifactViewer.fromLabel.text=From:
|
||||
MessageArtifactViewer.directionText.text=direction
|
||||
MessageArtifactViewer.subjectText.text=subject goes here
|
||||
MessageArtifactViewer.viewInNewWindowButton.text=View in New Window
|
||||
MessageArtifactViewer.subjectLabel.text=Subject:
|
||||
MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments
|
||||
MessageArtifactViewer.ccText.text=cc list goes here
|
||||
MessageArtifactViewer.ccLabel.text=CC:
|
||||
MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
|
||||
MessageArtifactViewer.toText.text=to list goes here
|
||||
MessageArtifactViewer.toLabel.text=To:
|
||||
MessageArtifactViewer.htmlPane.TabConstraints.tabTitle=HTML
|
||||
CallLogArtifactViewer.localAccountPersonaLabel.text=Persona
|
||||
CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1
|
||||
CallLogArtifactViewer.localAccountPersonaButton.text=jButton1
|
||||
ContactArtifactViewer.personasLabel.text=Personas
|
||||
MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts
|
||||
ContactArtifactViewer.contactImage.text=
|
||||
|
||||
|
71
Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED
Executable file → Normal file
71
Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED
Executable file → Normal file
@ -35,28 +35,6 @@ AnnotationsContentViewer.title=Annotations
|
||||
AnnotationsContentViewer.toolTip=Displays tags and comments associated with the selected content.
|
||||
ApplicationContentViewer.title=Application
|
||||
ApplicationContentViewer.toolTip=Displays file contents.
|
||||
CallLogArtifactViewer_crdisbaled_persona_button_text=Create
|
||||
CallLogArtifactViewer_crdisbaled_persona_label=Unknown
|
||||
CallLogArtifactViewer_number_from=From
|
||||
CallLogArtifactViewer_number_to=To
|
||||
CallLogArtifactViewer_persona_button_new=Create
|
||||
CallLogArtifactViewer_persona_button_view=View
|
||||
CallLogArtifactViewer_persona_label=\ Persona
|
||||
CallLogArtifactViewer_persona_searching=Searching...
|
||||
CallLogArtifactViewer_persona_text_none=None Found
|
||||
ContactArtifactViewer_missing_account_label=Missing Account:
|
||||
ContactArtifactViewer_persona_account_justification=Account found in Contact artifact
|
||||
ContactArtifactViewer_persona_button_new=Create
|
||||
ContactArtifactViewer_persona_button_view=View
|
||||
ContactArtifactViewer_persona_label=Persona
|
||||
ContactArtifactViewer_persona_searching=\ Searching...
|
||||
ContactArtifactViewer_persona_text_none=None found
|
||||
ContactArtifactViewer_persona_unknown=Unknown
|
||||
DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database
|
||||
DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database
|
||||
DefaultArtifactContentViewer.attrsTableHeader.sources=Source(s)
|
||||
DefaultArtifactContentViewer.attrsTableHeader.type=Type
|
||||
DefaultArtifactContentViewer.attrsTableHeader.value=Value
|
||||
FXVideoPanel.pauseButton.infoLabel.playbackErr=Unable to play video.
|
||||
FXVideoPanel.progress.bufferingCancelled=media buffering was canceled
|
||||
FXVideoPanel.progress.bufferingInterrupted=media buffering was interrupted
|
||||
@ -107,11 +85,6 @@ MediaViewVideoPanel.progressLabel.text=00:00
|
||||
MediaViewVideoPanel.infoLabel.text=info
|
||||
MediaViewImagePanel.imgFileTooLarge.msg=Could not load image file (too large): {0}
|
||||
|
||||
MessageAccountPanel_button_create_label=Create
|
||||
MessageAccountPanel_button_view_label=View
|
||||
MessageAccountPanel_persona_label=Persona:
|
||||
MessageAccountPanel_unknown_label=Unknown
|
||||
MessageArtifactViewer.AttachmentPanel.title=Attachments
|
||||
Metadata.nodeText.none=None
|
||||
Metadata.nodeText.truncated=(results truncated)
|
||||
Metadata.nodeText.unknown=Unknown
|
||||
@ -1054,46 +1027,4 @@ manager.properties.lafError =\
|
||||
manager.properties.brokenProperty = Broken default property {0} value: {1}
|
||||
|
||||
manager.properties.missingProperty = Missing default property {0} value: {1}
|
||||
DefaultArtifactContentViewer.copyMenuItem.text=Copy
|
||||
DefaultArtifactContentViewer.selectAllMenuItem.text=Select All
|
||||
ContactArtifactViewer.contactNameLabel.text=Joanna Doe
|
||||
ContactArtifactViewer.phonesLabel.text=Phone
|
||||
ContactArtifactViewer.emailsLabel.text=Email
|
||||
ContactArtifactViewer.othersLabel.text=Other
|
||||
DefaultArtifactContentViewer.copyMenuItem.text=Copy
|
||||
DefaultArtifactContentViewer.selectAllMenuItem.text=Select All
|
||||
CallLogArtifactViewer.dataSourceNameLabel.text=data source name
|
||||
CallLogArtifactViewer.jLabel2.text=Device Id
|
||||
CallLogArtifactViewer.deviceIdLabel.text=device id
|
||||
CallLogArtifactViewer.localAccountIdLabel.text=local account
|
||||
CallLogArtifactViewer.localAccountLabel.text=Local Account
|
||||
CallLogArtifactViewer.jLabel4.text=Data Source Name
|
||||
CallLogArtifactViewer.otherInfoLabel.text=Other Information
|
||||
CallLogArtifactViewer.sourceSectionLabel.text=Source
|
||||
CallLogArtifactViewer.callDetailsLabel.text=Call Details
|
||||
CallLogArtifactViewer.durationLabel.text=Duration....
|
||||
CallLogArtifactViewer.dateTimeLabel.text=Date/Time.....
|
||||
CallLogArtifactViewer.directionLabel.text=Direction
|
||||
CallLogArtifactViewer.onLabel.text=On
|
||||
CallLogArtifactViewer.callLabel.text=call
|
||||
MessageArtifactViewer.fromText.text=from address goes here
|
||||
MessageArtifactViewer.datetimeText.text=date goes here
|
||||
MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle=Headers
|
||||
MessageArtifactViewer.fromLabel.text=From:
|
||||
MessageArtifactViewer.directionText.text=direction
|
||||
MessageArtifactViewer.subjectText.text=subject goes here
|
||||
MessageArtifactViewer.viewInNewWindowButton.text=View in New Window
|
||||
MessageArtifactViewer.subjectLabel.text=Subject:
|
||||
MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments
|
||||
MessageArtifactViewer.ccText.text=cc list goes here
|
||||
MessageArtifactViewer.ccLabel.text=CC:
|
||||
MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
|
||||
MessageArtifactViewer.toText.text=to list goes here
|
||||
MessageArtifactViewer.toLabel.text=To:
|
||||
MessageArtifactViewer.htmlPane.TabConstraints.tabTitle=HTML
|
||||
CallLogArtifactViewer.localAccountPersonaLabel.text=Persona
|
||||
CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1
|
||||
CallLogArtifactViewer.localAccountPersonaButton.text=jButton1
|
||||
ContactArtifactViewer.personasLabel.text=Personas
|
||||
MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts
|
||||
ContactArtifactViewer.contactImage.text=
|
||||
|
||||
|
@ -149,20 +149,3 @@ MediaViewImagePanel.tagsMenu.text_1=\u30bf\u30b0\u30e1\u30cb\u30e5\u30fc
|
||||
SQLiteViewer.readTable.errorText=\u6b21\u306e\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0}
|
||||
# {0} - tableName
|
||||
SQLiteViewer.selectTable.errorText=\u6b21\u306e\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u30ab\u30a6\u30f3\u30c8\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0}
|
||||
DefaultArtifactContentViewer.selectAllMenuItem.text=\u3059\u3079\u3066\u3092\u9078\u629e
|
||||
DefaultArtifactContentViewer.copyMenuItem.text=\u30b3\u30d4\u30fc
|
||||
MessageArtifactViewer.fromText.text=\u9001\u4fe1\u5143\u30a2\u30c9\u30ec\u30b9\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.datetimeText.text=\u65e5\u4ed8\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle=\u30d8\u30c3\u30c0\u30fc
|
||||
MessageArtifactViewer.fromLabel.text=\u5dee\u51fa\u4eba:
|
||||
MessageArtifactViewer.directionText.text=\u9001\u53d7\u4fe1\u306e\u7a2e\u5225
|
||||
MessageArtifactViewer.subjectText.text=\u4ef6\u540d\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.viewInNewWindowButton.text=\u65b0\u3057\u3044\u30a6\u30a3\u30f3\u30c9\u30a6\u3067\u8868\u793a
|
||||
MessageArtifactViewer.subjectLabel.text=\u4ef6\u540d:
|
||||
MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle=\u6dfb\u4ed8\u30d5\u30a1\u30a4\u30eb
|
||||
MessageArtifactViewer.ccText.text=\u5b9b\u5148\u306eCC\u30ea\u30b9\u30c8\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.ccLabel.text=CC:
|
||||
MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
|
||||
MessageArtifactViewer.toText.text=\u5b9b\u5148\u306eTO\u30ea\u30b9\u30c8\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.toLabel.text=\u5b9b\u5148:
|
||||
MessageArtifactViewer.htmlPane.TabConstraints.tabTitle=HTML
|
||||
|
@ -1,227 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<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"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-57,0,0,2,31"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="namePanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="5" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="contactNameLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="true" component="contactNameLabel" italic="true" property="font" relativeSize="true" size="6"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContactArtifactViewer.contactNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="111" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="phonesLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="true" component="phonesLabel" property="font" relativeSize="true" size="2"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContactArtifactViewer.phonesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="phoneNumbersPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="3" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="emailsLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="true" component="emailsLabel" property="font" relativeSize="true" size="2"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContactArtifactViewer.emailsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="4" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="emailsPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="5" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="othersLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="true" component="othersLabel" property="font" relativeSize="true" size="2"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContactArtifactViewer.othersLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="6" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="otherAttrsPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="7" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.Box$Filler" name="interPanelfiller">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 32767]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="8" gridWidth="1" gridHeight="2" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.1"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="personasLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="true" component="personasLabel" property="font" relativeSize="true" size="2"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContactArtifactViewer.personasLabel.text" 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="[90, 19]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[90, 19]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[90, 19]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="9" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="personasPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="10" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.Box$Filler" name="bottomFiller">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 32767]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="11" gridWidth="4" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.Box$Filler" name="rightFiller">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 0]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalGlue"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="4" gridY="3" gridWidth="1" gridHeight="8" fill="1" ipadX="2" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="contactImage">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/images/defaultContact.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContactArtifactViewer.contactImage.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -1,942 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.contentviewers;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallback;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* This class displays the TSK_CONTACT artifact.
|
||||
*/
|
||||
@ServiceProvider(service = ArtifactContentViewer.class)
|
||||
public class ContactArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int TOP_INSET = 4;
|
||||
private static final int LEFT_INSET = 12;
|
||||
|
||||
// contact name, if available.
|
||||
private String contactName;
|
||||
|
||||
// A list of unique accounts matching the attributes of the contact artifact.
|
||||
private final List<CentralRepoAccount> contactUniqueAccountsList = new ArrayList<>();
|
||||
|
||||
// A list of all unique personas and their account, found by searching on the
|
||||
// account identifier attributes of the Contact artifact.
|
||||
private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap = new HashMap<>();
|
||||
|
||||
private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png";
|
||||
private final ImageIcon defaultImage;
|
||||
|
||||
/**
|
||||
* Creates new form for ContactArtifactViewer
|
||||
*/
|
||||
public ContactArtifactViewer() {
|
||||
initComponents();
|
||||
|
||||
defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
namePanel = new javax.swing.JPanel();
|
||||
contactNameLabel = new javax.swing.JLabel();
|
||||
phonesLabel = new javax.swing.JLabel();
|
||||
phoneNumbersPanel = new javax.swing.JPanel();
|
||||
emailsLabel = new javax.swing.JLabel();
|
||||
emailsPanel = new javax.swing.JPanel();
|
||||
othersLabel = new javax.swing.JLabel();
|
||||
otherAttrsPanel = new javax.swing.JPanel();
|
||||
javax.swing.Box.Filler interPanelfiller = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
|
||||
personasLabel = new javax.swing.JLabel();
|
||||
personasPanel = new javax.swing.JPanel();
|
||||
javax.swing.Box.Filler bottomFiller = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
|
||||
javax.swing.Box.Filler rightFiller = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
|
||||
contactImage = new javax.swing.JLabel();
|
||||
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
namePanel.setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
contactNameLabel.setFont(contactNameLabel.getFont().deriveFont((contactNameLabel.getFont().getStyle() | java.awt.Font.ITALIC) | java.awt.Font.BOLD, contactNameLabel.getFont().getSize()+6));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(contactNameLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.contactNameLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.ipadx = 111;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
namePanel.add(contactNameLabel, gridBagConstraints);
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.gridwidth = 5;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(namePanel, gridBagConstraints);
|
||||
|
||||
phonesLabel.setFont(phonesLabel.getFont().deriveFont(phonesLabel.getFont().getStyle() | java.awt.Font.BOLD, phonesLabel.getFont().getSize()+2));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(phonesLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.phonesLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.gridwidth = 3;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(phonesLabel, gridBagConstraints);
|
||||
|
||||
phoneNumbersPanel.setLayout(new java.awt.GridBagLayout());
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.gridwidth = 4;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(phoneNumbersPanel, gridBagConstraints);
|
||||
|
||||
emailsLabel.setFont(emailsLabel.getFont().deriveFont(emailsLabel.getFont().getStyle() | java.awt.Font.BOLD, emailsLabel.getFont().getSize()+2));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(emailsLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.emailsLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 4;
|
||||
gridBagConstraints.gridwidth = 2;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(emailsLabel, gridBagConstraints);
|
||||
|
||||
emailsPanel.setLayout(new java.awt.GridBagLayout());
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 5;
|
||||
gridBagConstraints.gridwidth = 4;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(emailsPanel, gridBagConstraints);
|
||||
|
||||
othersLabel.setFont(othersLabel.getFont().deriveFont(othersLabel.getFont().getStyle() | java.awt.Font.BOLD, othersLabel.getFont().getSize()+2));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(othersLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.othersLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 6;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(othersLabel, gridBagConstraints);
|
||||
|
||||
otherAttrsPanel.setLayout(new java.awt.GridBagLayout());
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 7;
|
||||
gridBagConstraints.gridwidth = 4;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(otherAttrsPanel, gridBagConstraints);
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 8;
|
||||
gridBagConstraints.gridheight = 2;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||
gridBagConstraints.weighty = 0.1;
|
||||
add(interPanelfiller, gridBagConstraints);
|
||||
|
||||
personasLabel.setFont(personasLabel.getFont().deriveFont(personasLabel.getFont().getStyle() | java.awt.Font.BOLD, personasLabel.getFont().getSize()+2));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(personasLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.personasLabel.text")); // NOI18N
|
||||
personasLabel.setMaximumSize(new java.awt.Dimension(90, 19));
|
||||
personasLabel.setMinimumSize(new java.awt.Dimension(90, 19));
|
||||
personasLabel.setPreferredSize(new java.awt.Dimension(90, 19));
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 9;
|
||||
gridBagConstraints.gridwidth = 3;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(personasLabel, gridBagConstraints);
|
||||
|
||||
personasPanel.setLayout(new java.awt.GridBagLayout());
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 10;
|
||||
gridBagConstraints.gridwidth = 4;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(personasPanel, gridBagConstraints);
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 11;
|
||||
gridBagConstraints.gridwidth = 4;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
add(bottomFiller, gridBagConstraints);
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 4;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.gridheight = 8;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||
gridBagConstraints.ipadx = 2;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
add(rightFiller, gridBagConstraints);
|
||||
|
||||
contactImage.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/defaultContact.png"))); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(contactImage, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.contactImage.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
|
||||
add(contactImage, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
@Override
|
||||
public void setArtifact(BlackboardArtifact artifact) {
|
||||
|
||||
// Reset the panel.
|
||||
resetComponent();
|
||||
|
||||
if (artifact == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<BlackboardAttribute> phoneNumList = new ArrayList<>();
|
||||
List<BlackboardAttribute> emailList = new ArrayList<>();
|
||||
List<BlackboardAttribute> nameList = new ArrayList<>();
|
||||
List<BlackboardAttribute> otherList = new ArrayList<>();
|
||||
List<BlackboardAttribute> accountAttributesList = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// Get all the attributes and group them by the section panels they go in
|
||||
for (BlackboardAttribute bba : artifact.getAttributes()) {
|
||||
if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
|
||||
phoneNumList.add(bba);
|
||||
accountAttributesList.add(bba);
|
||||
} else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
|
||||
emailList.add(bba);
|
||||
accountAttributesList.add(bba);
|
||||
} else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
|
||||
nameList.add(bba);
|
||||
} else {
|
||||
otherList.add(bba);
|
||||
if (bba.getAttributeType().getTypeName().equalsIgnoreCase("TSK_ID")) {
|
||||
accountAttributesList.add(bba);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
|
||||
}
|
||||
// update name section
|
||||
updateNamePanel(nameList);
|
||||
|
||||
// update contact attributes sections
|
||||
updateSection(phoneNumList, this.phonesLabel, this.phoneNumbersPanel);
|
||||
updateSection(emailList, this.emailsLabel, this.emailsPanel);
|
||||
updateSection(otherList, this.othersLabel, this.otherAttrsPanel);
|
||||
|
||||
try {
|
||||
initiatePersonasSearch(accountAttributesList);
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error getting Personas for Contact artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
|
||||
}
|
||||
|
||||
contactImage.setIcon(getImageFromArtifact(artifact));
|
||||
|
||||
// repaint
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponent() {
|
||||
// Slap a vertical scrollbar on the panel.
|
||||
return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given artifact is supported by this viewer. This viewer
|
||||
* supports TSK_CONTACT artifacts.
|
||||
*
|
||||
* @param artifact artifact to check.
|
||||
*
|
||||
* @return True if the artifact is supported, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isSupported(BlackboardArtifact artifact) {
|
||||
return artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all artifact specific state.
|
||||
*/
|
||||
private void resetComponent() {
|
||||
contactNameLabel.setVisible(false);
|
||||
emailsLabel.setVisible(false);
|
||||
emailsPanel.removeAll();
|
||||
//namePanel.removeAll(); // this is not dynamically populated, do not remove.
|
||||
otherAttrsPanel.removeAll();
|
||||
othersLabel.setVisible(false);
|
||||
personasLabel.setVisible(false);
|
||||
personasPanel.removeAll();
|
||||
phoneNumbersPanel.removeAll();
|
||||
phonesLabel.setVisible(false);
|
||||
|
||||
contactName = null;
|
||||
contactUniqueAccountsList.clear();
|
||||
contactUniquePersonasMap.clear();
|
||||
contactImage.setIcon(defaultImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the contact name in the view.
|
||||
*
|
||||
* @param attributesList
|
||||
*/
|
||||
private void updateNamePanel(List<BlackboardAttribute> attributesList) {
|
||||
for (BlackboardAttribute bba : attributesList) {
|
||||
if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
|
||||
contactName = bba.getDisplayString();
|
||||
contactNameLabel.setText(contactName);
|
||||
contactNameLabel.setVisible(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
contactNameLabel.revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view by displaying the given list of attributes in the given
|
||||
* section panel.
|
||||
*
|
||||
* @param sectionAttributesList list of attributes to display.
|
||||
* @param sectionLabel section name label.
|
||||
* @param sectionPanel section panel to display the attributes in.
|
||||
*/
|
||||
private void updateSection(List<BlackboardAttribute> sectionAttributesList, JLabel sectionLabel, JPanel sectionPanel) {
|
||||
|
||||
// If there are no attributes for tis section, hide the section panel and the section label
|
||||
if (sectionAttributesList.isEmpty()) {
|
||||
sectionLabel.setVisible(false);
|
||||
sectionPanel.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// create a gridbag layout to show each attribute on one line
|
||||
GridBagLayout gridBagLayout = new GridBagLayout();
|
||||
GridBagConstraints constraints = new GridBagConstraints();
|
||||
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
|
||||
constraints.gridy = 0;
|
||||
constraints.insets = new java.awt.Insets(TOP_INSET, LEFT_INSET, 0, 0);
|
||||
for (BlackboardAttribute bba : sectionAttributesList) {
|
||||
constraints.fill = GridBagConstraints.NONE;
|
||||
constraints.weightx = 0;
|
||||
|
||||
constraints.gridx = 0;
|
||||
|
||||
// Add a label for attribute type
|
||||
javax.swing.JLabel attrTypeLabel = new javax.swing.JLabel();
|
||||
String attrLabel = bba.getAttributeType().getDisplayName();
|
||||
attrTypeLabel.setText(attrLabel);
|
||||
|
||||
// make type label bold - uncomment if needed.
|
||||
//attrTypeLabel.setFont(attrTypeLabel.getFont().deriveFont(Font.BOLD, attrTypeLabel.getFont().getSize() ));
|
||||
gridBagLayout.setConstraints(attrTypeLabel, constraints);
|
||||
sectionPanel.add(attrTypeLabel);
|
||||
|
||||
// Add the attribute value
|
||||
constraints.gridx++;
|
||||
javax.swing.JLabel attrValueLabel = new javax.swing.JLabel();
|
||||
attrValueLabel.setText(bba.getValueString());
|
||||
gridBagLayout.setConstraints(attrValueLabel, constraints);
|
||||
sectionPanel.add(attrValueLabel);
|
||||
|
||||
// add a filler to take up rest of the space
|
||||
constraints.gridx++;
|
||||
constraints.weightx = 1.0;
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
sectionPanel.add(new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)));
|
||||
|
||||
constraints.gridy++;
|
||||
}
|
||||
|
||||
sectionLabel.setVisible(true);
|
||||
sectionPanel.setVisible(true);
|
||||
|
||||
sectionPanel.setLayout(gridBagLayout);
|
||||
sectionPanel.revalidate();
|
||||
sectionPanel.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks off a search for personas, based in the list of attributes.
|
||||
*
|
||||
* @param accountAttributesList a list of account identifying attributes.
|
||||
*
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_persona_searching= Searching...",
|
||||
"ContactArtifactViewer_persona_unknown=Unknown"
|
||||
})
|
||||
private void initiatePersonasSearch(List<BlackboardAttribute> accountAttributesList) throws CentralRepoException {
|
||||
|
||||
personasLabel.setVisible(true);
|
||||
|
||||
String personaStatusLabelText = CentralRepository.isEnabled()
|
||||
? Bundle.ContactArtifactViewer_persona_searching()
|
||||
: Bundle.ContactArtifactViewer_persona_unknown();
|
||||
|
||||
// create a gridbag layout to show each participant on one line
|
||||
GridBagLayout gridBagLayout = new GridBagLayout();
|
||||
GridBagConstraints constraints = new GridBagConstraints();
|
||||
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
constraints.insets = new java.awt.Insets(TOP_INSET, LEFT_INSET, 0, 0);
|
||||
|
||||
// Add a Persona Name label
|
||||
constraints.fill = GridBagConstraints.NONE;
|
||||
constraints.weightx = 0;
|
||||
|
||||
//javax.swing.Box.Filler filler1 = this.createFiller(5, 0);
|
||||
//personasPanel.add(filler1, constraints);
|
||||
javax.swing.JLabel personaLabel = new javax.swing.JLabel();
|
||||
personaLabel.setText(Bundle.ContactArtifactViewer_persona_label());
|
||||
personaLabel.setFont(personaLabel.getFont().deriveFont(Font.BOLD, personaLabel.getFont().getSize()));
|
||||
gridBagLayout.setConstraints(personaLabel, constraints);
|
||||
personasPanel.add(personaLabel);
|
||||
|
||||
constraints.gridy++;
|
||||
javax.swing.JLabel personaStatusLabel = new javax.swing.JLabel();
|
||||
personaStatusLabel.setText(personaStatusLabelText);
|
||||
gridBagLayout.setConstraints(personaStatusLabel, constraints);
|
||||
personasPanel.add(personaStatusLabel);
|
||||
|
||||
|
||||
if (CentralRepository.isEnabled() ) {
|
||||
personasLabel.setEnabled(true);
|
||||
|
||||
// Kick off a background task to serach for personas for the contact
|
||||
ContactPersonaSearcherTask personaSearchTask = new ContactPersonaSearcherTask(accountAttributesList);
|
||||
personaSearchTask.execute();
|
||||
} else {
|
||||
personasLabel.setEnabled(false);
|
||||
personaLabel.setEnabled(false);
|
||||
personaStatusLabel.setEnabled(false);
|
||||
}
|
||||
|
||||
personasPanel.setLayout(gridBagLayout);
|
||||
personasPanel.revalidate();
|
||||
personasPanel.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Persona panel with the gathered persona information.
|
||||
*/
|
||||
private void updatePersonasPanel() {
|
||||
// Clear out the panel
|
||||
personasPanel.removeAll();
|
||||
|
||||
GridBagLayout gridBagLayout = new GridBagLayout();
|
||||
GridBagConstraints constraints = new GridBagConstraints();
|
||||
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
constraints.insets = new java.awt.Insets(TOP_INSET, LEFT_INSET, 0, 0);
|
||||
|
||||
if (contactUniquePersonasMap.isEmpty()) {
|
||||
showPersona(null, Collections.emptyList(), gridBagLayout, constraints);
|
||||
} else {
|
||||
for (Map.Entry<Persona, ArrayList<CentralRepoAccount>> entry : contactUniquePersonasMap.entrySet()) {
|
||||
List<CentralRepoAccount> missingAccounts = new ArrayList<>();
|
||||
ArrayList<CentralRepoAccount> personaAccounts = entry.getValue();
|
||||
|
||||
// create a list of accounts missing from this persona
|
||||
for (CentralRepoAccount account : contactUniqueAccountsList) {
|
||||
if (personaAccounts.contains(account) == false) {
|
||||
missingAccounts.add(account);
|
||||
}
|
||||
}
|
||||
|
||||
showPersona(entry.getKey(), missingAccounts, gridBagLayout, constraints);
|
||||
|
||||
constraints.gridy += 2;
|
||||
}
|
||||
}
|
||||
|
||||
personasPanel.setLayout(gridBagLayout);
|
||||
personasPanel.setSize(personasPanel.getPreferredSize());
|
||||
personasPanel.revalidate();
|
||||
personasPanel.repaint();
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_persona_label=Persona ",
|
||||
"ContactArtifactViewer_persona_text_none=None found",
|
||||
"ContactArtifactViewer_persona_button_view=View",
|
||||
"ContactArtifactViewer_persona_button_new=Create",
|
||||
"ContactArtifactViewer_missing_account_label=Missing Account: "
|
||||
})
|
||||
|
||||
/**
|
||||
* Displays the given persona in the persona panel.
|
||||
*
|
||||
* @param persona Persona to display.
|
||||
* @param missingAccountsList List of accounts this persona may be missing.
|
||||
* @param gridBagLayout Layout to use.
|
||||
* @param constraints layout constraints.
|
||||
*
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
private void showPersona(Persona persona, List<CentralRepoAccount> missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
|
||||
|
||||
constraints.fill = GridBagConstraints.NONE;
|
||||
constraints.weightx = 0;
|
||||
constraints.gridx = 0;
|
||||
|
||||
//javax.swing.Box.Filler filler1 = createFiller(5, 0);
|
||||
// gridBagLayout.setConstraints(filler1, constraints);
|
||||
//personasPanel.add(filler1);
|
||||
// Add a "Persona" label
|
||||
//constraints.gridx++;
|
||||
javax.swing.JLabel personaLabel = new javax.swing.JLabel();
|
||||
personaLabel.setText(Bundle.ContactArtifactViewer_persona_label());
|
||||
personaLabel.setFont(personaLabel.getFont().deriveFont(Font.BOLD, personaLabel.getFont().getSize()));
|
||||
gridBagLayout.setConstraints(personaLabel, constraints);
|
||||
personasPanel.add(personaLabel);
|
||||
|
||||
javax.swing.JLabel personaNameLabel = new javax.swing.JLabel();
|
||||
javax.swing.JButton personaButton = new javax.swing.JButton();
|
||||
|
||||
String personaName;
|
||||
String personaButtonText;
|
||||
ActionListener personaButtonListener;
|
||||
|
||||
if (persona != null) {
|
||||
personaName = persona.getName();
|
||||
personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
|
||||
personaButtonListener = new ViewPersonaButtonListener(persona);
|
||||
} else {
|
||||
personaName = Bundle.ContactArtifactViewer_persona_text_none();
|
||||
personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
|
||||
personaButtonListener = new CreatePersonaButtonListener(new PersonaUIComponents(personaNameLabel, personaButton));
|
||||
}
|
||||
|
||||
// Add the label for persona name,
|
||||
constraints.gridy++;
|
||||
constraints.gridx = 0;
|
||||
personaNameLabel.setText(personaName);
|
||||
gridBagLayout.setConstraints(personaNameLabel, constraints);
|
||||
personasPanel.add(personaNameLabel);
|
||||
|
||||
//constraints.gridx++;
|
||||
//personasPanel.add(createFiller(5, 0), constraints);
|
||||
// Add a Persona action button
|
||||
constraints.gridx++;
|
||||
personaButton.setText(personaButtonText);
|
||||
personaButton.addActionListener(personaButtonListener);
|
||||
|
||||
// no top inset of the button, in order to center align with the labels.
|
||||
constraints.insets = new java.awt.Insets(0, LEFT_INSET, 0, 0);
|
||||
gridBagLayout.setConstraints(personaButton, constraints);
|
||||
personasPanel.add(personaButton);
|
||||
|
||||
// restore normal inset
|
||||
constraints.insets = new java.awt.Insets(TOP_INSET, LEFT_INSET, 0, 0);
|
||||
|
||||
// show missing accounts.
|
||||
for (CentralRepoAccount missingAccount : missingAccountsList) {
|
||||
constraints.weightx = 0;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy++;
|
||||
|
||||
// Add a "Missing Account: " label
|
||||
constraints.gridx++; // Ident
|
||||
javax.swing.JLabel missingAccountLabel = new javax.swing.JLabel();
|
||||
missingAccountLabel.setText(Bundle.ContactArtifactViewer_missing_account_label());
|
||||
gridBagLayout.setConstraints(missingAccountLabel, constraints);
|
||||
personasPanel.add(missingAccountLabel);
|
||||
|
||||
// Add the label for account id,
|
||||
constraints.gridx++;
|
||||
javax.swing.JLabel missingAccountIdentifierLabel = new javax.swing.JLabel();
|
||||
missingAccountIdentifierLabel.setText(missingAccount.getIdentifier());
|
||||
gridBagLayout.setConstraints(missingAccountIdentifierLabel, constraints);
|
||||
personasPanel.add(missingAccountIdentifierLabel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an image from a TSK_CONTACT artifact.
|
||||
*
|
||||
* @param artifact
|
||||
*
|
||||
* @return Image from a TSK_CONTACT artifact or default image if none was
|
||||
* found or the artifact is not a TSK_CONTACT
|
||||
*/
|
||||
private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
|
||||
ImageIcon imageIcon = defaultImage;
|
||||
|
||||
if (artifact == null) {
|
||||
return imageIcon;
|
||||
}
|
||||
|
||||
BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||
if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
|
||||
return imageIcon;
|
||||
}
|
||||
|
||||
try {
|
||||
for (Content content : artifact.getChildren()) {
|
||||
if (content instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) content;
|
||||
|
||||
try {
|
||||
BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath()));
|
||||
imageIcon = new ImageIcon(image);
|
||||
break;
|
||||
} catch (IOException ex) {
|
||||
// ImageIO.read will through an IOException if file is not an image
|
||||
// therefore we don't need to report this exception just try
|
||||
// the next file.
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex);
|
||||
}
|
||||
|
||||
return imageIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread to search for a personas for all account identifier attributes for
|
||||
* a contact.
|
||||
*/
|
||||
private class ContactPersonaSearcherTask extends SwingWorker<Map<Persona, ArrayList<CentralRepoAccount>>, Void> {
|
||||
|
||||
private final List<BlackboardAttribute> accountAttributesList;
|
||||
private final List<CentralRepoAccount> uniqueAccountsList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a persona searcher task.
|
||||
*
|
||||
* @param accountAttributesList List of attributes that may map to
|
||||
* accounts.
|
||||
*/
|
||||
ContactPersonaSearcherTask(List<BlackboardAttribute> accountAttributesList) {
|
||||
this.accountAttributesList = accountAttributesList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Persona, ArrayList<CentralRepoAccount>> doInBackground() throws Exception {
|
||||
|
||||
Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas = new HashMap<>();
|
||||
|
||||
for (BlackboardAttribute bba : accountAttributesList) {
|
||||
|
||||
// Get account, add to accounts list
|
||||
Collection<Persona> personas;
|
||||
|
||||
Collection<CentralRepoAccount> accountCandidates
|
||||
= CentralRepoAccount.getAccountsWithIdentifier(bba.getValueString());
|
||||
|
||||
if (accountCandidates.isEmpty() == false) {
|
||||
CentralRepoAccount account = accountCandidates.iterator().next();
|
||||
if (uniqueAccountsList.contains(account) == false) {
|
||||
uniqueAccountsList.add(account);
|
||||
}
|
||||
|
||||
// get personas for the account
|
||||
personas = PersonaAccount.getPersonaAccountsForAccount(account.getId())
|
||||
.stream()
|
||||
.map(PersonaAccount::getPersona)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// make a list of unique personas, along with all their accounts
|
||||
for (Persona persona : personas) {
|
||||
if (uniquePersonas.containsKey(persona) == false) {
|
||||
Collection<CentralRepoAccount> accounts = persona.getPersonaAccounts()
|
||||
.stream()
|
||||
.map(PersonaAccount::getAccount)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ArrayList<CentralRepoAccount> personaAccountsList = new ArrayList<>(accounts);
|
||||
uniquePersonas.put(persona, personaAccountsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return uniquePersonas;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
|
||||
Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
|
||||
try {
|
||||
personasMap = super.get();
|
||||
|
||||
if (this.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
contactUniquePersonasMap.clear();
|
||||
contactUniquePersonasMap.putAll(personasMap);
|
||||
contactUniqueAccountsList.clear();
|
||||
contactUniqueAccountsList.addAll(uniqueAccountsList);
|
||||
|
||||
updatePersonasPanel();
|
||||
|
||||
} catch (CancellationException ex) {
|
||||
logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper class that bags the UI components that need to be updated when
|
||||
* a persona search task or a create dialog returns.
|
||||
*/
|
||||
private class PersonaUIComponents {
|
||||
|
||||
private final JLabel personaNameLabel;
|
||||
private final JButton personaActionButton;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param personaNameLabel Persona name label.
|
||||
* @param personaActionButton Persona action button.
|
||||
*/
|
||||
PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) {
|
||||
this.personaNameLabel = personaNameLabel;
|
||||
this.personaActionButton = personaActionButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns persona name label.
|
||||
*
|
||||
* @return Persona name label.
|
||||
*/
|
||||
public JLabel getPersonaNameLabel() {
|
||||
return personaNameLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns persona action button.
|
||||
*
|
||||
* @return Persona action button.
|
||||
*/
|
||||
public JButton getPersonaActionButton() {
|
||||
return personaActionButton;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action listener for Create persona button.
|
||||
*/
|
||||
private class CreatePersonaButtonListener implements ActionListener {
|
||||
|
||||
private final PersonaUIComponents personaUIComponents;
|
||||
|
||||
/**
|
||||
* Constructs a listener for Create persona button..
|
||||
*
|
||||
* @param personaUIComponents UI components.
|
||||
*/
|
||||
CreatePersonaButtonListener(PersonaUIComponents personaUIComponents) {
|
||||
this.personaUIComponents = personaUIComponents;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_persona_account_justification=Account found in Contact artifact"
|
||||
})
|
||||
|
||||
@Override
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
// Launch the Persona Create dialog - do not display immediately
|
||||
PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(ContactArtifactViewer.this,
|
||||
PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(personaUIComponents), false);
|
||||
|
||||
// Pre populate the persona name and accounts if we have them.
|
||||
PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
|
||||
|
||||
if (contactName != null) {
|
||||
personaPanel.setPersonaName(contactName);
|
||||
}
|
||||
|
||||
// pass the list of accounts to the dialog
|
||||
for (CentralRepoAccount account : contactUniqueAccountsList) {
|
||||
personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH);
|
||||
}
|
||||
|
||||
// display the dialog now
|
||||
createPersonaDialog.display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action listener for View persona button.
|
||||
*/
|
||||
private class ViewPersonaButtonListener implements ActionListener {
|
||||
|
||||
private final Persona persona;
|
||||
|
||||
/**
|
||||
* Creates listener for View persona button.
|
||||
*
|
||||
* @param persona
|
||||
*/
|
||||
ViewPersonaButtonListener(Persona persona) {
|
||||
this.persona = persona;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
new PersonaDetailsDialog(ContactArtifactViewer.this,
|
||||
PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for the create mode of the PersonaDetailsDialog
|
||||
*/
|
||||
class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback {
|
||||
|
||||
private final PersonaUIComponents personaUIComponents;
|
||||
|
||||
/**
|
||||
* Creates a callback to handle new persona creation.
|
||||
*
|
||||
* @param personaUIComponents UI Components.
|
||||
*/
|
||||
PersonaCreateCallbackImpl(PersonaUIComponents personaUIComponents) {
|
||||
this.personaUIComponents = personaUIComponents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callback(Persona persona) {
|
||||
JButton personaButton = personaUIComponents.getPersonaActionButton();
|
||||
if (persona != null) {
|
||||
// update the persona name label with newly created persona,
|
||||
// and change the button to a "View" button
|
||||
personaUIComponents.getPersonaNameLabel().setText(persona.getName());
|
||||
personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
|
||||
|
||||
// replace action listener with a View button listener
|
||||
for (ActionListener act : personaButton.getActionListeners()) {
|
||||
personaButton.removeActionListener(act);
|
||||
}
|
||||
personaButton.addActionListener(new ViewPersonaButtonListener(persona));
|
||||
|
||||
}
|
||||
|
||||
personaButton.getParent().revalidate();
|
||||
personaButton.getParent().repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for the view mode of the PersonaDetailsDialog
|
||||
*/
|
||||
class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback {
|
||||
|
||||
@Override
|
||||
public void callback(Persona persona) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel contactImage;
|
||||
private javax.swing.JLabel contactNameLabel;
|
||||
private javax.swing.JLabel emailsLabel;
|
||||
private javax.swing.JPanel emailsPanel;
|
||||
private javax.swing.JPanel namePanel;
|
||||
private javax.swing.JPanel otherAttrsPanel;
|
||||
private javax.swing.JLabel othersLabel;
|
||||
private javax.swing.JLabel personasLabel;
|
||||
private javax.swing.JPanel personasPanel;
|
||||
private javax.swing.JPanel phoneNumbersPanel;
|
||||
private javax.swing.JLabel phonesLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -42,7 +42,7 @@ import org.w3c.dom.events.EventTarget;
|
||||
* A file content viewer for HTML files.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
final class HtmlPanel extends javax.swing.JPanel {
|
||||
public final class HtmlPanel extends javax.swing.JPanel {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(HtmlPanel.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -54,7 +54,7 @@ final class HtmlPanel extends javax.swing.JPanel {
|
||||
/**
|
||||
* Creates new form HtmlViewerPanel
|
||||
*/
|
||||
HtmlPanel() {
|
||||
public HtmlPanel() {
|
||||
initComponents();
|
||||
Platform.runLater(() -> {
|
||||
webView = new WebView();
|
||||
@ -83,7 +83,7 @@ final class HtmlPanel extends javax.swing.JPanel {
|
||||
*
|
||||
* @param htmlText The HTML text to be applied to the text pane.
|
||||
*/
|
||||
void setHtmlText(String htmlText) {
|
||||
public void setHtmlText(String htmlText) {
|
||||
this.htmlText = htmlText;
|
||||
refresh();
|
||||
}
|
||||
@ -91,7 +91,7 @@ final class HtmlPanel extends javax.swing.JPanel {
|
||||
/**
|
||||
* Clear the HTML in the text pane and disable the show/hide button.
|
||||
*/
|
||||
void reset() {
|
||||
public void reset() {
|
||||
Platform.runLater(() -> {
|
||||
webView.getEngine().loadContent("", TEXT_TYPE);
|
||||
});
|
||||
|
@ -131,6 +131,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
private double zoomRatio;
|
||||
private double rotation; // Can be 0, 90, 180, and 270.
|
||||
|
||||
private boolean autoResize = true; // Auto resize when the user changes the size
|
||||
// of the content viewer unless the user has used the zoom buttons.
|
||||
private static final double[] ZOOM_STEPS = {
|
||||
0.0625, 0.125, 0.25, 0.375, 0.5, 0.75,
|
||||
1, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10};
|
||||
@ -197,7 +199,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
imageTaggingOptions.add(exportTagsMenuItem);
|
||||
|
||||
imageTaggingOptions.setPopupSize(300, 150);
|
||||
|
||||
|
||||
//Disable image tagging for non-windows users or upon failure to load OpenCV.
|
||||
if (!PlatformUtil.isWindowsOS() || !OpenCvLoader.openCvIsLoaded()) {
|
||||
tagsMenu.setEnabled(false);
|
||||
@ -266,8 +268,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
|
||||
/**
|
||||
* Handle tags menu item enabling and disabling given the state of the
|
||||
* content viewer. For example, when the tags group is empty (no tags on image),
|
||||
* disable delete menu item, hide menu item, and export menu item.
|
||||
* content viewer. For example, when the tags group is empty (no tags on
|
||||
* image), disable delete menu item, hide menu item, and export menu item.
|
||||
*/
|
||||
private void subscribeTagMenuItemsToStateChanges() {
|
||||
pcs.addPropertyChangeListener((event) -> {
|
||||
@ -394,6 +396,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
}
|
||||
|
||||
try {
|
||||
autoResize = true;
|
||||
Image fxImage = readImageTask.get();
|
||||
masterGroup.getChildren().clear();
|
||||
tagsGroup.getChildren().clear();
|
||||
@ -464,7 +467,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
* current file.
|
||||
*
|
||||
* @param contentTags
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
@ -488,7 +493,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
* appropriate type.
|
||||
*
|
||||
* @param contentTags
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
@ -685,16 +692,21 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void rotateLeftButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateLeftButtonActionPerformed
|
||||
autoResize = false;
|
||||
|
||||
rotation = (rotation + 270) % 360;
|
||||
updateView();
|
||||
}//GEN-LAST:event_rotateLeftButtonActionPerformed
|
||||
|
||||
private void rotateRightButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateRightButtonActionPerformed
|
||||
autoResize = false;
|
||||
|
||||
rotation = (rotation + 90) % 360;
|
||||
updateView();
|
||||
}//GEN-LAST:event_rotateRightButtonActionPerformed
|
||||
|
||||
private void zoomInButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomInButtonActionPerformed
|
||||
autoResize = false;
|
||||
// Find the next zoom step.
|
||||
for (int i = 0; i < ZOOM_STEPS.length; i++) {
|
||||
if (zoomRatio < ZOOM_STEPS[i]) {
|
||||
@ -706,6 +718,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
}//GEN-LAST:event_zoomInButtonActionPerformed
|
||||
|
||||
private void zoomOutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed
|
||||
autoResize = false;
|
||||
// Find the next zoom step.
|
||||
for (int i = ZOOM_STEPS.length - 1; i >= 0; i--) {
|
||||
if (zoomRatio > ZOOM_STEPS[i]) {
|
||||
@ -717,11 +730,16 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
}//GEN-LAST:event_zoomOutButtonActionPerformed
|
||||
|
||||
private void zoomResetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomResetButtonActionPerformed
|
||||
autoResize = true;
|
||||
resetView();
|
||||
}//GEN-LAST:event_zoomResetButtonActionPerformed
|
||||
|
||||
private void formComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentResized
|
||||
updateView();
|
||||
if (autoResize) {
|
||||
resetView();
|
||||
} else {
|
||||
updateView();
|
||||
}
|
||||
}//GEN-LAST:event_formComponentResized
|
||||
|
||||
/**
|
||||
@ -801,6 +819,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
* Creates an ImageTag instance from the ContentViewerTag.
|
||||
*
|
||||
* @param contentViewerTag
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private ImageTag buildImageTag(ContentViewerTag<ImageTagRegion> contentViewerTag) {
|
||||
@ -883,17 +902,17 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
List<ContentTag> tags = Case.getCurrentCase().getServices()
|
||||
.getTagsManager().getContentTagsByContent(file);
|
||||
List<ContentViewerTag<ImageTagRegion>> contentViewerTags = getContentViewerTags(tags);
|
||||
|
||||
|
||||
//Pull out image tag regions
|
||||
Collection<ImageTagRegion> regions = contentViewerTags.stream()
|
||||
.map(cvTag -> cvTag.getDetails()).collect(Collectors.toList());
|
||||
|
||||
|
||||
//Apply tags to image and write to file
|
||||
BufferedImage taggedImage = ImageTagsUtil.getImageWithTags(file, regions);
|
||||
Path output = Paths.get(exportChooser.getSelectedFile().getPath(),
|
||||
FilenameUtils.getBaseName(file.getName()) + "-with_tags.png"); //NON-NLS
|
||||
ImageIO.write(taggedImage, "png", output.toFile());
|
||||
|
||||
|
||||
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport());
|
||||
} catch (Exception ex) { //Runtime exceptions may spill out of ImageTagsUtil from JavaFX.
|
||||
//This ensures we (devs and users) have something when it doesn't work.
|
||||
|
@ -37,14 +37,14 @@ import org.sleuthkit.autopsy.texttranslation.ui.TranslateTextTask;
|
||||
/**
|
||||
* This is a panel for translation with a subcomponent that allows for translation.
|
||||
*/
|
||||
class TranslatablePanel extends JPanel {
|
||||
public class TranslatablePanel extends JPanel {
|
||||
|
||||
/**
|
||||
* This is an exception that can occur during the normal operation of the translatable
|
||||
* panel. For instance, this exception can be thrown if it is not possible to set the child
|
||||
* content to the provided content string.
|
||||
*/
|
||||
class TranslatablePanelException extends Exception {
|
||||
public class TranslatablePanelException extends Exception {
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
TranslatablePanelException(String message) {
|
||||
@ -61,7 +61,7 @@ class TranslatablePanel extends JPanel {
|
||||
* This describes a child component to be placed as a child of this panel. The child received
|
||||
* from {@link #getRootComponent() getRootComponent() } will listen for content updates from setContent().
|
||||
*/
|
||||
interface ContentComponent {
|
||||
public interface ContentComponent {
|
||||
/**
|
||||
* This method gets root component of the translation panel.
|
||||
* @return the root component to insert into the translatable panel
|
||||
@ -191,7 +191,7 @@ class TranslatablePanel extends JPanel {
|
||||
|
||||
@Messages({"TranslatablePanel.comboBoxOption.originalText=Original Text",
|
||||
"TranslatablePanel.comboBoxOption.translatedText=Translated Text"})
|
||||
TranslatablePanel(ContentComponent contentComponent) {
|
||||
public TranslatablePanel(ContentComponent contentComponent) {
|
||||
this(
|
||||
contentComponent,
|
||||
Bundle.TranslatablePanel_comboBoxOption_originalText(),
|
||||
@ -263,7 +263,7 @@ class TranslatablePanel extends JPanel {
|
||||
* This resets the component to an empty state and sets the translation bar visibility
|
||||
* based on whether there is a provider.
|
||||
*/
|
||||
final void reset() {
|
||||
public final void reset() {
|
||||
setContent(null, null);
|
||||
}
|
||||
|
||||
@ -272,7 +272,7 @@ class TranslatablePanel extends JPanel {
|
||||
* @param content the content for the panel
|
||||
* @param contentDescriptor the content descriptor to be used in error messages
|
||||
*/
|
||||
void setContent(String content, String contentDescriptor) {
|
||||
public void setContent(String content, String contentDescriptor) {
|
||||
cancelPendingTranslation();
|
||||
setTranslationEnabled();
|
||||
this.translateComboBox.setSelectedIndex(0);
|
||||
|
@ -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.artifactviewers;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
@ -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.artifactviewers;
|
||||
|
||||
import java.awt.Component;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
@ -0,0 +1,34 @@
|
||||
# Copyright 2020 Basis Technology Corp.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
DefaultArtifactContentViewer.copyMenuItem.text=Copy
|
||||
DefaultArtifactContentViewer.selectAllMenuItem.text=Select All
|
||||
MessageArtifactViewer.ccLabel.text=CC:
|
||||
MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
|
||||
MessageArtifactViewer.toText.text=to list goes here
|
||||
MessageArtifactViewer.toLabel.text=To:
|
||||
MessageArtifactViewer.htmlPane.TabConstraints.tabTitle=HTML
|
||||
MessageArtifactViewer.fromText.text=from address goes here
|
||||
MessageArtifactViewer.datetimeText.text=date goes here
|
||||
MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle=Headers
|
||||
MessageArtifactViewer.fromLabel.text=From:
|
||||
MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts
|
||||
MessageArtifactViewer.directionText.text=direction
|
||||
MessageArtifactViewer.subjectText.text=subject goes here
|
||||
MessageArtifactViewer.viewInNewWindowButton.text=View in New Window
|
||||
MessageArtifactViewer.subjectLabel.text=Subject:
|
||||
MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments
|
||||
MessageArtifactViewer.ccText.text=cc list goes here
|
||||
MessageArtifactViewer.textbodyScrollPane.TabConstraints.tabTitle=Text
|
@ -0,0 +1,85 @@
|
||||
# Copyright 2020 Basis Technology Corp.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
CalllogArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.
|
||||
CallLogArtifactViewer_heading_metadata=Metadata
|
||||
CallLogArtifactViewer_heading_others=Other Attributes
|
||||
CallLogArtifactViewer_heading_parties=Parties
|
||||
CallLogArtifactViewer_heading_Source=Source
|
||||
CallLogArtifactViewer_label_datasource=Data Source
|
||||
CallLogArtifactViewer_label_date=Date
|
||||
CallLogArtifactViewer_label_direction=Direction
|
||||
CallLogArtifactViewer_label_duration=Duration
|
||||
CallLogArtifactViewer_label_from=From
|
||||
CallLogArtifactViewer_label_to=To
|
||||
CallLogArtifactViewer_suffix_local=(Local)
|
||||
CallLogArtifactViewer_value_unknown=Unknown
|
||||
CommunicationArtifactViewerHelper_menuitem_copy=Copy
|
||||
CommunicationArtifactViewerHelper_persona_button_create=Create
|
||||
CommunicationArtifactViewerHelper_persona_button_view=View
|
||||
CommunicationArtifactViewerHelper_persona_label=Persona:
|
||||
CommunicationArtifactViewerHelper_persona_searching=Searching...
|
||||
CommunicationArtifactViewerHelper_persona_unknown=Unknown
|
||||
ContactArtifactViewer.contactImage.text=
|
||||
ContactArtifactViewer_contactname_unknown=Unknown
|
||||
ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.
|
||||
ContactArtifactViewer_emails_header=Email
|
||||
ContactArtifactViewer_found_all_accounts_label=All accounts found.
|
||||
ContactArtifactViewer_heading_Source=Source
|
||||
ContactArtifactViewer_label_datasource=Data Source
|
||||
ContactArtifactViewer_missing_account_label=Missing contact account
|
||||
ContactArtifactViewer_others_header=Other
|
||||
ContactArtifactViewer_persona_account_justification=Account found in Contact artifact
|
||||
ContactArtifactViewer_persona_button_new=Create
|
||||
ContactArtifactViewer_persona_button_view=View
|
||||
ContactArtifactViewer_persona_header=Persona
|
||||
ContactArtifactViewer_persona_label=Persona
|
||||
ContactArtifactViewer_persona_match_num=Match
|
||||
ContactArtifactViewer_persona_no_match=No matches found
|
||||
ContactArtifactViewer_persona_searching=Searching...
|
||||
ContactArtifactViewer_persona_unknown=Unknown
|
||||
ContactArtifactViewer_phones_header=Phone
|
||||
ContactArtifactViewer_plural_suffix=s
|
||||
DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database
|
||||
DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database
|
||||
DefaultArtifactContentViewer.attrsTableHeader.sources=Source(s)
|
||||
DefaultArtifactContentViewer.attrsTableHeader.type=Type
|
||||
DefaultArtifactContentViewer.attrsTableHeader.value=Value
|
||||
DefaultArtifactContentViewer.copyMenuItem.text=Copy
|
||||
DefaultArtifactContentViewer.selectAllMenuItem.text=Select All
|
||||
MessageAccountPanel_button_create_label=Create
|
||||
MessageAccountPanel_button_view_label=View
|
||||
MessageAccountPanel_persona_label=Persona:
|
||||
MessageAccountPanel_unknown_label=Unknown
|
||||
MessageArtifactViewer.AttachmentPanel.title=Attachments
|
||||
MessageArtifactViewer.ccLabel.text=CC:
|
||||
MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
|
||||
MessageArtifactViewer.toText.text=to list goes here
|
||||
MessageArtifactViewer.toLabel.text=To:
|
||||
MessageArtifactViewer.htmlPane.TabConstraints.tabTitle=HTML
|
||||
MessageArtifactViewer.fromText.text=from address goes here
|
||||
MessageArtifactViewer.datetimeText.text=date goes here
|
||||
MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle=Headers
|
||||
MessageArtifactViewer.fromLabel.text=From:
|
||||
MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts
|
||||
MessageArtifactViewer.directionText.text=direction
|
||||
MessageArtifactViewer.subjectText.text=subject goes here
|
||||
MessageArtifactViewer.viewInNewWindowButton.text=View in New Window
|
||||
MessageArtifactViewer.subjectLabel.text=Subject:
|
||||
MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments
|
||||
MessageArtifactViewer.ccText.text=cc list goes here
|
||||
MessageArtifactViewer.textbodyScrollPane.TabConstraints.tabTitle=Text
|
||||
# {0} - Persona count
|
||||
PersonaDisplayTask_persona_count_suffix=(1 of {0})
|
@ -0,0 +1,19 @@
|
||||
|
||||
DefaultArtifactContentViewer.selectAllMenuItem.text=\u3059\u3079\u3066\u3092\u9078\u629e
|
||||
|
||||
DefaultArtifactContentViewer.copyMenuItem.text=\u30b3\u30d4\u30fc
|
||||
MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
|
||||
MessageArtifactViewer.toText.text=\u5b9b\u5148\u306eTO\u30ea\u30b9\u30c8\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.toLabel.text=\u5b9b\u5148:
|
||||
MessageArtifactViewer.htmlPane.TabConstraints.tabTitle=HTML
|
||||
MessageArtifactViewer.fromText.text=\u9001\u4fe1\u5143\u30a2\u30c9\u30ec\u30b9\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.datetimeText.text=\u65e5\u4ed8\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle=\u30d8\u30c3\u30c0\u30fc
|
||||
MessageArtifactViewer.fromLabel.text=\u5dee\u51fa\u4eba:
|
||||
MessageArtifactViewer.directionText.text=\u9001\u53d7\u4fe1\u306e\u7a2e\u5225
|
||||
MessageArtifactViewer.subjectText.text=\u4ef6\u540d\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.viewInNewWindowButton.text=\u65b0\u3057\u3044\u30a6\u30a3\u30f3\u30c9\u30a6\u3067\u8868\u793a
|
||||
MessageArtifactViewer.subjectLabel.text=\u4ef6\u540d:
|
||||
MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle=\u6dfb\u4ed8\u30d5\u30a1\u30a4\u30eb
|
||||
MessageArtifactViewer.ccText.text=\u5b9b\u5148\u306eCC\u30ea\u30b9\u30c8\u3092\u3053\u3053\u306b\u8868\u793a
|
||||
MessageArtifactViewer.ccLabel.text=CC:
|
@ -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.artifactviewers;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.GridBagConstraints;
|
||||
@ -27,7 +27,6 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JScrollPane;
|
||||
@ -35,6 +34,7 @@ import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -66,8 +66,8 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
|
||||
private GridBagLayout m_gridBagLayout = new GridBagLayout();
|
||||
private GridBagConstraints m_constraints = new GridBagConstraints();
|
||||
|
||||
private final List<PersonaSearchAndDisplayTask> personaSearchtasks = new ArrayList<>();
|
||||
|
||||
private PersonaAccountFetcher currentAccountFetcher = null;
|
||||
|
||||
/**
|
||||
* Creates new form CallLogArtifactViewer.
|
||||
@ -92,6 +92,10 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
public void setArtifact(BlackboardArtifact artifact) {
|
||||
resetComponent();
|
||||
|
||||
if (artifact == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CallLogViewData callLogViewData = null;
|
||||
try {
|
||||
callLogViewData = getCallLogViewData(artifact);
|
||||
@ -101,11 +105,16 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
|
||||
// update the view with the call log data
|
||||
if (callLogViewData != null) {
|
||||
updateView(callLogViewData);
|
||||
List<AccountPersonaSearcherData> personaSearchDataList = updateView(callLogViewData);
|
||||
if(!personaSearchDataList.isEmpty()) {
|
||||
currentAccountFetcher = new PersonaAccountFetcher(artifact, personaSearchDataList, this);
|
||||
currentAccountFetcher.execute();
|
||||
} else {
|
||||
currentAccountFetcher = null;
|
||||
}
|
||||
}
|
||||
// repaint
|
||||
this.revalidate();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,6 +290,8 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
* Update the viewer with the call log data.
|
||||
*
|
||||
* @param callLogViewData Call log data to update the view with.
|
||||
*
|
||||
* @return List of AccountPersonaSearcherData objects.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"CallLogArtifactViewer_heading_parties=Parties",
|
||||
@ -288,10 +299,11 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
"CallLogArtifactViewer_label_from=From",
|
||||
"CallLogArtifactViewer_label_to=To"
|
||||
})
|
||||
private void updateView(CallLogViewData callLogViewData) {
|
||||
private List<AccountPersonaSearcherData> updateView(CallLogViewData callLogViewData) {
|
||||
|
||||
CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_parties());
|
||||
|
||||
List<AccountPersonaSearcherData> dataList = new ArrayList<>();
|
||||
// Display From address
|
||||
CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_from());
|
||||
|
||||
@ -301,10 +313,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, accountDisplayString);
|
||||
|
||||
// show persona
|
||||
Optional<PersonaSearchAndDisplayTask> task = CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, callLogViewData.getFromAccount());
|
||||
if (task.isPresent()) {
|
||||
personaSearchtasks.add(task.get());
|
||||
}
|
||||
dataList.addAll( CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, callLogViewData.getFromAccount()));
|
||||
} else {
|
||||
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_value_unknown());
|
||||
}
|
||||
@ -315,10 +324,8 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
String accountDisplayString = getAccountDisplayString(callLogViewData.getToAccount(), callLogViewData);
|
||||
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, accountDisplayString);
|
||||
|
||||
Optional<PersonaSearchAndDisplayTask> task = CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, callLogViewData.getToAccount());
|
||||
if (task.isPresent()) {
|
||||
personaSearchtasks.add(task.get());
|
||||
}
|
||||
dataList.addAll( CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, callLogViewData.getToAccount()));
|
||||
|
||||
} else {
|
||||
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_value_unknown());
|
||||
}
|
||||
@ -328,20 +335,26 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_to());
|
||||
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, otherParty);
|
||||
|
||||
Optional<PersonaSearchAndDisplayTask> task = CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, otherParty);
|
||||
if (task.isPresent()) {
|
||||
personaSearchtasks.add(task.get());
|
||||
}
|
||||
dataList.addAll( CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, otherParty));
|
||||
}
|
||||
|
||||
updateMetadataView(callLogViewData);
|
||||
|
||||
updateOtherAttributesView(callLogViewData);
|
||||
|
||||
updateSourceView(callLogViewData);
|
||||
|
||||
if (CentralRepository.isEnabled() == false) {
|
||||
showCRDisabledMessage();
|
||||
}
|
||||
|
||||
CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
|
||||
|
||||
this.setLayout(m_gridBagLayout);
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
|
||||
return dataList;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -392,6 +405,37 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDataSourceName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the other attributes section.
|
||||
*
|
||||
* @param callLogViewData Call log data.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"CallLogArtifactViewer_heading_others=Other Attributes"
|
||||
})
|
||||
private void updateOtherAttributesView(CallLogViewData callLogViewData) {
|
||||
|
||||
if (callLogViewData.getOtherAttributes().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_others());
|
||||
|
||||
for (Map.Entry<String, String> entry : callLogViewData.getOtherAttributes().entrySet()) {
|
||||
CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, entry.getKey());
|
||||
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"CalllogArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas."
|
||||
})
|
||||
private void showCRDisabledMessage() {
|
||||
CommunicationArtifactViewerHelper.addBlankLine(this, m_gridBagLayout, m_constraints);
|
||||
m_constraints.gridy++;
|
||||
CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
|
||||
m_constraints.gridy++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns display string for a account. Checks if the given account is the
|
||||
* local account, if it is known. If it is, it appends a "(Local)" suffix to
|
||||
@ -419,7 +463,9 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
|
||||
@Override
|
||||
public boolean isSupported(BlackboardArtifact artifact) {
|
||||
return artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID();
|
||||
|
||||
return (artifact != null)
|
||||
&& (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -428,8 +474,10 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
private void resetComponent() {
|
||||
|
||||
// cancel any outstanding persona searching threads.
|
||||
personaSearchtasks.forEach(task -> task.cancel(Boolean.TRUE));
|
||||
personaSearchtasks.clear();
|
||||
if(currentAccountFetcher != null && !currentAccountFetcher.isDone()) {
|
||||
currentAccountFetcher.cancel(true);
|
||||
currentAccountFetcher = null;
|
||||
}
|
||||
|
||||
// clear the panel
|
||||
this.removeAll();
|
||||
@ -441,9 +489,9 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
|
||||
m_constraints.anchor = GridBagConstraints.FIRST_LINE_START;
|
||||
m_constraints.gridy = 0;
|
||||
m_constraints.gridx = 0;
|
||||
m_constraints.weighty = 0.05;
|
||||
m_constraints.weightx = 0.05;
|
||||
m_constraints.insets = new java.awt.Insets(0, 0, 0, 0);
|
||||
m_constraints.weighty = 0.0;
|
||||
m_constraints.weightx = 0.0; // keep components fixed horizontally.
|
||||
m_constraints.insets = new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
|
||||
m_constraints.fill = GridBagConstraints.NONE;
|
||||
|
||||
}
|
@ -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.artifactviewers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
@ -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.artifactviewers;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
@ -27,12 +27,14 @@ import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.util.Optional;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
|
||||
@ -41,20 +43,20 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
* A class to help display a communication artifact in a panel using a
|
||||
* gridbaglayout.
|
||||
*/
|
||||
public final class CommunicationArtifactViewerHelper {
|
||||
final class CommunicationArtifactViewerHelper {
|
||||
|
||||
// Number of columns in the gridbag layout.
|
||||
private final static int MAX_COLS = 4;
|
||||
|
||||
private final static int LEFT_INDENT = 12;
|
||||
|
||||
final static int LEFT_INSET = 12;
|
||||
|
||||
/**
|
||||
* Empty private constructor
|
||||
*/
|
||||
private CommunicationArtifactViewerHelper() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a new heading to the panel.
|
||||
*
|
||||
@ -62,8 +64,15 @@ public final class CommunicationArtifactViewerHelper {
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constrains to use.
|
||||
* @param headerString Heading string to display.
|
||||
*
|
||||
* @return JLabel Heading label added.
|
||||
*/
|
||||
static void addHeader(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String headerString) {
|
||||
static JLabel addHeader(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String headerString) {
|
||||
|
||||
Insets savedInsets = constraints.insets;
|
||||
|
||||
// create label for heading
|
||||
javax.swing.JLabel headingLabel = new javax.swing.JLabel();
|
||||
|
||||
// add a blank line before the start of new section, unless it's
|
||||
// the first section
|
||||
@ -75,9 +84,9 @@ public final class CommunicationArtifactViewerHelper {
|
||||
|
||||
// let the header span all of the row
|
||||
constraints.gridwidth = MAX_COLS;
|
||||
constraints.insets = new Insets(0, 0, 0, 0); // No inset for header
|
||||
|
||||
// create label for heading
|
||||
javax.swing.JLabel headingLabel = new javax.swing.JLabel();
|
||||
// set text
|
||||
headingLabel.setText(headerString);
|
||||
|
||||
// make it large and bold
|
||||
@ -92,6 +101,28 @@ public final class CommunicationArtifactViewerHelper {
|
||||
|
||||
// add line end glue
|
||||
addLineEndGlue(panel, gridbagLayout, constraints);
|
||||
|
||||
//restore insets
|
||||
constraints.insets = savedInsets;
|
||||
|
||||
return headingLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given component to the panel.
|
||||
*
|
||||
* Caller must know what it's doing and set up all the constraints properly.
|
||||
*
|
||||
* @param panel Panel to update.
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constrains to use.
|
||||
* @param component Component to add.
|
||||
*/
|
||||
static void addComponent(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, JComponent component) {
|
||||
|
||||
// add to panel
|
||||
gridbagLayout.setConstraints(component, constraints);
|
||||
panel.add(component);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,7 +133,7 @@ public final class CommunicationArtifactViewerHelper {
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constrains to use.
|
||||
*/
|
||||
private static void addLineEndGlue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) {
|
||||
static void addLineEndGlue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) {
|
||||
// Place the filler just past the last column.
|
||||
constraints.gridx = MAX_COLS;
|
||||
|
||||
@ -155,7 +186,7 @@ public final class CommunicationArtifactViewerHelper {
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constrains to use.
|
||||
*/
|
||||
private static void addBlankLine(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) {
|
||||
static void addBlankLine(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) {
|
||||
constraints.gridy++;
|
||||
constraints.gridx = 0;
|
||||
|
||||
@ -167,54 +198,85 @@ public final class CommunicationArtifactViewerHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a label/key to the panel.
|
||||
* Adds a label/key to the panel at col 0.
|
||||
*
|
||||
* @param panel Panel to update.
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constrains to use.
|
||||
* @param keyString Key name to display.
|
||||
*
|
||||
* @return Label added.
|
||||
*/
|
||||
static void addKey(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString) {
|
||||
static JLabel addKey(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString) {
|
||||
return addKeyAtCol(panel, gridbagLayout, constraints, keyString, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a label/key to the panel at specified column.
|
||||
*
|
||||
* @param panel Panel to update.
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constrains to use.
|
||||
* @param keyString Key name to display.
|
||||
* @param gridx column index, must be less than MAX_COLS - 1.
|
||||
*
|
||||
* @return Label added.
|
||||
*/
|
||||
static JLabel addKeyAtCol(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString, int gridx) {
|
||||
|
||||
// create label
|
||||
javax.swing.JLabel keyLabel = new javax.swing.JLabel();
|
||||
|
||||
constraints.gridy++;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridx = gridx < MAX_COLS - 1 ? gridx : MAX_COLS - 2;
|
||||
|
||||
Insets savedInsets = constraints.insets;
|
||||
|
||||
// Set inset to indent in
|
||||
constraints.insets = new java.awt.Insets(0, LEFT_INDENT, 0, 0);
|
||||
|
||||
// create label,
|
||||
javax.swing.JLabel keyLabel = new javax.swing.JLabel();
|
||||
// set text
|
||||
keyLabel.setText(keyString + ": ");
|
||||
|
||||
// add to panel
|
||||
gridbagLayout.setConstraints(keyLabel, constraints);
|
||||
panel.add(keyLabel);
|
||||
|
||||
// restore inset
|
||||
constraints.insets = savedInsets;
|
||||
return keyLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value string to the panel.
|
||||
* Adds a value string to the panel at col 1.
|
||||
*
|
||||
* @param panel Panel to update.
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constrains to use.
|
||||
* @param keyString Value string to display.
|
||||
*
|
||||
* @return Label added.
|
||||
*/
|
||||
static void addValue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString) {
|
||||
static JLabel addValue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString) {
|
||||
return addValueAtCol(panel, gridbagLayout, constraints, valueString, 1);
|
||||
}
|
||||
|
||||
constraints.gridx = 1;
|
||||
/**
|
||||
* Adds a value string to the panel at specified column.
|
||||
*
|
||||
* @param panel Panel to update.
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constrains to use.
|
||||
* @param keyString Value string to display.
|
||||
* @param gridx Column index, must be less than MAX_COLS;
|
||||
*
|
||||
* @return Label added.
|
||||
*/
|
||||
static JLabel addValueAtCol(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString, int gridx) {
|
||||
// create label,
|
||||
javax.swing.JLabel valueField = new javax.swing.JLabel();
|
||||
|
||||
constraints.gridx = gridx < MAX_COLS ? gridx : MAX_COLS - 1;
|
||||
|
||||
int savedGridwidth = constraints.gridwidth;
|
||||
|
||||
// let the value span 2 cols
|
||||
constraints.gridwidth = 2;
|
||||
|
||||
// create label,
|
||||
javax.swing.JLabel valueField = new javax.swing.JLabel();
|
||||
// set text
|
||||
valueField.setText(valueString);
|
||||
|
||||
// attach a right click menu with Copy option
|
||||
@ -234,6 +296,63 @@ public final class CommunicationArtifactViewerHelper {
|
||||
|
||||
// end the line
|
||||
addLineEndGlue(panel, gridbagLayout, constraints);
|
||||
|
||||
return valueField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a message string, starting at column 0, and spanning the entire
|
||||
* row.
|
||||
*
|
||||
* @param panel Panel to show.
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constraints to use.
|
||||
*
|
||||
* @param messageString Message to display.
|
||||
*
|
||||
* @return Label for message added.
|
||||
*/
|
||||
static JLabel addMessageRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String messageString) {
|
||||
return addMessageRow(panel, gridbagLayout, constraints, messageString, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a message string, starting at specified column, and spanning the
|
||||
* entire row.
|
||||
*
|
||||
* @param panel Panel to show.
|
||||
* @param gridbagLayout Layout to use.
|
||||
* @param constraints Constraints to use.
|
||||
*
|
||||
* @param messageString Message to display.
|
||||
*
|
||||
* @return Label for message added.
|
||||
*/
|
||||
static JLabel addMessageRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String messageString, int gridx) {
|
||||
|
||||
// create label
|
||||
javax.swing.JLabel messageLabel = new javax.swing.JLabel();
|
||||
|
||||
constraints.gridy++;
|
||||
constraints.gridx = gridx < MAX_COLS - 1 ? gridx : MAX_COLS - 2;
|
||||
|
||||
int savedGridwidth = constraints.gridwidth;
|
||||
|
||||
constraints.gridwidth = 3;
|
||||
|
||||
// set text
|
||||
messageLabel.setText(messageString);
|
||||
|
||||
// add to panel
|
||||
gridbagLayout.setConstraints(messageLabel, constraints);
|
||||
panel.add(messageLabel);
|
||||
|
||||
addLineEndGlue(panel, gridbagLayout, constraints);
|
||||
|
||||
// restore constraints
|
||||
constraints.gridwidth = savedGridwidth;
|
||||
|
||||
return messageLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -250,8 +369,7 @@ public final class CommunicationArtifactViewerHelper {
|
||||
* @param constraints Constrains to use.
|
||||
* @param accountIdentifier Account identifier to search the persona.
|
||||
*
|
||||
* @return Optional PersonaSearchAndDisplayTask started to search for
|
||||
* persona.
|
||||
* @return List of AccountPersonaSearcherData objects.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"CommunicationArtifactViewerHelper_persona_label=Persona: ",
|
||||
@ -260,17 +378,17 @@ public final class CommunicationArtifactViewerHelper {
|
||||
"CommunicationArtifactViewerHelper_persona_button_view=View",
|
||||
"CommunicationArtifactViewerHelper_persona_button_create=Create"
|
||||
})
|
||||
static Optional<PersonaSearchAndDisplayTask> addPersonaRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String accountIdentifier) {
|
||||
|
||||
PersonaSearchAndDisplayTask personaTask = null;
|
||||
|
||||
static List<AccountPersonaSearcherData> addPersonaRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String accountIdentifier) {
|
||||
List<AccountPersonaSearcherData> dataList = new ArrayList<>();
|
||||
|
||||
constraints.gridy++;
|
||||
constraints.gridx = 1;
|
||||
|
||||
Insets savedInsets = constraints.insets;
|
||||
|
||||
// Indent in
|
||||
constraints.insets = new java.awt.Insets(0, LEFT_INDENT, 0, 0);
|
||||
// extra Indent in
|
||||
constraints.insets = new java.awt.Insets(0, 2 * LEFT_INSET, 0, 0);
|
||||
|
||||
// create label
|
||||
javax.swing.JLabel personaLabel = new javax.swing.JLabel();
|
||||
@ -293,23 +411,22 @@ public final class CommunicationArtifactViewerHelper {
|
||||
// Place a button as place holder. It will be enabled when persona is available.
|
||||
javax.swing.JButton personaButton = new javax.swing.JButton();
|
||||
personaButton.setText(Bundle.CommunicationArtifactViewerHelper_persona_button_view());
|
||||
personaButton.setMargin(new Insets(0, 5, 0, 5));
|
||||
personaButton.setEnabled(false);
|
||||
|
||||
|
||||
gridbagLayout.setConstraints(personaButton, constraints);
|
||||
panel.add(personaButton);
|
||||
|
||||
if (CentralRepository.isEnabled()) {
|
||||
// kick off a task to find the persona for this account
|
||||
personaTask = new PersonaSearchAndDisplayTask(panel, new AccountPersonaSearcherData(accountIdentifier, personaLabel, personaButton));
|
||||
personaTask.execute();
|
||||
dataList.add(new AccountPersonaSearcherData(accountIdentifier, personaLabel, personaButton));
|
||||
} else {
|
||||
personaLabel.setEnabled(false);
|
||||
}
|
||||
|
||||
addLineEndGlue(panel, gridbagLayout, constraints);
|
||||
|
||||
return Optional.ofNullable(personaTask);
|
||||
return dataList;
|
||||
}
|
||||
|
||||
/**
|
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="toolTipText" type="java.lang.String" value="" noResource="true"/>
|
||||
</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"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
</Form>
|
@ -0,0 +1,867 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.contentviewers.artifactviewers;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallback;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* This class displays the TSK_CONTACT artifact.
|
||||
*/
|
||||
@ServiceProvider(service = ArtifactContentViewer.class)
|
||||
public class ContactArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private GridBagLayout m_gridBagLayout = new GridBagLayout();
|
||||
private GridBagConstraints m_constraints = new GridBagConstraints();
|
||||
|
||||
private JLabel personaSearchStatusLabel;
|
||||
|
||||
private BlackboardArtifact contactArtifact;
|
||||
private String contactName;
|
||||
private String datasourceName;
|
||||
|
||||
private List<BlackboardAttribute> phoneNumList = new ArrayList<>();
|
||||
private List<BlackboardAttribute> emailList = new ArrayList<>();
|
||||
private List<BlackboardAttribute> nameList = new ArrayList<>();
|
||||
private List<BlackboardAttribute> otherList = new ArrayList<>();
|
||||
private List<BlackboardAttribute> accountAttributesList = new ArrayList<>();
|
||||
|
||||
private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png";
|
||||
private final ImageIcon defaultImage;
|
||||
|
||||
// A list of unique accounts matching the attributes of the contact artifact.
|
||||
private final List<CentralRepoAccount> contactUniqueAccountsList = new ArrayList<>();
|
||||
|
||||
// A list of all unique personas and their account, found by searching on the
|
||||
// account identifier attributes of the Contact artifact.
|
||||
private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap = new HashMap<>();
|
||||
|
||||
private ContactPersonaSearcherTask personaSearchTask;
|
||||
|
||||
/**
|
||||
* Creates new form ContactArtifactViewer
|
||||
*/
|
||||
public ContactArtifactViewer() {
|
||||
initComponents();
|
||||
|
||||
defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
setToolTipText(""); // NOI18N
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
@Override
|
||||
public void setArtifact(BlackboardArtifact artifact) {
|
||||
// Reset the panel.
|
||||
resetComponent();
|
||||
|
||||
if (artifact == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
extractArtifactData(artifact);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
|
||||
return;
|
||||
}
|
||||
|
||||
updateView();
|
||||
|
||||
this.setLayout(this.m_gridBagLayout);
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponent() {
|
||||
// Slap a vertical scrollbar on the panel.
|
||||
return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(BlackboardArtifact artifact) {
|
||||
return (artifact != null)
|
||||
&& (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts data from the artifact to be displayed in the panel.
|
||||
*
|
||||
* @param artifact Artifact to show.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private void extractArtifactData(BlackboardArtifact artifact) throws TskCoreException {
|
||||
|
||||
this.contactArtifact = artifact;
|
||||
|
||||
phoneNumList = new ArrayList<>();
|
||||
emailList = new ArrayList<>();
|
||||
nameList = new ArrayList<>();
|
||||
otherList = new ArrayList<>();
|
||||
accountAttributesList = new ArrayList<>();
|
||||
|
||||
// Get all the attributes and group them by the section panels they go in
|
||||
for (BlackboardAttribute bba : contactArtifact.getAttributes()) {
|
||||
if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
|
||||
phoneNumList.add(bba);
|
||||
accountAttributesList.add(bba);
|
||||
} else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
|
||||
emailList.add(bba);
|
||||
accountAttributesList.add(bba);
|
||||
} else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
|
||||
nameList.add(bba);
|
||||
} else {
|
||||
otherList.add(bba);
|
||||
if (bba.getAttributeType().getTypeName().equalsIgnoreCase("TSK_ID")) {
|
||||
accountAttributesList.add(bba);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
datasourceName = contactArtifact.getDataSource().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view with the data extracted from the artifact.
|
||||
*/
|
||||
private void updateView() {
|
||||
|
||||
// Update contact name, image, phone numbers
|
||||
updateContactDetails();
|
||||
|
||||
// update artifact source panel
|
||||
updateSource();
|
||||
|
||||
// show a empty Personas panel and kick off a serch for personas
|
||||
initiatePersonasSearch();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view with contact's details.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_phones_header=Phone",
|
||||
"ContactArtifactViewer_emails_header=Email",
|
||||
"ContactArtifactViewer_others_header=Other",})
|
||||
private void updateContactDetails() {
|
||||
|
||||
// update image and name.
|
||||
updateContactImage(m_gridBagLayout, m_constraints);
|
||||
updateContactName(m_gridBagLayout, m_constraints);
|
||||
|
||||
// update contact attributes sections
|
||||
updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints);
|
||||
updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints);
|
||||
updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the contact image in the view.
|
||||
*
|
||||
* @param contactPanelLayout Panel layout.
|
||||
* @param contactPanelConstraints Layout constraints.
|
||||
*
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer.contactImage.text=",})
|
||||
private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
|
||||
// place the image on the top right corner
|
||||
Insets savedInsets = contactPanelConstraints.insets;
|
||||
contactPanelConstraints.gridy = 0;
|
||||
contactPanelConstraints.gridx = 0;
|
||||
contactPanelConstraints.insets = new Insets(0, 0, 0, 0);
|
||||
|
||||
javax.swing.JLabel contactImage = new javax.swing.JLabel();
|
||||
contactImage.setIcon(getImageFromArtifact(contactArtifact));
|
||||
contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text());
|
||||
|
||||
// add image to top left corner of the page.
|
||||
CommunicationArtifactViewerHelper.addComponent(this, contactPanelLayout, contactPanelConstraints, contactImage);
|
||||
CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints);
|
||||
contactPanelConstraints.gridy++;
|
||||
|
||||
contactPanelConstraints.insets = savedInsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the contact name in the view.
|
||||
*
|
||||
* @param contactPanelLayout Panel layout.
|
||||
* @param contactPanelConstraints Layout constraints.
|
||||
*
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_contactname_unknown=Unknown",})
|
||||
private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
|
||||
|
||||
boolean foundName = false;
|
||||
for (BlackboardAttribute bba : this.nameList) {
|
||||
if (StringUtils.isEmpty(bba.getValueString()) == false) {
|
||||
contactName = bba.getDisplayString();
|
||||
|
||||
CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, contactName);
|
||||
foundName = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundName == false) {
|
||||
CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view by displaying the given list of attributes in the given
|
||||
* section panel.
|
||||
*
|
||||
* @param sectionAttributesList List of attributes to display.
|
||||
* @param sectionHeader Section name label.
|
||||
* @param contactPanelLayout Panel layout.
|
||||
* @param contactPanelConstraints Layout constraints.
|
||||
*
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_plural_suffix=s",})
|
||||
private void updateContactMethodSection(List<BlackboardAttribute> sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
|
||||
|
||||
// If there are no attributes for this section, do nothing
|
||||
if (sectionAttributesList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String sectionHeaderString = sectionHeader;
|
||||
if (sectionAttributesList.size() > 1) {
|
||||
sectionHeaderString = sectionHeaderString.concat(Bundle.ContactArtifactViewer_plural_suffix());
|
||||
}
|
||||
CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, sectionHeaderString);
|
||||
for (BlackboardAttribute bba : sectionAttributesList) {
|
||||
CommunicationArtifactViewerHelper.addKey(this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName());
|
||||
CommunicationArtifactViewerHelper.addValue(this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the source section.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_heading_Source=Source",
|
||||
"ContactArtifactViewer_label_datasource=Data Source",})
|
||||
private void updateSource() {
|
||||
CommunicationArtifactViewerHelper.addHeader(this, this.m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_heading_Source());
|
||||
CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource());
|
||||
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, datasourceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a search for Personas for the accounts associated with the
|
||||
* Contact.
|
||||
*
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_persona_header=Persona",
|
||||
"ContactArtifactViewer_persona_searching=Searching...",
|
||||
"ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.",
|
||||
"ContactArtifactViewer_persona_unknown=Unknown"
|
||||
})
|
||||
private void initiatePersonasSearch() {
|
||||
|
||||
// add a section header
|
||||
JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_persona_header());
|
||||
|
||||
m_constraints.gridy++;
|
||||
|
||||
// add a status label
|
||||
String personaStatusLabelText = CentralRepository.isEnabled()
|
||||
? Bundle.ContactArtifactViewer_persona_searching()
|
||||
: Bundle.ContactArtifactViewer_persona_unknown();
|
||||
|
||||
this.personaSearchStatusLabel = new javax.swing.JLabel();
|
||||
personaSearchStatusLabel.setText(personaStatusLabelText);
|
||||
|
||||
m_constraints.gridx = 0;
|
||||
|
||||
CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
|
||||
|
||||
if (CentralRepository.isEnabled()) {
|
||||
// Kick off a background task to serach for personas for the contact
|
||||
personaSearchTask = new ContactPersonaSearcherTask(contactArtifact);
|
||||
personaSearchTask.execute();
|
||||
} else {
|
||||
personaHeader.setEnabled(false);
|
||||
personaSearchStatusLabel.setEnabled(false);
|
||||
|
||||
CommunicationArtifactViewerHelper.addBlankLine(this, m_gridBagLayout, m_constraints);
|
||||
m_constraints.gridy++;
|
||||
CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
|
||||
m_constraints.gridy++;
|
||||
|
||||
CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Persona panel with the gathered persona information.
|
||||
*/
|
||||
private void updatePersonas() {
|
||||
|
||||
// Remove the "Searching....." label
|
||||
this.remove(personaSearchStatusLabel);
|
||||
|
||||
m_constraints.gridx = 0;
|
||||
if (contactUniquePersonasMap.isEmpty()) {
|
||||
// No persona found - show a button to create one.
|
||||
showPersona(null, 0, Collections.emptyList(), this.m_gridBagLayout, this.m_constraints);
|
||||
} else {
|
||||
int matchCounter = 0;
|
||||
for (Map.Entry<Persona, ArrayList<CentralRepoAccount>> entry : contactUniquePersonasMap.entrySet()) {
|
||||
List<CentralRepoAccount> missingAccounts = new ArrayList<>();
|
||||
ArrayList<CentralRepoAccount> personaAccounts = entry.getValue();
|
||||
matchCounter++;
|
||||
|
||||
// create a list of accounts missing from this persona
|
||||
for (CentralRepoAccount account : contactUniqueAccountsList) {
|
||||
if (personaAccounts.contains(account) == false) {
|
||||
missingAccounts.add(account);
|
||||
}
|
||||
}
|
||||
|
||||
showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints);
|
||||
m_constraints.gridy += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// add veritcal glue at the end
|
||||
CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
|
||||
|
||||
// redraw the panel
|
||||
this.setLayout(this.m_gridBagLayout);
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the given persona in the persona panel.
|
||||
*
|
||||
* @param persona Persona to display.
|
||||
* @param matchNumber Number of matches.
|
||||
* @param missingAccountsList List of contact accounts this persona may be
|
||||
* missing.
|
||||
* @param gridBagLayout Layout to use.
|
||||
* @param constraints layout constraints.
|
||||
*
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_persona_label=Persona ",
|
||||
"ContactArtifactViewer_persona_no_match=No matches found",
|
||||
"ContactArtifactViewer_persona_button_view=View",
|
||||
"ContactArtifactViewer_persona_button_new=Create",
|
||||
"ContactArtifactViewer_persona_match_num=Match ",
|
||||
"ContactArtifactViewer_missing_account_label=Missing contact account",
|
||||
"ContactArtifactViewer_found_all_accounts_label=All accounts found."
|
||||
})
|
||||
private void showPersona(Persona persona, int matchNumber, List<CentralRepoAccount> missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
|
||||
|
||||
// save the original insets
|
||||
Insets savedInsets = constraints.insets;
|
||||
|
||||
// some label are indented 2x to appear indented w.r.t column above
|
||||
Insets extraIndentInsets = new java.awt.Insets(0, 2 * CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
|
||||
|
||||
// Add a Match X label in col 0.
|
||||
constraints.gridx = 0;
|
||||
javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(this, gridBagLayout, constraints, String.format("%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber));
|
||||
|
||||
javax.swing.JLabel personaNameLabel = new javax.swing.JLabel();
|
||||
javax.swing.JButton personaButton = new javax.swing.JButton();
|
||||
|
||||
String personaName;
|
||||
String personaButtonText;
|
||||
ActionListener personaButtonListener;
|
||||
if (persona != null) {
|
||||
personaName = persona.getName();
|
||||
personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
|
||||
personaButtonListener = new ViewPersonaButtonListener(this, persona);
|
||||
} else {
|
||||
matchNumberLabel.setVisible(false);
|
||||
personaName = Bundle.ContactArtifactViewer_persona_no_match();
|
||||
personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
|
||||
personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton));
|
||||
}
|
||||
|
||||
//constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel
|
||||
constraints.gridx++;
|
||||
personaNameLabel.setText(personaName);
|
||||
gridBagLayout.setConstraints(personaNameLabel, constraints);
|
||||
CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel);
|
||||
//personasPanel.add(personaNameLabel);
|
||||
|
||||
// Add a Persona action button
|
||||
constraints.gridx++;
|
||||
//constraints.gridwidth = 1;
|
||||
personaButton.setText(personaButtonText);
|
||||
personaButton.addActionListener(personaButtonListener);
|
||||
|
||||
// Shirnk the button height.
|
||||
personaButton.setMargin(new Insets(0, 5, 0, 5));
|
||||
gridBagLayout.setConstraints(personaButton, constraints);
|
||||
CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton);
|
||||
CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
|
||||
|
||||
constraints.insets = savedInsets;
|
||||
|
||||
// if we have a persona, indicate if any of the contact's accounts are missing from it.
|
||||
if (persona != null) {
|
||||
if (missingAccountsList.isEmpty()) {
|
||||
constraints.gridy++;
|
||||
constraints.gridx = 1;
|
||||
//constraints.insets = labelInsets;
|
||||
|
||||
javax.swing.JLabel accountsStatus = new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label());
|
||||
constraints.insets = extraIndentInsets;
|
||||
CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, accountsStatus);
|
||||
constraints.insets = savedInsets;
|
||||
|
||||
CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
|
||||
} else {
|
||||
// show missing accounts.
|
||||
for (CentralRepoAccount missingAccount : missingAccountsList) {
|
||||
//constraints.weightx = 0;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy++;
|
||||
|
||||
// this needs an extra indent
|
||||
constraints.insets = extraIndentInsets;
|
||||
CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
|
||||
constraints.insets = savedInsets;
|
||||
|
||||
CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restore insets
|
||||
constraints.insets = savedInsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all artifact specific state.
|
||||
*/
|
||||
private void resetComponent() {
|
||||
|
||||
contactArtifact = null;
|
||||
contactName = null;
|
||||
datasourceName = null;
|
||||
|
||||
contactUniqueAccountsList.clear();
|
||||
contactUniquePersonasMap.clear();
|
||||
|
||||
phoneNumList.clear();
|
||||
emailList.clear();
|
||||
nameList.clear();
|
||||
otherList.clear();
|
||||
accountAttributesList.clear();
|
||||
|
||||
if (personaSearchTask != null) {
|
||||
personaSearchTask.cancel(Boolean.TRUE);
|
||||
personaSearchTask = null;
|
||||
}
|
||||
|
||||
// clear the panel
|
||||
this.removeAll();
|
||||
this.setLayout(null);
|
||||
|
||||
m_gridBagLayout = new GridBagLayout();
|
||||
m_constraints = new GridBagConstraints();
|
||||
|
||||
m_constraints.anchor = GridBagConstraints.FIRST_LINE_START;
|
||||
m_constraints.gridy = 0;
|
||||
m_constraints.gridx = 0;
|
||||
m_constraints.weighty = 0.0;
|
||||
m_constraints.weightx = 0.0; // keep components fixed horizontally.
|
||||
m_constraints.insets = new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
|
||||
m_constraints.fill = GridBagConstraints.NONE;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an image from a TSK_CONTACT artifact.
|
||||
*
|
||||
* @param artifact
|
||||
*
|
||||
* @return Image from a TSK_CONTACT artifact or default image if none was
|
||||
* found or the artifact is not a TSK_CONTACT
|
||||
*/
|
||||
private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
|
||||
ImageIcon imageIcon = defaultImage;
|
||||
|
||||
if (artifact == null) {
|
||||
return imageIcon;
|
||||
}
|
||||
|
||||
BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||
if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
|
||||
return imageIcon;
|
||||
}
|
||||
|
||||
try {
|
||||
for (Content content : artifact.getChildren()) {
|
||||
if (content instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) content;
|
||||
|
||||
try {
|
||||
BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath()));
|
||||
imageIcon = new ImageIcon(image);
|
||||
break;
|
||||
} catch (IOException ex) {
|
||||
// ImageIO.read will throw an IOException if file is not an image
|
||||
// therefore we don't need to report this exception just try
|
||||
// the next file.
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex);
|
||||
}
|
||||
|
||||
return imageIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread to search for a personas for all account identifier attributes for
|
||||
* a contact.
|
||||
*/
|
||||
private class ContactPersonaSearcherTask extends SwingWorker<Map<Persona, ArrayList<CentralRepoAccount>>, Void> {
|
||||
|
||||
private final BlackboardArtifact artifact;
|
||||
private final List<CentralRepoAccount> uniqueAccountsList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a persona searcher task.
|
||||
*
|
||||
* @param accountAttributesList List of attributes that may map to
|
||||
* accounts.
|
||||
*/
|
||||
ContactPersonaSearcherTask(BlackboardArtifact artifact) {
|
||||
this.artifact = artifact;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Persona, ArrayList<CentralRepoAccount>> doInBackground() throws Exception {
|
||||
|
||||
Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas = new HashMap<>();
|
||||
|
||||
CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
|
||||
List<Account> contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact);
|
||||
|
||||
for (Account account : contactAccountsList) {
|
||||
if (isCancelled()) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
Collection<PersonaAccount> personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
|
||||
if (personaAccounts != null && !personaAccounts.isEmpty()) {
|
||||
|
||||
// look for unique accounts
|
||||
Collection<CentralRepoAccount> accountCandidates
|
||||
= personaAccounts
|
||||
.stream()
|
||||
.map(PersonaAccount::getAccount)
|
||||
.collect(Collectors.toList());
|
||||
for (CentralRepoAccount crAccount : accountCandidates) {
|
||||
if (uniqueAccountsList.contains(crAccount) == false) {
|
||||
uniqueAccountsList.add(crAccount);
|
||||
}
|
||||
}
|
||||
|
||||
// get personas for the account
|
||||
Collection<Persona> personas
|
||||
= personaAccounts
|
||||
.stream()
|
||||
.map(PersonaAccount::getPersona)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// make a list of unique personas, along with all their accounts
|
||||
for (Persona persona : personas) {
|
||||
if (uniquePersonas.containsKey(persona) == false) {
|
||||
Collection<CentralRepoAccount> accounts = persona.getPersonaAccounts()
|
||||
.stream()
|
||||
.map(PersonaAccount::getAccount)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ArrayList<CentralRepoAccount> personaAccountsList = new ArrayList<>(accounts);
|
||||
uniquePersonas.put(persona, personaAccountsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uniquePersonas;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
|
||||
Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
|
||||
try {
|
||||
personasMap = super.get();
|
||||
|
||||
if (this.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
contactUniquePersonasMap.clear();
|
||||
contactUniquePersonasMap.putAll(personasMap);
|
||||
contactUniqueAccountsList.clear();
|
||||
contactUniqueAccountsList.addAll(uniqueAccountsList);
|
||||
|
||||
updatePersonas();
|
||||
|
||||
} catch (CancellationException ex) {
|
||||
logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper class that bags the UI components that need to be updated when
|
||||
* a persona search task or a create dialog returns.
|
||||
*/
|
||||
private class PersonaUIComponents {
|
||||
|
||||
private final JLabel personaNameLabel;
|
||||
private final JButton personaActionButton;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param personaNameLabel Persona name label.
|
||||
* @param personaActionButton Persona action button.
|
||||
*/
|
||||
PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) {
|
||||
this.personaNameLabel = personaNameLabel;
|
||||
this.personaActionButton = personaActionButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns persona name label.
|
||||
*
|
||||
* @return Persona name label.
|
||||
*/
|
||||
public JLabel getPersonaNameLabel() {
|
||||
return personaNameLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns persona action button.
|
||||
*
|
||||
* @return Persona action button.
|
||||
*/
|
||||
public JButton getPersonaActionButton() {
|
||||
return personaActionButton;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action listener for Create persona button.
|
||||
*/
|
||||
private class CreatePersonaButtonListener implements ActionListener {
|
||||
|
||||
private final Component parentComponent;
|
||||
private final PersonaUIComponents personaUIComponents;
|
||||
|
||||
/**
|
||||
* Constructs a listener for Create persona button..
|
||||
*
|
||||
* @param personaUIComponents UI components.
|
||||
*/
|
||||
CreatePersonaButtonListener(Component parentComponent, PersonaUIComponents personaUIComponents) {
|
||||
this.personaUIComponents = personaUIComponents;
|
||||
this.parentComponent = parentComponent;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"ContactArtifactViewer_persona_account_justification=Account found in Contact artifact"
|
||||
})
|
||||
|
||||
@Override
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
// Launch the Persona Create dialog - do not display immediately
|
||||
PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(parentComponent,
|
||||
PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(parentComponent, personaUIComponents), false);
|
||||
|
||||
// Pre populate the persona name and accounts if we have them.
|
||||
PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
|
||||
|
||||
if (contactName != null) {
|
||||
personaPanel.setPersonaName(contactName);
|
||||
}
|
||||
|
||||
// pass the list of accounts to the dialog
|
||||
for (CentralRepoAccount account : contactUniqueAccountsList) {
|
||||
personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH);
|
||||
}
|
||||
|
||||
// display the dialog now
|
||||
createPersonaDialog.display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action listener for View persona button.
|
||||
*/
|
||||
private class ViewPersonaButtonListener implements ActionListener {
|
||||
|
||||
private final Persona persona;
|
||||
private final Component parentComponent;
|
||||
|
||||
/**
|
||||
* Creates listener for View persona button.
|
||||
*
|
||||
* @param persona
|
||||
*/
|
||||
ViewPersonaButtonListener(Component parentComponent, Persona persona) {
|
||||
this.persona = persona;
|
||||
this.parentComponent = parentComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
new PersonaDetailsDialog(parentComponent,
|
||||
PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for the create mode of the PersonaDetailsDialog
|
||||
*/
|
||||
class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback {
|
||||
|
||||
private final Component parentComponent;
|
||||
private final PersonaUIComponents personaUIComponents;
|
||||
|
||||
/**
|
||||
* Creates a callback to handle new persona creation.
|
||||
*
|
||||
* @param personaUIComponents UI Components.
|
||||
*/
|
||||
PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) {
|
||||
this.parentComponent = parentComponent;
|
||||
this.personaUIComponents = personaUIComponents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callback(Persona persona) {
|
||||
JButton personaButton = personaUIComponents.getPersonaActionButton();
|
||||
if (persona != null) {
|
||||
// update the persona name label with newly created persona,
|
||||
// and change the button to a "View" button
|
||||
personaUIComponents.getPersonaNameLabel().setText(persona.getName());
|
||||
personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
|
||||
|
||||
// replace action listener with a View button listener
|
||||
for (ActionListener act : personaButton.getActionListeners()) {
|
||||
personaButton.removeActionListener(act);
|
||||
}
|
||||
personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona));
|
||||
|
||||
}
|
||||
|
||||
personaButton.getParent().revalidate();
|
||||
personaButton.getParent().repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for the view mode of the PersonaDetailsDialog
|
||||
*/
|
||||
class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback {
|
||||
|
||||
@Override
|
||||
public void callback(Persona persona) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -11,14 +11,14 @@
|
||||
<MenuItem class="javax.swing.JMenuItem" name="copyMenuItem">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="DefaultArtifactContentViewer.copyMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="DefaultArtifactContentViewer.copyMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</MenuItem>
|
||||
<MenuItem class="javax.swing.JMenuItem" name="selectAllMenuItem">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="DefaultArtifactContentViewer.selectAllMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="DefaultArtifactContentViewer.selectAllMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</MenuItem>
|
@ -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.artifactviewers;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
@ -54,6 +54,7 @@ import com.google.gson.JsonArray;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.swing.SwingUtilities;
|
||||
//import org.sleuthkit.autopsy.contentviewers.Bundle;
|
||||
|
||||
/**
|
||||
* This class displays a Blackboard artifact as a table listing all it's
|
@ -17,7 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.sleuthkit.autopsy.contentviewers;
|
||||
package org.sleuthkit.autopsy.contentviewers.artifactviewers;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
@ -120,7 +120,7 @@
|
||||
<Component class="javax.swing.JLabel" name="fromLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.fromLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.fromLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
@ -128,28 +128,28 @@
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.datetimeText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.datetimeText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="fromText">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.fromText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.fromText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="toLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.toLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.toLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="toText">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.toText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.toText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="autoscrolls" type="boolean" value="true"/>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
@ -160,14 +160,14 @@
|
||||
<Component class="javax.swing.JLabel" name="ccLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.ccLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.ccLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="ccText">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.ccText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.ccText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[27, 14]"/>
|
||||
@ -177,14 +177,14 @@
|
||||
<Component class="javax.swing.JLabel" name="subjectLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.subjectLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.subjectLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="subjectText">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.subjectText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.subjectText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[26, 14]"/>
|
||||
@ -195,7 +195,7 @@
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.directionText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.directionText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
@ -214,7 +214,7 @@
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
||||
<JTabbedPaneConstraints tabName="Headers">
|
||||
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</JTabbedPaneConstraints>
|
||||
</Constraint>
|
||||
@ -238,7 +238,7 @@
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
||||
<JTabbedPaneConstraints tabName="HTML">
|
||||
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.htmlPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.htmlPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</JTabbedPaneConstraints>
|
||||
</Constraint>
|
||||
@ -254,7 +254,7 @@
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
||||
<JTabbedPaneConstraints tabName="RTF">
|
||||
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</JTabbedPaneConstraints>
|
||||
</Constraint>
|
||||
@ -274,7 +274,7 @@
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
||||
<JTabbedPaneConstraints tabName="Attachments">
|
||||
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</JTabbedPaneConstraints>
|
||||
</Constraint>
|
||||
@ -311,7 +311,7 @@
|
||||
<Component class="javax.swing.JButton" name="viewInNewWindowButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.viewInNewWindowButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.viewInNewWindowButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@ -329,7 +329,7 @@
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
||||
<JTabbedPaneConstraints tabName="Accounts">
|
||||
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.accountsTab.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties" key="MessageArtifactViewer.accountsTab.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</JTabbedPaneConstraints>
|
||||
</Constraint>
|
@ -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.artifactviewers;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.AttachmentNode;
|
||||
import java.awt.Color;
|
||||
@ -41,7 +41,9 @@ import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.autopsy.contentviewers.TranslatablePanel;
|
||||
import org.sleuthkit.autopsy.contentviewers.TranslatablePanel.TranslatablePanelException;
|
||||
import org.sleuthkit.autopsy.contentviewers.Utilities;
|
||||
import org.sleuthkit.autopsy.corecomponents.AutoWrappingJTextPane;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
@ -16,122 +16,150 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.contentviewers;
|
||||
package org.sleuthkit.autopsy.contentviewers.artifactviewers;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallback;
|
||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
|
||||
/**
|
||||
* Background task to search for a persona for a given account.
|
||||
*
|
||||
* When the search is complete, it updates the UI components
|
||||
* for the persona appropriately.
|
||||
*
|
||||
*/
|
||||
* SwingWorker for fetching and updating Persona controls.
|
||||
*/
|
||||
class PersonaAccountFetcher extends SwingWorker<Map<String, Collection<Persona>>, Void> {
|
||||
|
||||
@NbBundle.Messages({
|
||||
private final static Logger logger = Logger.getLogger(PersonaAccountFetcher.class.getName());
|
||||
|
||||
private final BlackboardArtifact artifact;
|
||||
private final List<AccountPersonaSearcherData> personaSearchDataList;
|
||||
private final Component parentComponent;
|
||||
|
||||
/**
|
||||
* Construct the SwingWorker.
|
||||
*
|
||||
* @param artifact The artifact to search account for.
|
||||
* @param personaSearchDataList List of PersonaSerarcherData objects.
|
||||
* @param parentComponent The parent panel.
|
||||
*/
|
||||
PersonaAccountFetcher(BlackboardArtifact artifact, List<AccountPersonaSearcherData> personaSearchDataList, Component parentComponent) {
|
||||
this.artifact = artifact;
|
||||
this.personaSearchDataList = personaSearchDataList;
|
||||
this.parentComponent = parentComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Collection<Persona>> doInBackground() throws Exception {
|
||||
Map<String, Collection<Persona>> accountMap = new HashMap<>();
|
||||
|
||||
CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
|
||||
|
||||
List<Account> relatedAccountList = commManager.getAccountsRelatedToArtifact(artifact);
|
||||
|
||||
for (Account account : relatedAccountList) {
|
||||
|
||||
if (isCancelled()) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
Collection<PersonaAccount> personaAccountList = PersonaAccount.getPersonaAccountsForAccount(account);
|
||||
Collection<Persona> personaList = new ArrayList<>();
|
||||
for (PersonaAccount pAccount : personaAccountList) {
|
||||
personaList.add(pAccount.getPersona());
|
||||
}
|
||||
|
||||
accountMap.put(account.getTypeSpecificID(), personaList);
|
||||
}
|
||||
|
||||
return accountMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
if (isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Collection<Persona>> accountMap = get();
|
||||
|
||||
for (AccountPersonaSearcherData searcherData : personaSearchDataList) {
|
||||
Collection<Persona> persona = accountMap.get(searcherData.getAccountIdentifer());
|
||||
updatePersonaControls(searcherData, persona);
|
||||
}
|
||||
|
||||
} catch (CancellationException ex) {
|
||||
logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
parentComponent.repaint();
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"# {0} - Persona count",
|
||||
"PersonaDisplayTask_persona_count_suffix=(1 of {0})"
|
||||
})
|
||||
class PersonaSearchAndDisplayTask extends SwingWorker<Collection<Persona>, Void> {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(PersonaSearchAndDisplayTask.class.getName());
|
||||
|
||||
private final Component parentComponent;
|
||||
private final AccountPersonaSearcherData personaSearcherData;
|
||||
/**
|
||||
* Update the Persona gui controls.
|
||||
*
|
||||
* @param personaSearcherData The data objects with persona controls
|
||||
* @param personas Collection of persona objects
|
||||
*/
|
||||
private void updatePersonaControls(AccountPersonaSearcherData personaSearcherData, Collection<Persona> personas) {
|
||||
//Update the Persona label and button based on the search result
|
||||
String personaLabelText = Bundle.CommunicationArtifactViewerHelper_persona_label();
|
||||
String personaButtonText;
|
||||
ActionListener buttonActionListener;
|
||||
|
||||
PersonaSearchAndDisplayTask(Component parentComponent, AccountPersonaSearcherData personaSearcherData) {
|
||||
this.parentComponent = parentComponent;
|
||||
this.personaSearcherData = personaSearcherData;
|
||||
}
|
||||
if (personas == null || personas.isEmpty()) {
|
||||
// No persona found
|
||||
personaLabelText += Bundle.CommunicationArtifactViewerHelper_persona_unknown();
|
||||
|
||||
@Override
|
||||
protected Collection<Persona> doInBackground() throws Exception {
|
||||
|
||||
Collection<Persona> personas = new ArrayList<>();
|
||||
|
||||
if (CentralRepository.isEnabled()) {
|
||||
Collection<CentralRepoAccount> accountCandidates
|
||||
= CentralRepoAccount.getAccountsWithIdentifier(personaSearcherData.getAccountIdentifer());
|
||||
|
||||
if (accountCandidates.isEmpty() == false) {
|
||||
CentralRepoAccount account = accountCandidates.iterator().next();
|
||||
|
||||
// get personas for the account
|
||||
Collection<PersonaAccount> personaAccountsList = PersonaAccount.getPersonaAccountsForAccount(account.getId());
|
||||
personas = personaAccountsList.stream().map(PersonaAccount::getPersona)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
// show a 'Create' button
|
||||
personaButtonText = Bundle.CommunicationArtifactViewerHelper_persona_button_create();
|
||||
buttonActionListener = new CreatePersonaButtonListener(parentComponent, personaSearcherData);
|
||||
} else {
|
||||
Persona persona = personas.iterator().next();
|
||||
personaLabelText += persona.getName();
|
||||
if (personas.size() > 1) {
|
||||
personaLabelText += Bundle.PersonaDisplayTask_persona_count_suffix(Integer.toString(personas.size()));
|
||||
}
|
||||
return personas;
|
||||
// Show a 'View' button
|
||||
personaButtonText = Bundle.CommunicationArtifactViewerHelper_persona_button_view();
|
||||
buttonActionListener = new ViewPersonaButtonListener(parentComponent, persona);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
Collection<Persona> personas;
|
||||
try {
|
||||
personas = super.get();
|
||||
personaSearcherData.getPersonaNameLabel().setText(personaLabelText);
|
||||
personaSearcherData.getPersonaActionButton().setText(personaButtonText);
|
||||
personaSearcherData.getPersonaActionButton().setEnabled(true);
|
||||
|
||||
if (this.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
// set button action
|
||||
personaSearcherData.getPersonaActionButton().addActionListener(buttonActionListener);
|
||||
}
|
||||
|
||||
//Update the Persona label and button based on the search result
|
||||
String personaLabelText = Bundle.CommunicationArtifactViewerHelper_persona_label();
|
||||
String personaButtonText;
|
||||
ActionListener buttonActionListener;
|
||||
|
||||
if (personas.isEmpty()) {
|
||||
// No persona found
|
||||
personaLabelText += Bundle.CommunicationArtifactViewerHelper_persona_unknown();
|
||||
|
||||
// show a 'Create' button
|
||||
personaButtonText = Bundle.CommunicationArtifactViewerHelper_persona_button_create();
|
||||
buttonActionListener = new CreatePersonaButtonListener(parentComponent, personaSearcherData);
|
||||
} else {
|
||||
Persona persona = personas.iterator().next();
|
||||
personaLabelText += persona.getName();
|
||||
if (personas.size() > 1) {
|
||||
personaLabelText += Bundle.PersonaDisplayTask_persona_count_suffix(Integer.toString(personas.size()));
|
||||
}
|
||||
// Show a 'View' button
|
||||
personaButtonText = Bundle.CommunicationArtifactViewerHelper_persona_button_view();
|
||||
buttonActionListener = new ViewPersonaButtonListener(parentComponent, persona);
|
||||
}
|
||||
|
||||
personaSearcherData.getPersonaNameLabel().setText(personaLabelText);
|
||||
personaSearcherData.getPersonaActionButton().setText(personaButtonText);
|
||||
personaSearcherData.getPersonaActionButton().setEnabled(true);
|
||||
|
||||
// set button action
|
||||
personaSearcherData.getPersonaActionButton().addActionListener(buttonActionListener);
|
||||
} catch (CancellationException ex) {
|
||||
logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Action listener for Create persona button.
|
||||
*/
|
||||
@ -177,7 +205,7 @@ class PersonaSearchAndDisplayTask extends SwingWorker<Collection<Persona>, Void>
|
||||
* Callback method for the create mode of the PersonaDetailsDialog
|
||||
*/
|
||||
class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback {
|
||||
|
||||
|
||||
private final Component parentComponent;
|
||||
private final AccountPersonaSearcherData personaSearcherData;
|
||||
|
||||
@ -217,4 +245,5 @@ class PersonaSearchAndDisplayTask extends SwingWorker<Collection<Persona>, Void>
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -33,6 +33,8 @@ import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import javafx.application.Platform;
|
||||
import javafx.embed.swing.JFXPanel;
|
||||
import net.sf.sevenzipjbinding.SevenZip;
|
||||
import net.sf.sevenzipjbinding.SevenZipNativeInitializationException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.modules.InstalledFileLocator;
|
||||
@ -336,8 +338,8 @@ public class Installer extends ModuleInstall {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a folder in the config directory for object detection classifiers if one does not
|
||||
* exist.
|
||||
* Make a folder in the config directory for object detection classifiers if
|
||||
* one does not exist.
|
||||
*/
|
||||
private static void ensureClassifierFolderExists() {
|
||||
File objectDetectionClassifierDir = new File(PlatformUtil.getObjectDetectionClassifierPath());
|
||||
@ -381,6 +383,7 @@ public class Installer extends ModuleInstall {
|
||||
ensureClassifierFolderExists();
|
||||
ensureOcrLanguagePacksFolderExists();
|
||||
initJavaFx();
|
||||
initializeSevenZip();
|
||||
for (ModuleInstall mi : packageInstallers) {
|
||||
try {
|
||||
mi.restored();
|
||||
@ -393,8 +396,21 @@ public class Installer extends ModuleInstall {
|
||||
logger.log(Level.INFO, "Autopsy Core restore completed"); //NON-NLS
|
||||
preloadJython();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes 7zip-java bindings. We are performing initialization once
|
||||
* because we encountered issues related to file locking when initialization
|
||||
* was performed closer to where the bindings are used. See JIRA-6528.
|
||||
*/
|
||||
private void initializeSevenZip() {
|
||||
try {
|
||||
SevenZip.initSevenZipFromPlatformJAR();
|
||||
logger.log(Level.INFO, "7zip-java bindings loaded"); //NON-NLS
|
||||
} catch (SevenZipNativeInitializationException e) {
|
||||
logger.log(Level.SEVERE, "Error loading 7zip-java bindings", e); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an initial load of the Jython modules to speed up subsequent loads.
|
||||
*/
|
||||
@ -403,13 +419,12 @@ public class Installer extends ModuleInstall {
|
||||
try {
|
||||
JythonModuleLoader.getIngestModuleFactories();
|
||||
JythonModuleLoader.getGeneralReportModules();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
// This is a firewall exception to ensure that any possible exception caused
|
||||
// by this initial load of the Jython modules are caught and logged.
|
||||
logger.log(Level.SEVERE, "There was an error while doing an initial load of python plugins.", ex);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
new Thread(loader).start();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2015 Basis Technology Corp.
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -42,65 +42,29 @@ import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* This class periodically checks availability of collaboration resources -
|
||||
* remote database, remote keyword search server, messaging service - and
|
||||
* reports status updates to the user in case of a gap in service.
|
||||
* Monitors the status of services and publishes events and user notifications
|
||||
* when the status of a service changes. The database server, keyword search
|
||||
* server, and messaging service are considered to be core services in a
|
||||
* collaborative, multi-user case environment. Additional services can provide
|
||||
* current status by calling the setServiceStatus() method.
|
||||
*/
|
||||
public class ServicesMonitor {
|
||||
|
||||
private AutopsyEventPublisher eventPublisher;
|
||||
private static final Logger logger = Logger.getLogger(ServicesMonitor.class.getName());
|
||||
private final ScheduledThreadPoolExecutor periodicTasksExecutor;
|
||||
|
||||
private static final String PERIODIC_TASK_THREAD_NAME = "services-monitor-periodic-task-%d"; //NON-NLS
|
||||
private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1;
|
||||
private static final long CRASH_DETECTION_INTERVAL_MINUTES = 15;
|
||||
|
||||
private static final Set<String> servicesList = Stream.of(ServicesMonitor.Service.values())
|
||||
.map(Service::toString)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
/**
|
||||
* The service monitor maintains a mapping of each service to it's last
|
||||
* status update.
|
||||
*/
|
||||
private final ConcurrentHashMap<String, String> statusByService;
|
||||
|
||||
/**
|
||||
* Call constructor on start-up so that the first check of services is done
|
||||
* as soon as possible.
|
||||
*/
|
||||
private static ServicesMonitor instance = new ServicesMonitor();
|
||||
|
||||
/**
|
||||
* List of services that are being monitored. The service names should be
|
||||
* representative of the service functionality and readable as they get
|
||||
* logged when service outage occurs.
|
||||
* An enumeration of the core services in a collaborative, multi-user case
|
||||
* environment. The display names provided here can be used to identify the
|
||||
* service status events published for these services and to directly query
|
||||
* the ServicesMonitor for the current status of these services.
|
||||
*/
|
||||
public enum Service {
|
||||
|
||||
/**
|
||||
* Property change event fired when remote case database service status
|
||||
* changes. New value is set to updated ServiceStatus, old value is
|
||||
* null.
|
||||
*/
|
||||
REMOTE_CASE_DATABASE(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.remoteCaseDatabase.displayName.text")),
|
||||
/**
|
||||
* Property change event fired when remote keyword search service status
|
||||
* changes. New value is set to updated ServiceStatus, old value is
|
||||
* null.
|
||||
*/
|
||||
REMOTE_KEYWORD_SEARCH(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.remoteKeywordSearch.displayName.text")),
|
||||
/**
|
||||
* Property change event fired when messaging service status changes.
|
||||
* New value is set to updated ServiceStatus, old value is null.
|
||||
*/
|
||||
MESSAGING(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.messaging.displayName.text"));
|
||||
|
||||
private final String displayName;
|
||||
|
||||
private Service(String name) {
|
||||
this.displayName = name;
|
||||
private Service(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
@ -109,121 +73,249 @@ public class ServicesMonitor {
|
||||
};
|
||||
|
||||
/**
|
||||
* List of possible service statuses.
|
||||
* An enumeration of the standard service statuses.
|
||||
*/
|
||||
public enum ServiceStatus {
|
||||
|
||||
/**
|
||||
* Service is currently up.
|
||||
*/
|
||||
UP,
|
||||
/**
|
||||
* Service is currently down.
|
||||
*/
|
||||
DOWN
|
||||
};
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ServicesMonitor.class.getName());
|
||||
private static final String PERIODIC_TASK_THREAD_NAME = "services-monitor-periodic-task-%d"; //NON-NLS
|
||||
private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1;
|
||||
private static final long CRASH_DETECTION_INTERVAL_MINUTES = 15;
|
||||
private static final Set<String> coreServices = Stream.of(ServicesMonitor.Service.values()).map(Service::toString).collect(Collectors.toSet());
|
||||
private static ServicesMonitor servicesMonitor = new ServicesMonitor();
|
||||
private final ScheduledThreadPoolExecutor periodicTasksExecutor;
|
||||
private final ConcurrentHashMap<String, String> statusByService;
|
||||
private final AutopsyEventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* Gets the services monitor that monitors the status of services and
|
||||
* publishes events and user notifications when the status of a service
|
||||
* changes.
|
||||
*
|
||||
* @return The services monitor singleton.
|
||||
*/
|
||||
public synchronized static ServicesMonitor getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ServicesMonitor();
|
||||
if (servicesMonitor == null) {
|
||||
servicesMonitor = new ServicesMonitor();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ServicesMonitor() {
|
||||
|
||||
this.eventPublisher = new AutopsyEventPublisher();
|
||||
this.statusByService = new ConcurrentHashMap<>();
|
||||
|
||||
// First check is triggered immediately on current thread.
|
||||
checkAllServices();
|
||||
|
||||
/**
|
||||
* Start periodic task that check the availability of key collaboration
|
||||
* services.
|
||||
*/
|
||||
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
|
||||
periodicTasksExecutor.scheduleWithFixedDelay(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
|
||||
return servicesMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates service status and publishes the service status update if it is
|
||||
* different from previous status. Event is published locally. Logs status
|
||||
* Constructs a services monitor that monitors the status of services and
|
||||
* publishes events and user notifications when the status of a service
|
||||
* changes.
|
||||
*/
|
||||
private ServicesMonitor() {
|
||||
eventPublisher = new AutopsyEventPublisher();
|
||||
statusByService = new ConcurrentHashMap<>();
|
||||
|
||||
/*
|
||||
* The first service statuses check is performed immediately in the
|
||||
* current thread.
|
||||
*/
|
||||
checkAllServices();
|
||||
|
||||
/**
|
||||
* Start a periodic task to do ongoing service status checks.
|
||||
*/
|
||||
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
|
||||
periodicTasksExecutor.scheduleWithFixedDelay(new ServicesMonitoringTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the status of a service and publishes a service status event if
|
||||
* the current status is different from the previously reported status.
|
||||
*
|
||||
* @param service Name of the service.
|
||||
* @param status Updated status for the service.
|
||||
* @param details Details of the event.
|
||||
* @param status Current status of the service.
|
||||
* @param details Additional status details.
|
||||
*
|
||||
*/
|
||||
public void setServiceStatus(String service, String status, String details) {
|
||||
// if the status update is for an existing service who's status hasn't changed - do nothing.
|
||||
if (statusByService.containsKey(service) && status.equals(statusByService.get(service))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// new service or status has changed - identify service's display name
|
||||
statusByService.put(service, status);
|
||||
|
||||
String serviceDisplayName;
|
||||
try {
|
||||
serviceDisplayName = ServicesMonitor.Service.valueOf(service).getDisplayName();
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
// custom service that is not listed in ServicesMonitor.Service enum. Use service name as display name.
|
||||
serviceDisplayName = service;
|
||||
}
|
||||
|
||||
if (status.equals(ServiceStatus.UP.toString())) {
|
||||
logger.log(Level.INFO, "Connection to {0} is up", serviceDisplayName); //NON-NLS
|
||||
MessageNotifyUtil.Notify.info(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.title"),
|
||||
MessageNotifyUtil.Notify.info(
|
||||
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.title"),
|
||||
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.msg", serviceDisplayName));
|
||||
} else if (status.equals(ServiceStatus.DOWN.toString())) {
|
||||
logger.log(Level.SEVERE, "Failed to connect to {0}. Reason: {1}", new Object[]{serviceDisplayName, details}); //NON-NLS
|
||||
MessageNotifyUtil.Notify.error(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.title"),
|
||||
MessageNotifyUtil.Notify.error(
|
||||
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.title"),
|
||||
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.msg", serviceDisplayName));
|
||||
} else {
|
||||
logger.log(Level.INFO, "Status for {0} is {1}", new Object[]{serviceDisplayName, status}); //NON-NLS
|
||||
MessageNotifyUtil.Notify.info(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.title"),
|
||||
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.msg", new Object[]{serviceDisplayName, status}));
|
||||
logger.log(Level.INFO, "Status for {0} is {1} ({2})", new Object[]{serviceDisplayName, status}); //NON-NLS
|
||||
MessageNotifyUtil.Notify.info(
|
||||
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.title"),
|
||||
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.msg", new Object[]{serviceDisplayName, status, details}));
|
||||
}
|
||||
|
||||
// update and publish new status
|
||||
statusByService.put(service, status);
|
||||
eventPublisher.publishLocally(new ServiceEvent(service, status, details));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last status update for a service.
|
||||
* Get last recorded status for a service.
|
||||
*
|
||||
* @param service Name of the service.
|
||||
*
|
||||
* @return ServiceStatus Status for the service.
|
||||
*
|
||||
* @throws ServicesMonitorException If service name is null or service
|
||||
* doesn't exist.
|
||||
* @throws ServicesMonitorException If the service name is unknown to the
|
||||
* services monitor.
|
||||
*/
|
||||
public String getServiceStatus(String service) throws ServicesMonitorException {
|
||||
|
||||
if (service == null) {
|
||||
if (service == null || service.isEmpty()) {
|
||||
throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.nullServiceName.excepton.txt"));
|
||||
}
|
||||
|
||||
// if request is for one of our "core" services - perform an on demand check
|
||||
// to make sure we have the latest status.
|
||||
if (servicesList.contains(service)) {
|
||||
/*
|
||||
* If the request is for a core service, perform an "on demand" check to
|
||||
* get the current status.
|
||||
*/
|
||||
if (coreServices.contains(service)) {
|
||||
checkServiceStatus(service);
|
||||
}
|
||||
|
||||
String status = statusByService.get(service);
|
||||
if (status == null) {
|
||||
// no such service
|
||||
throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.unknownServiceName.excepton.txt", service));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs service availability status check.
|
||||
* Adds a subscriber to service status events for the core services.
|
||||
*
|
||||
* @param service Name of the service.
|
||||
* @param subscriber The subscriber to add.
|
||||
*/
|
||||
public void addSubscriber(PropertyChangeListener subscriber) {
|
||||
eventPublisher.addSubscriber(coreServices, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a subscriber to service status events for a subset of the services
|
||||
* known to the services monitor.
|
||||
*
|
||||
* @param services The services the subscriber is interested in.
|
||||
* @param subscriber The subscriber to add.
|
||||
*/
|
||||
public void addSubscriber(Set<String> services, PropertyChangeListener subscriber) {
|
||||
eventPublisher.addSubscriber(services, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a subscriber to service status events for a specific service known
|
||||
* to the services monitor.
|
||||
*
|
||||
* @param service The service the subscriber is interested in.
|
||||
* @param subscriber The subscriber to add.
|
||||
*/
|
||||
public void addSubscriber(String service, PropertyChangeListener subscriber) {
|
||||
eventPublisher.addSubscriber(service, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a subscriber to service status events for the core services.
|
||||
*
|
||||
* @param subscriber The subscriber to remove.
|
||||
*/
|
||||
public void removeSubscriber(PropertyChangeListener subscriber) {
|
||||
eventPublisher.removeSubscriber(coreServices, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a subscriber to service status events for a subset of the
|
||||
* services known to the services monitor.
|
||||
*
|
||||
* @param services The services the subscriber is no longer interested in.
|
||||
* @param subscriber The subscriber to remove.
|
||||
*/
|
||||
public void removeSubscriber(Set<String> services, PropertyChangeListener subscriber) {
|
||||
eventPublisher.removeSubscriber(services, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a subscriber to service status events for a specific service known
|
||||
* to the services monitor.
|
||||
*
|
||||
* @param service The service the subscriber is no longer interested in.
|
||||
* @param subscriber The subscriber to remove.
|
||||
*/
|
||||
public void removeSubscriber(String service, PropertyChangeListener subscriber) {
|
||||
eventPublisher.removeSubscriber(service, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the status of the core services in a collaborative, multi-user
|
||||
* case environment: the database server, the keyword search server and the
|
||||
* messaging service. Publishes a service event and user notification if the
|
||||
* status of a service has changed since the last check.
|
||||
*/
|
||||
private void checkAllServices() {
|
||||
if (!UserPreferences.getIsMultiUserModeEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String service : coreServices) {
|
||||
checkServiceStatus(service);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A task that checks the status of the core services in a collaborative,
|
||||
* multi-user case environment: the database server, the keyword search
|
||||
* server and the messaging service. Publishes a service event and user
|
||||
* notification if the status of a service has changed since the last check.
|
||||
*/
|
||||
private final class ServicesMonitoringTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
checkAllServices();
|
||||
} catch (Exception ex) { // Exception firewall
|
||||
logger.log(Level.SEVERE, "An error occurred during services monitoring", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown if an error occurs during a service status query.
|
||||
*/
|
||||
public class ServicesMonitorException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ServicesMonitorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ServicesMonitorException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a core service availability status check.
|
||||
*
|
||||
* @param service Name of the service to check.
|
||||
*/
|
||||
private void checkServiceStatus(String service) {
|
||||
if (service.equals(Service.REMOTE_CASE_DATABASE.toString())) {
|
||||
@ -236,7 +328,7 @@ public class ServicesMonitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs case database service availability status check.
|
||||
* Performs a database server availability status check.
|
||||
*/
|
||||
private void checkDatabaseConnectionStatus() {
|
||||
CaseDbConnectionInfo info;
|
||||
@ -256,7 +348,7 @@ public class ServicesMonitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs keyword search service availability status check.
|
||||
* Performs a keyword search service availability status check.
|
||||
*/
|
||||
private void checkKeywordSearchServerConnectionStatus() {
|
||||
KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);
|
||||
@ -303,113 +395,4 @@ public class ServicesMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event subscriber to this publisher. Subscriber will be subscribed
|
||||
* to all events from this publisher.
|
||||
*
|
||||
* @param subscriber The subscriber to add.
|
||||
*/
|
||||
public void addSubscriber(PropertyChangeListener subscriber) {
|
||||
eventPublisher.addSubscriber(servicesList, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event subscriber to this publisher.
|
||||
*
|
||||
* @param eventNames The events the subscriber is interested in.
|
||||
* @param subscriber The subscriber to add.
|
||||
*/
|
||||
public void addSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
|
||||
eventPublisher.addSubscriber(eventNames, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event subscriber to this publisher.
|
||||
*
|
||||
* @param eventName The event the subscriber is interested in.
|
||||
* @param subscriber The subscriber to add.
|
||||
*/
|
||||
public void addSubscriber(String eventName, PropertyChangeListener subscriber) {
|
||||
eventPublisher.addSubscriber(eventName, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an event subscriber from this publisher.
|
||||
*
|
||||
* @param eventNames The events the subscriber is no longer interested in.
|
||||
* @param subscriber The subscriber to remove.
|
||||
*/
|
||||
public void removeSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
|
||||
eventPublisher.removeSubscriber(eventNames, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an event subscriber from this publisher.
|
||||
*
|
||||
* @param eventName The event the subscriber is no longer interested in.
|
||||
* @param subscriber The subscriber to remove.
|
||||
*/
|
||||
public void removeSubscriber(String eventName, PropertyChangeListener subscriber) {
|
||||
eventPublisher.removeSubscriber(eventName, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an event subscriber to this publisher. Subscriber will be removed
|
||||
* from all event notifications from this publisher.
|
||||
*
|
||||
* @param subscriber The subscriber to remove.
|
||||
*/
|
||||
public void removeSubscriber(PropertyChangeListener subscriber) {
|
||||
eventPublisher.removeSubscriber(servicesList, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies connectivity to all services.
|
||||
*/
|
||||
private void checkAllServices() {
|
||||
if (!UserPreferences.getIsMultiUserModeEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String service : servicesList) {
|
||||
checkServiceStatus(service);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Runnable task that periodically checks the availability of
|
||||
* collaboration resources (remote database, remote keyword search service,
|
||||
* message broker) and reports status to the user in case of a gap in
|
||||
* service.
|
||||
*/
|
||||
private final class CrashDetectionTask implements Runnable {
|
||||
|
||||
/**
|
||||
* Monitor the availability of collaboration resources
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
checkAllServices();
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Unexpected exception in CrashDetectionTask", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when service status query results in an error.
|
||||
*/
|
||||
public class ServicesMonitorException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ServicesMonitorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ServicesMonitorException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -450,6 +450,7 @@
|
||||
<file name="cvt.wsmode" url="cvtWsmode.xml"/>
|
||||
<file name="discovery.wsmode" url="discoveryWsmode.xml"/>
|
||||
<file name="geolocation.wsmode" url="geolocationWsmode.xml"/>
|
||||
<file name="personas.wsmode" url="personasWsmode.xml"/>
|
||||
</folder>
|
||||
</folder>
|
||||
|
||||
|
11
Core/src/org/sleuthkit/autopsy/core/personasWsmode.xml
Normal file
11
Core/src/org/sleuthkit/autopsy/core/personasWsmode.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mode version="2.4">
|
||||
<name unique="personas"/>
|
||||
<kind type="editor"/>
|
||||
<state type="separated"/>
|
||||
<bounds x="76" y="68" width="1200" height="800"/>
|
||||
<frame state="0"/>
|
||||
|
||||
<empty-behavior permanent="false"/>
|
||||
</mode>
|
||||
|
@ -40,8 +40,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import org.sleuthkit.autopsy.contentviewers.ArtifactContentViewer;
|
||||
import org.sleuthkit.autopsy.contentviewers.DefaultArtifactContentViewer;
|
||||
import org.sleuthkit.autopsy.contentviewers.artifactviewers.ArtifactContentViewer;
|
||||
import org.sleuthkit.autopsy.contentviewers.artifactviewers.DefaultArtifactContentViewer;
|
||||
|
||||
/**
|
||||
* Instances of this class display the BlackboardArtifacts associated with the
|
||||
|
@ -63,7 +63,6 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
public class ExtractedContent implements AutopsyVisitableItem {
|
||||
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
||||
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
|
||||
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
|
||||
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||
private SleuthkitCase skCase; // set to null after case has been closed
|
||||
@ -145,12 +144,19 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
* This area has all of the blackboard artifacts that are not displayed in a
|
||||
* more specific form elsewhere in the tree.
|
||||
*/
|
||||
private class TypeFactory extends ChildFactory.Detachable<BlackboardArtifact.Type> {
|
||||
private class TypeFactory extends ChildFactory.Detachable<BlackboardArtifact.Type> implements RefreshThrottler.Refresher {
|
||||
|
||||
private final ArrayList<BlackboardArtifact.Type> doNotShow = new ArrayList<>();
|
||||
// maps the artifact type to its child node
|
||||
private final HashMap<BlackboardArtifact.Type, TypeNode> typeNodeList = new HashMap<>();
|
||||
|
||||
/**
|
||||
* RefreshThrottler is used to limit the number of refreshes performed
|
||||
* when CONTENT_CHANGED and DATA_ADDED ingest module events are
|
||||
* received.
|
||||
*/
|
||||
private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
TypeFactory() {
|
||||
super();
|
||||
@ -173,27 +179,11 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||
/**
|
||||
* This is a stop gap measure until a different way of handling
|
||||
* the closing of cases is worked out. Currently, remote events
|
||||
* may be received for a case that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
/**
|
||||
* Due to some unresolved issues with how cases are closed,
|
||||
* it is possible for the event to have a null oldValue if
|
||||
* the event is a remote event.
|
||||
*/
|
||||
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
|
||||
if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) {
|
||||
refresh(true);
|
||||
}
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeNotify();
|
||||
skCase = null;
|
||||
}
|
||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||
@ -204,32 +194,26 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
refresh(true);
|
||||
refresh(false);
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeNotify();
|
||||
skCase = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
refreshThrottler.registerForIngestModuleEvents();
|
||||
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
refreshThrottler.unregisterEventListener();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
typeNodeList.clear();
|
||||
}
|
||||
@ -273,6 +257,40 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
typeNodeList.put(key, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
refresh(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||
/**
|
||||
* This is a stop gap measure until a different way of handling
|
||||
* the closing of cases is worked out. Currently, remote events
|
||||
* may be received for a case that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
/**
|
||||
* Due to some unresolved issues with how cases are closed,
|
||||
* it is possible for the event to have a null oldValue if
|
||||
* the event is a remote event.
|
||||
*/
|
||||
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
|
||||
if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) {
|
||||
return true;
|
||||
}
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -355,73 +373,53 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
/**
|
||||
* Creates children for a given artifact type
|
||||
*/
|
||||
private class ArtifactFactory extends BaseChildFactory<BlackboardArtifact> {
|
||||
private class ArtifactFactory extends BaseChildFactory<BlackboardArtifact> implements RefreshThrottler.Refresher {
|
||||
|
||||
private BlackboardArtifact.Type type;
|
||||
private final BlackboardArtifact.Type type;
|
||||
|
||||
/**
|
||||
* RefreshThrottler is used to limit the number of refreshes performed
|
||||
* when CONTENT_CHANGED and DATA_ADDED ingest module events are
|
||||
* received.
|
||||
*/
|
||||
private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
|
||||
|
||||
ArtifactFactory(BlackboardArtifact.Type type) {
|
||||
super(type.getTypeName());
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case that is
|
||||
* already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
refresh(false);
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
/**
|
||||
* Even with the check above, it is still possible that
|
||||
* the case will be closed in a different thread before
|
||||
* this code executes. If that happens, it is possible
|
||||
* for the event to have a null oldValue.
|
||||
*/
|
||||
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
|
||||
if (null != event && event.getBlackboardArtifactType().equals(type)) {
|
||||
refresh(true);
|
||||
}
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
refresh(true);
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onAdd() {
|
||||
refreshThrottler.registerForIngestModuleEvents();
|
||||
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove() {
|
||||
refreshThrottler.unregisterEventListener();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -451,5 +449,43 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
refresh(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case that is
|
||||
* already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
/**
|
||||
* Even with the check above, it is still possible that the
|
||||
* case will be closed in a different thread before this
|
||||
* code executes. If that happens, it is possible for the
|
||||
* event to have a null oldValue.
|
||||
*/
|
||||
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
|
||||
if (null != event && event.getBlackboardArtifactType().equals(type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,39 +82,26 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
* Listens for case and ingest invest. Updates observers when events are
|
||||
* fired. FileType and FileTypes nodes are all listening to this.
|
||||
*/
|
||||
private class FileTypesByExtObservable extends Observable {
|
||||
private class FileTypesByExtObservable extends Observable implements RefreshThrottler.Refresher {
|
||||
|
||||
private final PropertyChangeListener pcl;
|
||||
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST;
|
||||
/**
|
||||
* RefreshThrottler is used to limit the number of refreshes performed
|
||||
* when CONTENT_CHANGED and DATA_ADDED ingest module events are
|
||||
* received.
|
||||
*/
|
||||
private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
|
||||
|
||||
private FileTypesByExtObservable() {
|
||||
super();
|
||||
this.CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.CURRENT_CASE);
|
||||
this.pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
|
||||
/**
|
||||
* If a new file has been added but does not have an extension
|
||||
* there is nothing to do.
|
||||
*/
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||
if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
|
||||
return;
|
||||
}
|
||||
ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
|
||||
if ((moduleContentEvent.getSource() instanceof AbstractFile) == false) {
|
||||
return;
|
||||
}
|
||||
AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource();
|
||||
if (abstractFile.getNameExtension().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
@ -139,14 +126,14 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
};
|
||||
|
||||
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||
refreshThrottler.registerForIngestModuleEvents();
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
refreshThrottler.unregisterEventListener();
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
@ -154,7 +141,52 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
typesRoot.updateShowCounts();
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case that is
|
||||
* already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
/**
|
||||
* If a new file has been added but does not have an
|
||||
* extension there is nothing to do.
|
||||
*/
|
||||
if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
|
||||
return false;
|
||||
}
|
||||
ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
|
||||
if ((moduleContentEvent.getSource() instanceof AbstractFile) == false) {
|
||||
return false;
|
||||
}
|
||||
AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource();
|
||||
if (!abstractFile.getNameExtension().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
/**
|
||||
* Case is closed, no refresh needed.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesByExtNode.fname.text");
|
||||
|
||||
/**
|
||||
|
@ -83,13 +83,19 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.CURRENT_CASE);
|
||||
|
||||
/**
|
||||
* RefreshThrottler is used to limit the number of refreshes performed when
|
||||
* CONTENT_CHANGED and DATA_ADDED ingest module events are received.
|
||||
*/
|
||||
private final RefreshThrottler refreshThrottler;
|
||||
|
||||
/**
|
||||
* Create the base expression used as the where clause in the queries for
|
||||
* files by mime type. Filters out certain kinds of files and directories,
|
||||
* and known/slack files based on user preferences.
|
||||
*
|
||||
* @return The base expression to be used in the where clause of queries for
|
||||
* files by mime type.
|
||||
* files by mime type.
|
||||
*/
|
||||
private String createBaseWhereExpr() {
|
||||
return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
|
||||
@ -108,6 +114,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
refreshThrottler.unregisterEventListener();
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
@ -155,32 +162,20 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
this.typesRoot = typesRoot;
|
||||
this.pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case that is
|
||||
* already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
typesRoot.updateShowCounts();
|
||||
populateHashMap();
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
|
||||
refreshMimeTypes();
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
if (evt.getNewValue() == null) {
|
||||
removeListeners();
|
||||
}
|
||||
}
|
||||
};
|
||||
refreshThrottler = new RefreshThrottler(new FileTypesByMimeTypeRefresher());
|
||||
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||
refreshThrottler.registerForIngestModuleEvents();
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
populateHashMap();
|
||||
}
|
||||
@ -201,7 +196,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
* @param node the Node which you wish to check.
|
||||
*
|
||||
* @return True if originNode is an instance of ByMimeTypeNode and is empty,
|
||||
* false otherwise.
|
||||
* false otherwise.
|
||||
*/
|
||||
public static boolean isEmptyMimeTypeNode(Node node) {
|
||||
boolean isEmptyMimeNode = false;
|
||||
@ -212,6 +207,41 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
|
||||
}
|
||||
|
||||
private void refreshMimeTypes() {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a different
|
||||
* way of handling the closing of cases is worked out. Currently, remote
|
||||
* events may be received for a case that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
typesRoot.updateShowCounts();
|
||||
populateHashMap();
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for updating the 'By Mime Type' view in the UI. See
|
||||
* RefreshThrottler for more details.
|
||||
*/
|
||||
private class FileTypesByMimeTypeRefresher implements RefreshThrottler.Refresher {
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
refreshMimeTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(PropertyChangeEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class which represents the root node of the "By MIME Type" tree, will
|
||||
* have children of each media type present in the database or no children
|
||||
|
125
Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java
Normal file
125
Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-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.datamodel;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
|
||||
/**
|
||||
* Utility class that can be used by UI nodes to reduce the number of
|
||||
* potentially expensive UI refresh events when DATA_ADDED and CONTENT_CHANGED
|
||||
* ingest manager events are received.
|
||||
*/
|
||||
class RefreshThrottler {
|
||||
|
||||
/**
|
||||
* The Refresher interface needs to be implemented by ChildFactory instances
|
||||
* that wish to take advantage of throttled refresh functionality.
|
||||
*/
|
||||
interface Refresher {
|
||||
|
||||
/**
|
||||
* The RefreshThrottler calls this method when the RefreshTask runs.
|
||||
*
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
/**
|
||||
* Determine whether the given event should result in a refresh.
|
||||
*
|
||||
* @param evt
|
||||
*
|
||||
* @return true if event should trigger a refresh, otherwise false.
|
||||
*/
|
||||
boolean isRefreshRequired(PropertyChangeEvent evt);
|
||||
}
|
||||
|
||||
static ScheduledThreadPoolExecutor refreshExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("Node Refresh Thread").build());
|
||||
// Keep a thread safe reference to the current refresh task (if any)
|
||||
private final AtomicReference<RefreshTask> refreshTaskRef;
|
||||
|
||||
// The factory instance that will be called when a refresh is due.
|
||||
private final Refresher refresher;
|
||||
|
||||
private static final long MIN_SECONDS_BETWEEN_REFRESH = 5;
|
||||
|
||||
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED, IngestManager.IngestModuleEvent.CONTENT_CHANGED);
|
||||
|
||||
/**
|
||||
* A RefreshTask is scheduled to run when an event arrives and there isn't
|
||||
* one already scheduled.
|
||||
*/
|
||||
private final class RefreshTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Call refresh on the factory
|
||||
refresher.refresh();
|
||||
// Clear the refresh task reference
|
||||
refreshTaskRef.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PropertyChangeListener that reacts to DATA_ADDED and CONTENT_CHANGED
|
||||
* events and schedules a refresh task if one is not already scheduled.
|
||||
*/
|
||||
private final PropertyChangeListener pcl;
|
||||
|
||||
RefreshThrottler(Refresher r) {
|
||||
this.refreshTaskRef = new AtomicReference<>(null);
|
||||
refresher = r;
|
||||
|
||||
pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())
|
||||
|| eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||
if (!refresher.isRefreshRequired(evt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshTask task = new RefreshTask();
|
||||
if (refreshTaskRef.compareAndSet(null, task)) {
|
||||
refreshExecutor.schedule(task, MIN_SECONDS_BETWEEN_REFRESH, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up listener for ingest module events of interest.
|
||||
*/
|
||||
void registerForIngestModuleEvents() {
|
||||
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove ingest module event listener.
|
||||
*/
|
||||
void unregisterEventListener() {
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
}
|
||||
}
|
@ -101,7 +101,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li
|
||||
constraints.weightx = LABEL_WEIGHT;
|
||||
constraints.weighty = LABEL_WEIGHT;
|
||||
constraints.gridwidth = LABEL_WIDTH;
|
||||
addToGridBagLayout(filterPanel.getCheckbox(), null, column);
|
||||
addToGridBagLayout(filterPanel.getCheckbox(), filterPanel.getAdditionalLabel(), column);
|
||||
if (filterPanel.hasPanel()) {
|
||||
constraints.gridx += constraints.gridwidth;
|
||||
constraints.fill = GridBagConstraints.BOTH;
|
||||
|
@ -101,3 +101,6 @@ DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which
|
||||
ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show
|
||||
VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show
|
||||
DiscoveryDialog.step1Label.text=Step 1: Choose result type
|
||||
ResultsSplitPaneDivider.hideButton.text=
|
||||
ResultsSplitPaneDivider.showButton.text=
|
||||
ResultsSplitPaneDivider.detailsLabel.text=Details Area
|
||||
|
@ -11,7 +11,7 @@ DiscoveryTopComponent.name=\ Discovery
|
||||
DiscoveryTopComponent.newSearch.text=New Search
|
||||
DiscoveryTopComponent.searchCancelled.text=Search has been cancelled.
|
||||
# {0} - search
|
||||
DiscoveryTopComponent.searchComplete.text=Results for {0}
|
||||
DiscoveryTopComponent.searchComplete.text=Results with {0}
|
||||
# {0} - searchType
|
||||
DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait.
|
||||
DiscoveryUiUtility.bytes.text=bytes
|
||||
@ -57,18 +57,24 @@ FileSearch.InterestingItemGroupKey.noSets=None
|
||||
FileSearch.KeywordListGroupKey.noKeywords=None
|
||||
FileSearch.NoGroupingGroupKey.allFiles=All Files
|
||||
FileSearch.ObjectDetectedGroupKey.noSets=None
|
||||
FileSearchData.FileSize.LARGE_IMAGE.displayName=Large: 1-50MB
|
||||
FileSearchData.FileSize.LARGE_VIDEO.displayName=Large: 1-5GB
|
||||
FileSearchData.FileSize.MEDIUM_IMAGE.displayName=Medium: 100KB-1MB
|
||||
FileSearchData.FileSize.MEDIUM_VIDEO.displayName=Medium: 100MB-1GB
|
||||
FileSearchData.FileSize.SMALL_IMAGE.displayName=Small: 16-100KB
|
||||
FileSearchData.FileSize.SMALL_VIDEO.displayName=Small: 500KB-100MB
|
||||
FileSearchData.FileSize.XLARGE_IMAGE.displayName=XLarge: 50-200MB
|
||||
FileSearchData.FileSize.XLARGE_VIDEO.displayName=XLarge: 5-10GB
|
||||
FileSearchData.FileSize.XSMALL_IMAGE.displayName=XSmall: 0-16KB
|
||||
FileSearchData.FileSize.XSMALL_VIDEO.displayName=XSmall: 0-500KB
|
||||
FileSearchData.FileSize.XXLARGE_IMAGE.displayName=XXLarge: 200MB+
|
||||
FileSearchData.FileSize.XXLARGE_VIDEO.displayName=XXLarge: 10GB+
|
||||
FileSearchData.FileSize.100kbto1mb=: 100KB-1MB
|
||||
FileSearchData.FileSize.100mbto1gb=: 100MB-1GB
|
||||
FileSearchData.FileSize.10PlusGb=: 10GB+
|
||||
FileSearchData.FileSize.16kbto100kb=: 16-100KB
|
||||
FileSearchData.FileSize.1gbto5gb=: 1-5GB
|
||||
FileSearchData.FileSize.1mbto50mb=: 1-50MB
|
||||
FileSearchData.FileSize.200PlusMb=: 200MB+
|
||||
FileSearchData.FileSize.500kbto100mb=: 500KB-100MB
|
||||
FileSearchData.FileSize.50mbto200mb=: 50-200MB
|
||||
FileSearchData.FileSize.5gbto10gb=: 5-10GB
|
||||
FileSearchData.FileSize.LARGE.displayName=Large
|
||||
FileSearchData.FileSize.MEDIUM.displayName=Medium
|
||||
FileSearchData.FileSize.SMALL.displayName=Small
|
||||
FileSearchData.FileSize.upTo16kb=: 0-16KB
|
||||
FileSearchData.FileSize.upTo500kb=: 0-500KB
|
||||
FileSearchData.FileSize.XLARGE.displayName=XLarge
|
||||
FileSearchData.FileSize.XSMALL.displayName=XSmall
|
||||
FileSearchData.FileSize.XXLARGE.displayName=XXLarge
|
||||
FileSearchData.FileType.Audio.displayName=Audio
|
||||
FileSearchData.FileType.Documents.displayName=Documents
|
||||
FileSearchData.FileType.Executables.displayName=Executables
|
||||
@ -106,45 +112,44 @@ FileSearchFiltering.concatenateSetNamesForDisplay.comma=,
|
||||
# {1} - Data source ID
|
||||
FileSearchFiltering.DataSourceFilter.datasource={0}({1})
|
||||
# {0} - filters
|
||||
FileSearchFiltering.DataSourceFilter.desc=Files in data source(s): {0}
|
||||
FileSearchFiltering.DataSourceFilter.or=\ or
|
||||
FileSearchFiltering.DataSourceFilter.desc=Data source(s): {0}
|
||||
FileSearchFiltering.DataSourceFilter.or=,
|
||||
# {0} - filters
|
||||
FileSearchFiltering.FileTypeFilter.desc=Files with type: {0}
|
||||
FileSearchFiltering.FileTypeFilter.or=\ or
|
||||
FileSearchFiltering.FileTypeFilter.desc=Type: {0}
|
||||
FileSearchFiltering.FileTypeFilter.or=,
|
||||
# {0} - filters
|
||||
FileSearchFiltering.FrequencyFilter.desc=Files with frequency: {0}
|
||||
FileSearchFiltering.FrequencyFilter.or=\ or
|
||||
FileSearchFiltering.FrequencyFilter.desc=Past occurrences: {0}
|
||||
FileSearchFiltering.FrequencyFilter.or=,
|
||||
# {0} - filters
|
||||
FileSearchFiltering.HashSetFilter.desc=Files with hash set hits in set(s): {0}
|
||||
FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0}
|
||||
# {0} - filters
|
||||
FileSearchFiltering.InterestingItemSetFilter.desc=Files with interesting item hits in set(s): {0}
|
||||
FileSearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0}
|
||||
# {0} - filters
|
||||
FileSearchFiltering.KeywordListFilter.desc=Files with keywords in list(s): {0}
|
||||
FileSearchFiltering.KnownFilter.desc=Files which are not known
|
||||
FileSearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0}
|
||||
FileSearchFiltering.KnownFilter.desc=which are not known
|
||||
# {0} - filters
|
||||
FileSearchFiltering.ObjectDetectionFilter.desc=Files with objects detected in set(s): {0}
|
||||
FileSearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0}
|
||||
# {0} - filters
|
||||
FileSearchFiltering.ParentFilter.desc=Files with paths matching: {0}
|
||||
FileSearchFiltering.ParentFilter.desc=Paths matching: {0}
|
||||
FileSearchFiltering.ParentFilter.exact=(exact match)
|
||||
FileSearchFiltering.ParentFilter.or=\ or
|
||||
FileSearchFiltering.ParentFilter.excluded=(excluded)
|
||||
FileSearchFiltering.ParentFilter.included=(included)
|
||||
FileSearchFiltering.ParentFilter.or=,
|
||||
FileSearchFiltering.ParentFilter.substring=(substring)
|
||||
FileSearchFiltering.ParentSearchTerm.excludeString=\ (exclude)
|
||||
FileSearchFiltering.ParentSearchTerm.fullString=\ (exact)
|
||||
FileSearchFiltering.ParentSearchTerm.includeString=\ (include)
|
||||
FileSearchFiltering.ParentSearchTerm.subString=\ (substring)
|
||||
FileSearchFiltering.PreviouslyNotableFilter.desc=Files that were previously marked as notable
|
||||
FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable
|
||||
# {0} - filters
|
||||
FileSearchFiltering.ScoreFilter.desc=Files with score(s) of : {0}
|
||||
FileSearchFiltering.ScoreFilter.desc=Score(s) of : {0}
|
||||
# {0} - filters
|
||||
FileSearchFiltering.SizeFilter.desc=Files with size in range(s): {0}
|
||||
FileSearchFiltering.SizeFilter.or=\ or
|
||||
# {0} - Minimum bytes
|
||||
# {1} - Maximum bytes
|
||||
FileSearchFiltering.SizeFilter.range=({0} to {1})
|
||||
FileSearchFiltering.SizeFilter.desc=Size(s): {0}
|
||||
FileSearchFiltering.SizeFilter.or=,
|
||||
# {0} - tag names
|
||||
FileSearchFiltering.TagsFilter.desc=Files that have been tagged {0}
|
||||
FileSearchFiltering.TagsFilter.or=\ or
|
||||
FileSearchFiltering.UserCreatedFilter.desc=Files that contain EXIF data
|
||||
FileSearchFiltering.TagsFilter.desc=Tagged {0}
|
||||
FileSearchFiltering.TagsFilter.or=,
|
||||
FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data
|
||||
FileSearchPanel.sortingPanel.border.title=Grouping
|
||||
FileSearchPanel.addButton.text=Add
|
||||
FileSearchPanel.substringRadioButton.text=Substring
|
||||
@ -186,7 +191,7 @@ GroupsListPanel.noResults.title.text=No results found
|
||||
ImageThumbnailPanel.isDeleted.text=All instances of file are deleted.
|
||||
# {0} - otherInstanceCount
|
||||
ImageThumbnailPanel.nameLabel.more.text=\ and {0} more
|
||||
OpenDiscoveryAction.resultsIncomplete.text=Results may be incomplete
|
||||
OpenDiscoveryAction.resultsIncomplete.text=Discovery results may be incomplete
|
||||
ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it.
|
||||
ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable.
|
||||
ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag.
|
||||
@ -259,6 +264,9 @@ DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which
|
||||
ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show
|
||||
VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show
|
||||
DiscoveryDialog.step1Label.text=Step 1: Choose result type
|
||||
ResultsSplitPaneDivider.hideButton.text=
|
||||
ResultsSplitPaneDivider.showButton.text=
|
||||
ResultsSplitPaneDivider.detailsLabel.text=Details Area
|
||||
VideoThumbnailPanel.bytes.text=bytes
|
||||
VideoThumbnailPanel.deleted.text=All instances of file are deleted.
|
||||
VideoThumbnailPanel.gigaBytes.text=GB
|
||||
|
@ -43,23 +43,25 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace pref="196" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="filler1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="step1Label" min="-2" pref="243" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Component id="imagesButton" min="-2" pref="110" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="videosButton" min="-2" pref="110" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="documentsButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="370" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="step1Label" min="-2" pref="243" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="filler1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="391" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace pref="196" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
|
@ -275,19 +275,21 @@ final class DiscoveryDialog extends javax.swing.JDialog {
|
||||
toolBarPanelLayout.setHorizontalGroup(
|
||||
toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(toolBarPanelLayout.createSequentialGroup()
|
||||
.addContainerGap(196, Short.MAX_VALUE)
|
||||
.addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, toolBarPanelLayout.createSequentialGroup()
|
||||
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(step1Label, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap()
|
||||
.addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(toolBarPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addComponent(imagesButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(videosButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(documentsButton)))
|
||||
.addContainerGap(196, Short.MAX_VALUE))
|
||||
.addComponent(documentsButton)
|
||||
.addContainerGap(370, Short.MAX_VALUE))
|
||||
.addGroup(toolBarPanelLayout.createSequentialGroup()
|
||||
.addComponent(step1Label, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(391, Short.MAX_VALUE))))
|
||||
);
|
||||
toolBarPanelLayout.setVerticalGroup(
|
||||
toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
|
@ -41,7 +41,7 @@
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JSplitPane" name="rightSplitPane">
|
||||
<Properties>
|
||||
<Property name="dividerSize" type="int" value="15"/>
|
||||
<Property name="dividerSize" type="int" value="35"/>
|
||||
<Property name="orientation" type="int" value="0"/>
|
||||
<Property name="resizeWeight" type="double" value="1.0"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
|
@ -19,11 +19,14 @@
|
||||
package org.sleuthkit.autopsy.discovery;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneDivider;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneUI;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.Mode;
|
||||
@ -67,6 +70,34 @@ public final class DiscoveryTopComponent extends TopComponent {
|
||||
mainSplitPane.setLeftComponent(groupListPanel);
|
||||
rightSplitPane.setTopComponent(resultsPanel);
|
||||
rightSplitPane.setBottomComponent(detailsPanel);
|
||||
//set color of divider
|
||||
rightSplitPane.setUI(new BasicSplitPaneUI() {
|
||||
@Override
|
||||
public BasicSplitPaneDivider createDefaultDivider() {
|
||||
return new BasicSplitPaneDividerImpl(this);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Private class for replacing the divider for the results split pane.
|
||||
*/
|
||||
private final class BasicSplitPaneDividerImpl extends BasicSplitPaneDivider {
|
||||
|
||||
/**
|
||||
* Construct a new BasicSplitPaneDividerImpl.
|
||||
*
|
||||
* @param ui The component which contains the split pane this divider is
|
||||
* in.
|
||||
*/
|
||||
BasicSplitPaneDividerImpl(BasicSplitPaneUI ui) {
|
||||
super(ui);
|
||||
this.setLayout(new BorderLayout());
|
||||
this.add(new ResultsSplitPaneDivider());
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,7 +160,7 @@ public final class DiscoveryTopComponent extends TopComponent {
|
||||
mainSplitPane.setDividerLocation(250);
|
||||
mainSplitPane.setPreferredSize(new java.awt.Dimension(1100, 700));
|
||||
|
||||
rightSplitPane.setDividerSize(15);
|
||||
rightSplitPane.setDividerSize(35);
|
||||
rightSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||
rightSplitPane.setResizeWeight(1.0);
|
||||
rightSplitPane.setPreferredSize(new java.awt.Dimension(800, 700));
|
||||
@ -249,11 +280,11 @@ public final class DiscoveryTopComponent extends TopComponent {
|
||||
@Subscribe
|
||||
@Messages({"DiscoveryTopComponent.newSearch.text=New Search",
|
||||
"# {0} - search",
|
||||
"DiscoveryTopComponent.searchComplete.text=Results for {0}"})
|
||||
"DiscoveryTopComponent.searchComplete.text=Results with {0}"})
|
||||
void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) {
|
||||
newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text());
|
||||
progressMessageTextArea.setForeground(Color.black);
|
||||
progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(searchCompleteEvent.getFilters().stream().map(FileFilter::getDesc).collect(Collectors.joining(", "))));
|
||||
progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(searchCompleteEvent.getFilters().stream().map(FileFilter::getDesc).collect(Collectors.joining("; "))));
|
||||
progressMessageTextArea.setCaretPosition(0);
|
||||
}
|
||||
|
||||
@ -269,6 +300,7 @@ public final class DiscoveryTopComponent extends TopComponent {
|
||||
newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text());
|
||||
progressMessageTextArea.setForeground(Color.red);
|
||||
progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchCancelled_text());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.discovery;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -29,6 +30,8 @@ import java.util.logging.Level;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextPane;
|
||||
import org.openide.util.ImageUtilities;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
@ -224,7 +227,16 @@ final class DiscoveryUiUtils {
|
||||
message += dsmodulesWrapper.getMessage();
|
||||
}
|
||||
if (!message.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(dialog, message, Bundle.OpenDiscoveryAction_resultsIncomplete_text(), JOptionPane.INFORMATION_MESSAGE);
|
||||
JScrollPane messageScrollPane = new JScrollPane();
|
||||
JTextPane messageTextPane = new JTextPane();
|
||||
messageTextPane.setText(message);
|
||||
messageTextPane.setVisible(true);
|
||||
messageTextPane.setEditable(false);
|
||||
messageTextPane.setCaretPosition(0);
|
||||
messageScrollPane.setMaximumSize(new Dimension(600, 100));
|
||||
messageScrollPane.setPreferredSize(new Dimension(600, 100));
|
||||
messageScrollPane.setViewportView(messageTextPane);
|
||||
JOptionPane.showMessageDialog(dialog, messageScrollPane, Bundle.OpenDiscoveryAction_resultsIncomplete_text(), JOptionPane.PLAIN_MESSAGE);
|
||||
}
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Exception while determining which modules have been run for Discovery", ex);
|
||||
|
@ -45,7 +45,6 @@ final class DocumentFilterPanel extends AbstractFiltersPanel {
|
||||
addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0);
|
||||
addFilter(new HashSetFilterPanel(), false, null, 1);
|
||||
addFilter(new InterestingItemsFilterPanel(), false, null, 1);
|
||||
addFilter(new ObjectDetectedFilterPanel(), false, null, 1);
|
||||
addFilter(new ParentFolderFilterPanel(), false, null, 1);
|
||||
addPanelsToScrollPane(documentsFiltersSplitPane);
|
||||
}
|
||||
|
@ -126,39 +126,46 @@ final class FileSearchData {
|
||||
* Enum representing the file size
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"FileSearchData.FileSize.XXLARGE_IMAGE.displayName=XXLarge: 200MB+",
|
||||
"FileSearchData.FileSize.XLARGE_IMAGE.displayName=XLarge: 50-200MB",
|
||||
"FileSearchData.FileSize.LARGE_IMAGE.displayName=Large: 1-50MB",
|
||||
"FileSearchData.FileSize.MEDIUM_IMAGE.displayName=Medium: 100KB-1MB",
|
||||
"FileSearchData.FileSize.SMALL_IMAGE.displayName=Small: 16-100KB",
|
||||
"FileSearchData.FileSize.XSMALL_IMAGE.displayName=XSmall: 0-16KB",
|
||||
"FileSearchData.FileSize.XXLARGE_VIDEO.displayName=XXLarge: 10GB+",
|
||||
"FileSearchData.FileSize.XLARGE_VIDEO.displayName=XLarge: 5-10GB",
|
||||
"FileSearchData.FileSize.LARGE_VIDEO.displayName=Large: 1-5GB",
|
||||
"FileSearchData.FileSize.MEDIUM_VIDEO.displayName=Medium: 100MB-1GB",
|
||||
"FileSearchData.FileSize.SMALL_VIDEO.displayName=Small: 500KB-100MB",
|
||||
"FileSearchData.FileSize.XSMALL_VIDEO.displayName=XSmall: 0-500KB",})
|
||||
"FileSearchData.FileSize.XXLARGE.displayName=XXLarge",
|
||||
"FileSearchData.FileSize.XLARGE.displayName=XLarge",
|
||||
"FileSearchData.FileSize.LARGE.displayName=Large",
|
||||
"FileSearchData.FileSize.MEDIUM.displayName=Medium",
|
||||
"FileSearchData.FileSize.SMALL.displayName=Small",
|
||||
"FileSearchData.FileSize.XSMALL.displayName=XSmall",
|
||||
"FileSearchData.FileSize.10PlusGb=: 10GB+",
|
||||
"FileSearchData.FileSize.5gbto10gb=: 5-10GB",
|
||||
"FileSearchData.FileSize.1gbto5gb=: 1-5GB",
|
||||
"FileSearchData.FileSize.100mbto1gb=: 100MB-1GB",
|
||||
"FileSearchData.FileSize.200PlusMb=: 200MB+",
|
||||
"FileSearchData.FileSize.50mbto200mb=: 50-200MB",
|
||||
"FileSearchData.FileSize.500kbto100mb=: 500KB-100MB",
|
||||
"FileSearchData.FileSize.1mbto50mb=: 1-50MB",
|
||||
"FileSearchData.FileSize.100kbto1mb=: 100KB-1MB",
|
||||
"FileSearchData.FileSize.16kbto100kb=: 16-100KB",
|
||||
"FileSearchData.FileSize.upTo500kb=: 0-500KB",
|
||||
"FileSearchData.FileSize.upTo16kb=: 0-16KB",})
|
||||
enum FileSize {
|
||||
XXLARGE_VIDEO(0, 10000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_VIDEO_displayName()),
|
||||
XLARGE_VIDEO(1, 5000 * BYTES_PER_MB, 10000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_VIDEO_displayName()),
|
||||
LARGE_VIDEO(2, 1000 * BYTES_PER_MB, 5000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_VIDEO_displayName()),
|
||||
MEDIUM_VIDEO(3, 100 * BYTES_PER_MB, 1000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_VIDEO_displayName()),
|
||||
SMALL_VIDEO(4, 500000, 100 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_SMALL_VIDEO_displayName()),
|
||||
XSMALL_VIDEO(5, 0, 500000, Bundle.FileSearchData_FileSize_XSMALL_VIDEO_displayName()),
|
||||
XXLARGE_IMAGE(6, 200 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_IMAGE_displayName()),
|
||||
XLARGE_IMAGE(7, 50 * BYTES_PER_MB, 200 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_IMAGE_displayName()),
|
||||
LARGE_IMAGE(8, 1 * BYTES_PER_MB, 50 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_IMAGE_displayName()),
|
||||
MEDIUM_IMAGE(9, 100000, 1 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_IMAGE_displayName()),
|
||||
SMALL_IMAGE(10, 16000, 100000, Bundle.FileSearchData_FileSize_SMALL_IMAGE_displayName()),
|
||||
XSMALL_IMAGE(11, 0, 16000, Bundle.FileSearchData_FileSize_XSMALL_IMAGE_displayName());
|
||||
XXLARGE_VIDEO(0, 10000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_displayName(), Bundle.FileSearchData_FileSize_10PlusGb()),
|
||||
XLARGE_VIDEO(1, 5000 * BYTES_PER_MB, 10000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_displayName(), Bundle.FileSearchData_FileSize_5gbto10gb()),
|
||||
LARGE_VIDEO(2, 1000 * BYTES_PER_MB, 5000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_displayName(), Bundle.FileSearchData_FileSize_1gbto5gb()),
|
||||
MEDIUM_VIDEO(3, 100 * BYTES_PER_MB, 1000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_displayName(), Bundle.FileSearchData_FileSize_100mbto1gb()),
|
||||
SMALL_VIDEO(4, 500000, 100 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_SMALL_displayName(), Bundle.FileSearchData_FileSize_500kbto100mb()),
|
||||
XSMALL_VIDEO(5, 0, 500000, Bundle.FileSearchData_FileSize_XSMALL_displayName(), Bundle.FileSearchData_FileSize_upTo500kb()),
|
||||
XXLARGE_IMAGE(6, 200 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_displayName(), Bundle.FileSearchData_FileSize_200PlusMb()),
|
||||
XLARGE_IMAGE(7, 50 * BYTES_PER_MB, 200 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_displayName(), Bundle.FileSearchData_FileSize_50mbto200mb()),
|
||||
LARGE_IMAGE(8, 1 * BYTES_PER_MB, 50 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_displayName(), Bundle.FileSearchData_FileSize_1mbto50mb()),
|
||||
MEDIUM_IMAGE(9, 100000, 1 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_displayName(), Bundle.FileSearchData_FileSize_100kbto1mb()),
|
||||
SMALL_IMAGE(10, 16000, 100000, Bundle.FileSearchData_FileSize_SMALL_displayName(), Bundle.FileSearchData_FileSize_16kbto100kb()),
|
||||
XSMALL_IMAGE(11, 0, 16000, Bundle.FileSearchData_FileSize_XSMALL_displayName(), Bundle.FileSearchData_FileSize_upTo16kb());
|
||||
|
||||
private final int ranking; // Must be unique for each value
|
||||
private final long minBytes; // Note that the size must be strictly greater than this to match
|
||||
private final long maxBytes;
|
||||
private final String displayName;
|
||||
private final String sizeGroup;
|
||||
private final String displaySize;
|
||||
final static long NO_MAXIMUM = -1;
|
||||
|
||||
FileSize(int ranking, long minB, long maxB, String displayName) {
|
||||
FileSize(int ranking, long minB, long maxB, String displayName, String displaySize) {
|
||||
this.ranking = ranking;
|
||||
this.minBytes = minB;
|
||||
if (maxB >= 0) {
|
||||
@ -166,7 +173,8 @@ final class FileSearchData {
|
||||
} else {
|
||||
this.maxBytes = NO_MAXIMUM;
|
||||
}
|
||||
this.displayName = displayName;
|
||||
this.sizeGroup = displayName;
|
||||
this.displaySize = displaySize;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,7 +254,11 @@ final class FileSearchData {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayName;
|
||||
return sizeGroup + displaySize;
|
||||
}
|
||||
|
||||
String getSizeGroup(){
|
||||
return sizeGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,11 +207,8 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.SizeFilter.desc=Files with size in range(s): {0}",
|
||||
"FileSearchFiltering.SizeFilter.or= or ",
|
||||
"# {0} - Minimum bytes",
|
||||
"# {1} - Maximum bytes",
|
||||
"FileSearchFiltering.SizeFilter.range=({0} to {1})",})
|
||||
"FileSearchFiltering.SizeFilter.desc=Size(s): {0}",
|
||||
"FileSearchFiltering.SizeFilter.or=, "})
|
||||
@Override
|
||||
String getDesc() {
|
||||
String desc = ""; // NON-NLS
|
||||
@ -219,7 +216,7 @@ class FileSearchFiltering {
|
||||
if (!desc.isEmpty()) {
|
||||
desc += Bundle.FileSearchFiltering_SizeFilter_or();
|
||||
}
|
||||
desc += Bundle.FileSearchFiltering_SizeFilter_range(size.getMinBytes(), size.getMaxBytes());
|
||||
desc += size.getSizeGroup();
|
||||
}
|
||||
desc = Bundle.FileSearchFiltering_SizeFilter_desc(desc);
|
||||
return desc;
|
||||
@ -364,10 +361,12 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.ParentFilter.desc=Files with paths matching: {0}",
|
||||
"FileSearchFiltering.ParentFilter.or= or ",
|
||||
"FileSearchFiltering.ParentFilter.desc=Paths matching: {0}",
|
||||
"FileSearchFiltering.ParentFilter.or=, ",
|
||||
"FileSearchFiltering.ParentFilter.exact=(exact match)",
|
||||
"FileSearchFiltering.ParentFilter.substring=(substring)",})
|
||||
"FileSearchFiltering.ParentFilter.substring=(substring)",
|
||||
"FileSearchFiltering.ParentFilter.included=(included)",
|
||||
"FileSearchFiltering.ParentFilter.excluded=(excluded)"})
|
||||
@Override
|
||||
String getDesc() {
|
||||
String desc = ""; // NON-NLS
|
||||
@ -380,6 +379,11 @@ class FileSearchFiltering {
|
||||
} else {
|
||||
desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_substring();
|
||||
}
|
||||
if (searchTerm.isIncluded()) {
|
||||
desc += Bundle.FileSearchFiltering_ParentFilter_included();
|
||||
} else {
|
||||
desc += Bundle.FileSearchFiltering_ParentFilter_excluded();
|
||||
}
|
||||
}
|
||||
desc = Bundle.FileSearchFiltering_ParentFilter_desc(desc);
|
||||
return desc;
|
||||
@ -417,8 +421,8 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.DataSourceFilter.desc=Files in data source(s): {0}",
|
||||
"FileSearchFiltering.DataSourceFilter.or= or ",
|
||||
"FileSearchFiltering.DataSourceFilter.desc=Data source(s): {0}",
|
||||
"FileSearchFiltering.DataSourceFilter.or=, ",
|
||||
"# {0} - Data source name",
|
||||
"# {1} - Data source ID",
|
||||
"FileSearchFiltering.DataSourceFilter.datasource={0}({1})",})
|
||||
@ -466,7 +470,7 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.KeywordListFilter.desc=Files with keywords in list(s): {0}",})
|
||||
"FileSearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0}",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
return Bundle.FileSearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames));
|
||||
@ -516,8 +520,8 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.FileTypeFilter.desc=Files with type: {0}",
|
||||
"FileSearchFiltering.FileTypeFilter.or= or ",})
|
||||
"FileSearchFiltering.FileTypeFilter.desc=Type: {0}",
|
||||
"FileSearchFiltering.FileTypeFilter.or=, ",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
String desc = "";
|
||||
@ -586,8 +590,8 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.FrequencyFilter.desc=Files with frequency: {0}",
|
||||
"FileSearchFiltering.FrequencyFilter.or= or ",})
|
||||
"FileSearchFiltering.FrequencyFilter.desc=Past occurrences: {0}",
|
||||
"FileSearchFiltering.FrequencyFilter.or=, ",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
String desc = ""; // NON-NLS
|
||||
@ -595,7 +599,7 @@ class FileSearchFiltering {
|
||||
if (!desc.isEmpty()) {
|
||||
desc += Bundle.FileSearchFiltering_FrequencyFilter_or();
|
||||
}
|
||||
desc += freq.name();
|
||||
desc += freq.toString();
|
||||
}
|
||||
return Bundle.FileSearchFiltering_FrequencyFilter_desc(desc);
|
||||
}
|
||||
@ -632,7 +636,7 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.HashSetFilter.desc=Files with hash set hits in set(s): {0}",})
|
||||
"FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0}",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
return Bundle.FileSearchFiltering_HashSetFilter_desc(concatenateSetNamesForDisplay(setNames));
|
||||
@ -670,7 +674,7 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.InterestingItemSetFilter.desc=Files with interesting item hits in set(s): {0}",})
|
||||
"FileSearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0}",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
return Bundle.FileSearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames));
|
||||
@ -708,7 +712,7 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.ObjectDetectionFilter.desc=Files with objects detected in set(s): {0}",})
|
||||
"FileSearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0}",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
return Bundle.FileSearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames));
|
||||
@ -784,7 +788,7 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - filters",
|
||||
"FileSearchFiltering.ScoreFilter.desc=Files with score(s) of : {0}",})
|
||||
"FileSearchFiltering.ScoreFilter.desc=Score(s) of : {0}",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
return Bundle.FileSearchFiltering_ScoreFilter_desc(
|
||||
@ -826,8 +830,8 @@ class FileSearchFiltering {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - tag names",
|
||||
"FileSearchFiltering.TagsFilter.desc=Files that have been tagged {0}",
|
||||
"FileSearchFiltering.TagsFilter.or= or ",})
|
||||
"FileSearchFiltering.TagsFilter.desc=Tagged {0}",
|
||||
"FileSearchFiltering.TagsFilter.or=, ",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
String desc = ""; // NON-NLS
|
||||
@ -862,7 +866,7 @@ class FileSearchFiltering {
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"FileSearchFiltering.UserCreatedFilter.desc=Files that contain EXIF data",})
|
||||
"FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
return Bundle.FileSearchFiltering_UserCreatedFilter_desc();
|
||||
@ -931,7 +935,7 @@ class FileSearchFiltering {
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"FileSearchFiltering.PreviouslyNotableFilter.desc=Files that were previously marked as notable",})
|
||||
"FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable",})
|
||||
@Override
|
||||
String getDesc() {
|
||||
return Bundle.FileSearchFiltering_PreviouslyNotableFilter_desc();
|
||||
@ -949,7 +953,7 @@ class FileSearchFiltering {
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"FileSearchFiltering.KnownFilter.desc=Files which are not known"})
|
||||
"FileSearchFiltering.KnownFilter.desc=which are not known"})
|
||||
@Override
|
||||
String getDesc() {
|
||||
return Bundle.FileSearchFiltering_KnownFilter_desc();
|
||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.discovery;
|
||||
import java.awt.Component;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.awt.ActionID;
|
||||
import org.openide.awt.ActionReference;
|
||||
import org.openide.awt.ActionReferences;
|
||||
@ -61,14 +62,16 @@ public final class OpenDiscoveryAction extends CallableSystemAction implements P
|
||||
return Case.isCaseOpen();
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"OpenDiscoveryAction.resultsIncomplete.text=Results may be incomplete"})
|
||||
@NbBundle.Messages({"OpenDiscoveryAction.resultsIncomplete.text=Discovery results may be incomplete"})
|
||||
|
||||
@Override
|
||||
public void performAction() {
|
||||
final DiscoveryDialog discDialog = DiscoveryDialog.getDiscoveryDialogInstance();
|
||||
discDialog.cancelSearch();
|
||||
discDialog.setVisible(true);
|
||||
DiscoveryUiUtils.displayErrorMessage(discDialog);
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
final DiscoveryDialog discDialog = DiscoveryDialog.getDiscoveryDialogInstance();
|
||||
discDialog.cancelSearch();
|
||||
DiscoveryUiUtils.displayErrorMessage(discDialog);
|
||||
discDialog.setVisible(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,18 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.ButtonGroup" name="includeButtonGroup">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.ButtonGroup" name="pathTypeButtonGroup">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</NonVisualComponents>
|
||||
<Properties>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
@ -143,6 +155,9 @@
|
||||
</Container>
|
||||
<Component class="javax.swing.JRadioButton" name="fullRadioButton">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="pathTypeButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.fullRadioButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
@ -152,6 +167,9 @@
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="includeRadioButton">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="includeButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.includeRadioButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
@ -161,6 +179,9 @@
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="substringRadioButton">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="pathTypeButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.substringRadioButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
@ -169,6 +190,9 @@
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="excludeRadioButton">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="includeButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.excludeRadioButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
|
@ -66,6 +66,8 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel {
|
||||
|
||||
parentCheckbox = new javax.swing.JCheckBox();
|
||||
parentLabel = new javax.swing.JLabel();
|
||||
javax.swing.ButtonGroup includeButtonGroup = new javax.swing.ButtonGroup();
|
||||
javax.swing.ButtonGroup pathTypeButtonGroup = new javax.swing.ButtonGroup();
|
||||
parentScrollPane = new javax.swing.JScrollPane();
|
||||
parentList = new javax.swing.JList<>();
|
||||
fullRadioButton = new javax.swing.JRadioButton();
|
||||
@ -106,17 +108,21 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel {
|
||||
});
|
||||
parentScrollPane.setViewportView(parentList);
|
||||
|
||||
pathTypeButtonGroup.add(fullRadioButton);
|
||||
fullRadioButton.setSelected(true);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(fullRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.fullRadioButton.text_1")); // NOI18N
|
||||
fullRadioButton.setEnabled(false);
|
||||
|
||||
includeButtonGroup.add(includeRadioButton);
|
||||
includeRadioButton.setSelected(true);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(includeRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.includeRadioButton.text_1")); // NOI18N
|
||||
includeRadioButton.setEnabled(false);
|
||||
|
||||
pathTypeButtonGroup.add(substringRadioButton);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(substringRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.substringRadioButton.text_1")); // NOI18N
|
||||
substringRadioButton.setEnabled(false);
|
||||
|
||||
includeButtonGroup.add(excludeRadioButton);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(excludeRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.excludeRadioButton.text_1")); // NOI18N
|
||||
excludeRadioButton.setEnabled(false);
|
||||
|
||||
@ -188,7 +194,7 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void parentCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_parentCheckboxActionPerformed
|
||||
// parentFilterSettings(true, true, parentCheckbox.isSelected(), null);
|
||||
configurePanel(parentCheckbox.isSelected(), null);
|
||||
}//GEN-LAST:event_parentCheckboxActionPerformed
|
||||
|
||||
private void parentListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_parentListValueChanged
|
||||
@ -235,6 +241,7 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel {
|
||||
parentCheckbox.setSelected(selected);
|
||||
if (parentCheckbox.isEnabled() && parentCheckbox.isSelected()) {
|
||||
parentScrollPane.setEnabled(true);
|
||||
parentLabel.setEnabled(true);
|
||||
includeRadioButton.setEnabled(true);
|
||||
excludeRadioButton.setEnabled(true);
|
||||
fullRadioButton.setEnabled(true);
|
||||
@ -248,6 +255,7 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel {
|
||||
}
|
||||
} else {
|
||||
parentScrollPane.setEnabled(false);
|
||||
parentLabel.setEnabled(false);
|
||||
parentList.setEnabled(false);
|
||||
includeRadioButton.setEnabled(false);
|
||||
excludeRadioButton.setEnabled(false);
|
||||
|
@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="aa" green="aa" red="aa" type="rgb"/>
|
||||
</Property>
|
||||
</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">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="detailsLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="251" max="32767" attributes="0"/>
|
||||
<Component id="showButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="hideButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="filler2" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="filler1" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="filler2" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="hideButton" max="32767" attributes="0"/>
|
||||
<Component id="showButton" max="32767" attributes="0"/>
|
||||
<Component id="detailsLabel" alignment="0" min="-2" pref="25" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="filler1" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="detailsLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ResultsSplitPaneDivider.detailsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="hideButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/discovery/arrow-down.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ResultsSplitPaneDivider.hideButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[0, 0, 0, 0]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="hideButtonActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_InitCodePost" type="java.lang.String" value="hideButton.setCursor(Cursor.getDefaultCursor());"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="showButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/discovery/arrow-up.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ResultsSplitPaneDivider.showButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[0, 0, 0, 0]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showButtonActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_InitCodePost" type="java.lang.String" value="showButton.setCursor(Cursor.getDefaultCursor());"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.Box$Filler" name="filler1">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 32767]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.Box$Filler" name="filler2">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 32767]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.awt.Cursor;
|
||||
|
||||
/**
|
||||
* Panel for separating the results list from the details area.
|
||||
*/
|
||||
final class ResultsSplitPaneDivider extends javax.swing.JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates new form LabeledSplitPaneDivider.
|
||||
*/
|
||||
ResultsSplitPaneDivider() {
|
||||
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() {
|
||||
|
||||
javax.swing.JLabel detailsLabel = new javax.swing.JLabel();
|
||||
javax.swing.JButton hideButton = new javax.swing.JButton();
|
||||
javax.swing.JButton showButton = new javax.swing.JButton();
|
||||
javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
|
||||
javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
|
||||
|
||||
setBackground(new java.awt.Color(170, 170, 170));
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(detailsLabel, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.detailsLabel.text")); // NOI18N
|
||||
detailsLabel.setFocusable(false);
|
||||
|
||||
hideButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-down.png"))); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(hideButton, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.hideButton.text")); // NOI18N
|
||||
hideButton.setBorder(null);
|
||||
hideButton.setFocusable(false);
|
||||
hideButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
|
||||
hideButton.setCursor(Cursor.getDefaultCursor());
|
||||
hideButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
hideButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
showButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-up.png"))); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(showButton, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.showButton.text")); // NOI18N
|
||||
showButton.setBorder(null);
|
||||
showButton.setFocusable(false);
|
||||
showButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
|
||||
showButton.setCursor(Cursor.getDefaultCursor());
|
||||
showButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
showButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(detailsLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 251, Short.MAX_VALUE)
|
||||
.addComponent(showButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(hideButton)
|
||||
.addContainerGap())
|
||||
.addComponent(filler2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(filler1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(filler2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(hideButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(showButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(detailsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(filler1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void showButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showButtonActionPerformed
|
||||
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(true));
|
||||
}//GEN-LAST:event_showButtonActionPerformed
|
||||
|
||||
private void hideButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hideButtonActionPerformed
|
||||
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(false));
|
||||
}//GEN-LAST:event_hideButtonActionPerformed
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -11,12 +11,17 @@
|
||||
<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"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,73,0,0,1,24"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,102,0,0,1,56"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JScrollPane" name="videoFiltersScrollPane">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[312, 102]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
@ -32,7 +37,7 @@
|
||||
<Container class="javax.swing.JPanel" name="videoFiltersPanel">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[223, 66]"/>
|
||||
<Dimension value="[310, 100]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
@ -45,7 +50,7 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||
<Component id="videoFiltersSplitPane" max="32767" attributes="0"/>
|
||||
<Component id="videoFiltersSplitPane" pref="294" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
@ -54,7 +59,7 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||
<Component id="videoFiltersSplitPane" max="32767" attributes="0"/>
|
||||
<Component id="videoFiltersSplitPane" pref="84" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
|
@ -66,7 +66,9 @@ final class VideoFilterPanel extends AbstractFiltersPanel {
|
||||
|
||||
setLayout(new java.awt.BorderLayout());
|
||||
|
||||
videoFiltersPanel.setPreferredSize(new java.awt.Dimension(223, 66));
|
||||
videoFiltersScrollPane.setPreferredSize(new java.awt.Dimension(312, 102));
|
||||
|
||||
videoFiltersPanel.setPreferredSize(new java.awt.Dimension(310, 100));
|
||||
|
||||
videoFiltersSplitPane.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(VideoFilterPanel.class, "VideoFilterPanel.videoFiltersSplitPane.border.title"))); // NOI18N
|
||||
videoFiltersSplitPane.setResizeWeight(0.5);
|
||||
@ -77,14 +79,14 @@ final class VideoFilterPanel extends AbstractFiltersPanel {
|
||||
videoFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(videoFiltersPanelLayout.createSequentialGroup()
|
||||
.addGap(8, 8, 8)
|
||||
.addComponent(videoFiltersSplitPane)
|
||||
.addComponent(videoFiltersSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 294, Short.MAX_VALUE)
|
||||
.addGap(8, 8, 8))
|
||||
);
|
||||
videoFiltersPanelLayout.setVerticalGroup(
|
||||
videoFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(videoFiltersPanelLayout.createSequentialGroup()
|
||||
.addGap(8, 8, 8)
|
||||
.addComponent(videoFiltersSplitPane)
|
||||
.addComponent(videoFiltersSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 84, Short.MAX_VALUE)
|
||||
.addGap(8, 8, 8))
|
||||
);
|
||||
|
||||
|
BIN
Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
BIN
Core/src/org/sleuthkit/autopsy/discovery/arrow-up.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/discovery/arrow-up.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
@ -78,7 +78,7 @@ final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewe
|
||||
artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID(), Color.GREEN);
|
||||
artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID(), Color.ORANGE);
|
||||
artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID(), Color.ORANGE);
|
||||
artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID(), Color.CYAN);
|
||||
artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID(), Color.MAGENTA);
|
||||
}
|
||||
|
||||
private final Waypoint dataModelWaypoint;
|
||||
|
@ -993,7 +993,7 @@ public final class HealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
String[] metricNames = {"Disk Reads: Hash calculation", "Database: getImages query", "Solr: Index chunk", "Solr: Connectivity check",
|
||||
"Correlation Engine: Notable artifact query", "Correlation Engine: Bulk insert"}; // NON-NLS
|
||||
"Central Repository: Notable artifact query", "Central Repository: Bulk insert"}; // NON-NLS
|
||||
|
||||
Random rand = new Random();
|
||||
|
||||
|
@ -471,6 +471,9 @@ public final class IngestJobSettings {
|
||||
case "Archive Extractor": //NON-NLS
|
||||
moduleNames.add("Embedded File Extractor"); //NON-NLS
|
||||
break;
|
||||
case "Correlation Engine": //NON-NLS
|
||||
moduleNames.add("Central Repository"); //NON-NLS
|
||||
break;
|
||||
default:
|
||||
moduleNames.add(name);
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implemen
|
||||
tabbedPane.setEnabled(!ingestIsRunning);
|
||||
settingsPanel.enableButtons(!ingestIsRunning);
|
||||
profilePanel.enableButtons(!ingestIsRunning);
|
||||
filterPanel.enableButtons(!ingestIsRunning);
|
||||
filterPanel.enableButtons();
|
||||
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
|
||||
|
||||
/**
|
||||
* Ingest job settings panel for the Correlation Engine module.
|
||||
* Ingest job settings panel for the Central Repository module.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
final class DataSourceIntegrityIngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
|
||||
|
@ -139,9 +139,10 @@ class SevenZipExtractor {
|
||||
}
|
||||
|
||||
SevenZipExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) throws SevenZipNativeInitializationException {
|
||||
if (!SevenZip.isInitializedSuccessfully() && (SevenZip.getLastInitializationException() == null)) {
|
||||
SevenZip.initSevenZipFromPlatformJAR();
|
||||
if (!SevenZip.isInitializedSuccessfully()) {
|
||||
throw new SevenZipNativeInitializationException("SevenZip has not been previously initialized.");
|
||||
}
|
||||
|
||||
this.context = context;
|
||||
this.fileTypeDetector = fileTypeDetector;
|
||||
this.moduleDirRelative = moduleDirRelative;
|
||||
|
@ -6,6 +6,7 @@ FilesIdentifierIngestModule.indexError.message=Failed to index interesting file
|
||||
FilesSet.rule.dateRule.toString=(modified within {0} day(s))
|
||||
FilesSetDefsPanel.bytes=Bytes
|
||||
FilesSetDefsPanel.cancelImportMsg=Cancel import
|
||||
FilesSetDefsPanel.cancelNewSetMsg=Cancel
|
||||
# {0} - file name
|
||||
FilesSetDefsPanel.exportButtonActionPerformed.fileExistPrompt=File {0} exists, overwrite?
|
||||
FilesSetDefsPanel.gigaBytes=Gigabytes
|
||||
@ -23,8 +24,12 @@ FilesSetDefsPanel.interesting.fileExtensionFilterLbl=Autopsy Interesting File Se
|
||||
FilesSetDefsPanel.interesting.importButtonAction.featureName=Interesting Files Set Import
|
||||
FilesSetDefsPanel.interesting.importOwConflict=Import Interesting files set conflict
|
||||
FilesSetDefsPanel.interesting.importSetButton.text=Import Set
|
||||
FilesSetDefsPanel.interesting.newOwConflict=Interesting files set conflict
|
||||
# {0} - FilesSet name
|
||||
FilesSetDefsPanel.interesting.overwriteSetPrompt=Interesting files set <{0}> already exists locally, overwrite?
|
||||
FilesSetDefsPanel.interesting.overwriteSetPrompt=Interesting files set "{0}" already exists locally, overwrite?
|
||||
# {0} - FilesSet name
|
||||
# {1} - New FilesSet name
|
||||
FilesSetDefsPanel.interesting.standardFileConflict=A standard interesting file set already exists with the name "{0}." Would you like to rename the set to "{1}?"
|
||||
FilesSetDefsPanel.Interesting.Title=Global Interesting Items Settings
|
||||
FilesSetDefsPanel.kiloBytes=Kilobytes
|
||||
FilesSetDefsPanel.loadError=Error loading interesting files sets from file.
|
||||
@ -32,6 +37,7 @@ FilesSetDefsPanel.megaBytes=Megabytes
|
||||
FilesSetDefsPanel.noSkipMsg=No, skip
|
||||
FilesSetDefsPanel.saveError=Error saving interesting files sets to file.
|
||||
FilesSetDefsPanel.yesOwMsg=Yes, overwrite
|
||||
FilesSetDefsPanel.yesStandardFileConflictCreate=Yes, create
|
||||
FilesSetPanel.filter.title=File Filter
|
||||
FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters...
|
||||
FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named.
|
||||
@ -140,3 +146,5 @@ FilesSetDefsPanel.ruleLabel.text=Rule Details
|
||||
FilesSetDefsPanel.pathLabel.text=Path Substring:
|
||||
FilesSetDefsPanel.mimeTypeLabel.text=MIME Type:
|
||||
FilesSetDefsPanel.fileSizeLabel.text=File Size:
|
||||
# {0} - filesSetName
|
||||
StandardInterestingFileSetsLoader.customSuffixed={0} (Custom)
|
||||
|
@ -44,6 +44,10 @@ public final class FilesSet implements Serializable {
|
||||
private final String description;
|
||||
private final boolean ignoreKnownFiles;
|
||||
private final boolean ignoreUnallocatedSpace;
|
||||
|
||||
private final boolean standardSet;
|
||||
private final int versionNumber;
|
||||
|
||||
private final Map<String, Rule> rules = new HashMap<>();
|
||||
|
||||
/**
|
||||
@ -59,9 +63,39 @@ public final class FilesSet implements Serializable {
|
||||
* but a set with no rules is the empty set.
|
||||
*/
|
||||
public FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map<String, Rule> rules) {
|
||||
this(name, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules, false, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an interesting files set.
|
||||
*
|
||||
* @param name The name of the set.
|
||||
* @param description A description of the set, may be null.
|
||||
* @param ignoreKnownFiles Whether or not to exclude known files from
|
||||
* the set.
|
||||
* @param ignoreUnallocatedSpace Whether or not to exclude unallocated space
|
||||
* from the set.
|
||||
* @param standardSet Whether or not the FilesSet is considered a
|
||||
* standard interesting set file.
|
||||
* @param versionNumber The versionNumber for the FilesSet so that
|
||||
* older versions can be replaced with newer
|
||||
* versions.
|
||||
* @param rules The rules that define the set. May be null,
|
||||
* but a set with no rules is the empty set.
|
||||
*/
|
||||
public FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map<String, Rule> rules,
|
||||
boolean standardSet, int versionNumber) {
|
||||
if ((name == null) || (name.isEmpty())) {
|
||||
throw new IllegalArgumentException("Interesting files set name cannot be null or empty");
|
||||
}
|
||||
|
||||
if (versionNumber < 0) {
|
||||
throw new IllegalArgumentException("version number must be >= 0");
|
||||
}
|
||||
|
||||
this.standardSet = standardSet;
|
||||
this.versionNumber = versionNumber;
|
||||
|
||||
this.name = name;
|
||||
this.description = (description != null ? description : "");
|
||||
this.ignoreKnownFiles = ignoreKnownFiles;
|
||||
@ -71,6 +105,22 @@ public final class FilesSet implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether or not the FilesSet is considered a standard interesting
|
||||
* set file.
|
||||
*/
|
||||
boolean isStandardSet() {
|
||||
return standardSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The versionNumber for the FilesSet so that older versions can be
|
||||
* replaced with newer versions.
|
||||
*/
|
||||
int getVersionNumber() {
|
||||
return versionNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this interesting files set.
|
||||
*
|
||||
@ -624,7 +674,6 @@ public final class FilesSet implements Serializable {
|
||||
* To ensure compatibility with existing serialized configuration
|
||||
* settings, this class cannot have a 'serialVersionUID'.
|
||||
*/
|
||||
|
||||
private final TextMatcher textMatcher;
|
||||
|
||||
/**
|
||||
@ -648,10 +697,10 @@ public final class FilesSet implements Serializable {
|
||||
AbstractTextCondition(Pattern regex) {
|
||||
this.textMatcher = new FilesSet.Rule.RegexMatcher(regex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a case-insensitive multi-value text condition.
|
||||
*
|
||||
*
|
||||
* @param values The list of values in which to look for a match.
|
||||
*/
|
||||
AbstractTextCondition(List<String> values) {
|
||||
@ -783,7 +832,6 @@ public final class FilesSet implements Serializable {
|
||||
* To ensure compatibility with existing serialized configuration
|
||||
* settings, this class cannot have a 'serialVersionUID'.
|
||||
*/
|
||||
|
||||
private final static long SECS_PER_DAY = 60 * 60 * 24;
|
||||
|
||||
private int daysIncluded;
|
||||
@ -834,8 +882,8 @@ public final class FilesSet implements Serializable {
|
||||
// AbstractFile.getFileNameExtension() returns just the
|
||||
// extension chars and not the dot.
|
||||
super(normalize(extension), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a case-insensitive file name extension condition.
|
||||
*
|
||||
@ -862,29 +910,29 @@ public final class FilesSet implements Serializable {
|
||||
public boolean passes(AbstractFile file) {
|
||||
return this.textMatches(file.getNameExtension());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strip "." from the start of extensions in the provided list.
|
||||
*
|
||||
*
|
||||
* @param extensions The list of extensions to be processed.
|
||||
*
|
||||
*
|
||||
* @return A post-processed list of extensions.
|
||||
*/
|
||||
private static List<String> normalize(List<String> extensions) {
|
||||
List<String> values = new ArrayList<>(extensions);
|
||||
|
||||
for (int i=0; i < values.size(); i++) {
|
||||
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
values.set(i, normalize(values.get(i)));
|
||||
}
|
||||
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strip "." from the start of the provided extension.
|
||||
*
|
||||
*
|
||||
* @param extension The extension to be processed.
|
||||
*
|
||||
*
|
||||
* @return A post-processed extension.
|
||||
*/
|
||||
private static String normalize(String extension) {
|
||||
|
@ -30,6 +30,7 @@ import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFileChooser;
|
||||
@ -37,12 +38,15 @@ import javax.swing.JOptionPane;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.netbeans.spi.options.OptionsPanelController;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
||||
import org.sleuthkit.autopsy.ingest.IngestProfiles;
|
||||
import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile;
|
||||
@ -100,6 +104,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
this.panelType = panelType;
|
||||
this.initComponents();
|
||||
this.customInit();
|
||||
|
||||
this.setsList.setModel(setsListModel);
|
||||
this.setsList.addListSelectionListener(new FilesSetDefsPanel.SetsListSelectionListener());
|
||||
this.rulesList.setModel(rulesListModel);
|
||||
@ -133,6 +138,13 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
this.ruleDialogTitle = "FilesSetPanel.interesting.title";
|
||||
this.ingoreUnallocCheckbox.setVisible(false);
|
||||
}
|
||||
|
||||
IngestManager.getInstance().addIngestJobEventListener((ignored) -> {
|
||||
canBeEnabled
|
||||
= !IngestManager.getInstance().isIngestRunning();
|
||||
enableButtons();
|
||||
});
|
||||
canBeEnabled = !IngestManager.getInstance().isIngestRunning();
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"FilesSetDefsPanel.Interesting.Title=Global Interesting Items Settings",
|
||||
@ -172,20 +184,23 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
}
|
||||
}
|
||||
|
||||
public void enableButtons(boolean isEnabled) {
|
||||
boolean setSelected = (FilesSetDefsPanel.this.setsList.getSelectedValue() != null);
|
||||
public void enableButtons() {
|
||||
FilesSet selectedFilesSet = this.setsList.getSelectedValue();
|
||||
boolean setSelected = (selectedFilesSet != null);
|
||||
boolean isStandardSet = (selectedFilesSet != null && selectedFilesSet.isStandardSet());
|
||||
|
||||
boolean ruleSelected = (FilesSetDefsPanel.this.rulesList.getSelectedValue() != null);
|
||||
canBeEnabled = isEnabled;
|
||||
newRuleButton.setEnabled(isEnabled);
|
||||
copySetButton.setEnabled(isEnabled && setSelected);
|
||||
newSetButton.setEnabled(isEnabled);
|
||||
editRuleButton.setEnabled(isEnabled && ruleSelected);
|
||||
editSetButton.setEnabled(isEnabled && setSelected);
|
||||
|
||||
newRuleButton.setEnabled(canBeEnabled && !isStandardSet);
|
||||
copySetButton.setEnabled(canBeEnabled && setSelected);
|
||||
newSetButton.setEnabled(canBeEnabled);
|
||||
editRuleButton.setEnabled(canBeEnabled && ruleSelected && !isStandardSet);
|
||||
editSetButton.setEnabled(canBeEnabled && setSelected && !isStandardSet);
|
||||
exportSetButton.setEnabled(setSelected);
|
||||
importSetButton.setEnabled(isEnabled);
|
||||
deleteRuleButton.setEnabled(isEnabled && ruleSelected);
|
||||
deleteSetButton.setEnabled(isEnabled && setSelected);
|
||||
ingestWarningLabel.setVisible(!isEnabled);
|
||||
importSetButton.setEnabled(canBeEnabled);
|
||||
deleteRuleButton.setEnabled(canBeEnabled && ruleSelected && !isStandardSet);
|
||||
deleteSetButton.setEnabled(canBeEnabled && setSelected && !isStandardSet);
|
||||
ingestWarningLabel.setVisible(!canBeEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -231,17 +246,11 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
* Clears the list models and resets all of the components.
|
||||
*/
|
||||
private void resetComponents() {
|
||||
this.resetRuleComponents();
|
||||
this.setsListModel.clear();
|
||||
this.setDescriptionTextArea.setText("");
|
||||
this.ignoreKnownFilesCheckbox.setSelected(true);
|
||||
this.ingoreUnallocCheckbox.setSelected(true);
|
||||
this.newSetButton.setEnabled(true && canBeEnabled);
|
||||
this.editSetButton.setEnabled(false);
|
||||
this.copySetButton.setEnabled(false);
|
||||
this.exportSetButton.setEnabled(false);
|
||||
this.importSetButton.setEnabled(true && canBeEnabled);
|
||||
this.deleteSetButton.setEnabled(false);
|
||||
this.resetRuleComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -260,9 +269,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
this.equalitySignComboBox.setSelectedIndex(2);
|
||||
this.fileSizeUnitComboBox.setSelectedIndex(1);
|
||||
this.fileSizeSpinner.setValue(0);
|
||||
this.newRuleButton.setEnabled(!this.setsListModel.isEmpty() && canBeEnabled);
|
||||
this.editRuleButton.setEnabled(false);
|
||||
this.deleteRuleButton.setEnabled(false);
|
||||
enableButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -275,12 +282,10 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
if (e.getValueIsAdjusting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FilesSetDefsPanel.this.rulesListModel.clear();
|
||||
FilesSetDefsPanel.this.resetRuleComponents();
|
||||
//enable the new button
|
||||
FilesSetDefsPanel.this.newSetButton.setEnabled(canBeEnabled);
|
||||
FilesSetDefsPanel.this.importSetButton.setEnabled(canBeEnabled);
|
||||
|
||||
|
||||
// Get the selected interesting files set and populate the set
|
||||
// components.
|
||||
FilesSet selectedSet = FilesSetDefsPanel.this.setsList.getSelectedValue();
|
||||
@ -291,11 +296,6 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
FilesSetDefsPanel.this.setDescriptionTextArea.setText(selectedSet.getDescription());
|
||||
FilesSetDefsPanel.this.ignoreKnownFilesCheckbox.setSelected(selectedSet.ignoresKnownFiles());
|
||||
FilesSetDefsPanel.this.ingoreUnallocCheckbox.setSelected(selectedSet.ingoresUnallocatedSpace());
|
||||
// Enable the copy, export, edit and delete set buttons.
|
||||
FilesSetDefsPanel.this.editSetButton.setEnabled(canBeEnabled);
|
||||
FilesSetDefsPanel.this.deleteSetButton.setEnabled(canBeEnabled);
|
||||
FilesSetDefsPanel.this.copySetButton.setEnabled(canBeEnabled);
|
||||
FilesSetDefsPanel.this.exportSetButton.setEnabled(true);
|
||||
// Populate the rule definitions list, sorted by name.
|
||||
List<FilesSet.Rule> rules = new ArrayList<>(selectedSet.getRules().values());
|
||||
Collections.sort(rules, new Comparator<FilesSet.Rule>() {
|
||||
@ -311,15 +311,8 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
if (!FilesSetDefsPanel.this.rulesListModel.isEmpty()) {
|
||||
FilesSetDefsPanel.this.rulesList.setSelectedIndex(0);
|
||||
}
|
||||
} else {
|
||||
// Disable the edit, delete, copy, and export buttons
|
||||
FilesSetDefsPanel.this.editSetButton.setEnabled(false);
|
||||
FilesSetDefsPanel.this.deleteSetButton.setEnabled(false);
|
||||
FilesSetDefsPanel.this.copySetButton.setEnabled(false);
|
||||
FilesSetDefsPanel.this.exportSetButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -389,18 +382,14 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
FilesSetDefsPanel.this.equalitySignComboBox.setSelectedIndex(2);
|
||||
FilesSetDefsPanel.this.fileSizeSpinner.setValue(0);
|
||||
}
|
||||
if (dateCondition != null){
|
||||
FilesSetDefsPanel.this.daysIncludedTextField.setText(Integer.toString(dateCondition.getDaysIncluded()));
|
||||
if (dateCondition != null) {
|
||||
FilesSetDefsPanel.this.daysIncludedTextField.setText(Integer.toString(dateCondition.getDaysIncluded()));
|
||||
} else {
|
||||
FilesSetDefsPanel.this.daysIncludedTextField.setText("");
|
||||
}
|
||||
else {
|
||||
FilesSetDefsPanel.this.daysIncludedTextField.setText("");
|
||||
}
|
||||
// Enable the new, edit and delete rule buttons.
|
||||
FilesSetDefsPanel.this.newRuleButton.setEnabled(true && canBeEnabled);
|
||||
FilesSetDefsPanel.this.editRuleButton.setEnabled(true && canBeEnabled);
|
||||
FilesSetDefsPanel.this.deleteRuleButton.setEnabled(true && canBeEnabled);
|
||||
enableButtons();
|
||||
} else {
|
||||
FilesSetDefsPanel.this.resetRuleComponents();
|
||||
resetRuleComponents();
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,15 +425,6 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
option = JOptionPane.showConfirmDialog(this, panel, NbBundle.getMessage(FilesSetPanel.class, filterDialogTitle), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
} while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition());
|
||||
|
||||
// While adding new ruleset(selectedSet == null), if rule set with same name already exists, do not add to the filesSets hashMap.
|
||||
// In case of editing an existing ruleset(selectedSet != null), following check is not performed.
|
||||
if (this.filesSets.containsKey(panel.getFilesSetName()) && shouldCreateNew) {
|
||||
MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(),
|
||||
"FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text",
|
||||
panel.getFilesSetName()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (option == JOptionPane.OK_OPTION) {
|
||||
Map<String, FilesSet.Rule> rules = new HashMap<>();
|
||||
if (selectedSet != null) {
|
||||
@ -453,10 +433,25 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
// Preserve the existing rules from the set being edited.
|
||||
rules.putAll(selectedSet.getRules());
|
||||
}
|
||||
if (shouldCreateNew) {
|
||||
this.replaceFilesSet(null, panel.getFilesSetName(), panel.getFilesSetDescription(), panel.getFileSetIgnoresKnownFiles(), panel.getFileSetIgnoresUnallocatedSpace(), rules);
|
||||
} else {
|
||||
this.replaceFilesSet(selectedSet, panel.getFilesSetName(), panel.getFilesSetDescription(), panel.getFileSetIgnoresKnownFiles(), panel.getFileSetIgnoresUnallocatedSpace(), rules);
|
||||
|
||||
FilesSet filesSet = new FilesSet(
|
||||
panel.getFilesSetName(),
|
||||
panel.getFilesSetDescription(),
|
||||
panel.getFileSetIgnoresKnownFiles(),
|
||||
panel.getFileSetIgnoresUnallocatedSpace(),
|
||||
rules
|
||||
);
|
||||
|
||||
Pair<FilesSet, Integer> result = handleConflict(filesSet, false);
|
||||
option = result.getRight();
|
||||
FilesSet toAddOrUpdate = result.getLeft();
|
||||
|
||||
if (result.getRight() == JOptionPane.OK_OPTION) {
|
||||
if (shouldCreateNew) {
|
||||
this.replaceFilesSet(null, toAddOrUpdate, null);
|
||||
} else {
|
||||
this.replaceFilesSet(selectedSet, toAddOrUpdate, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -504,7 +499,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
|
||||
// Add the new/edited files set definition, replacing any previous
|
||||
// definition with the same name and refreshing the display.
|
||||
this.replaceFilesSet(selectedSet, selectedSet.getName(), selectedSet.getDescription(), selectedSet.ignoresKnownFiles(), selectedSet.ingoresUnallocatedSpace(), rules);
|
||||
this.replaceFilesSet(selectedSet, selectedSet, rules);
|
||||
|
||||
// Select the new/edited rule. Queue it up so it happens after the
|
||||
// selection listeners react to the selection of the "new" files
|
||||
@ -520,27 +515,36 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
* owned by this panel. If there is a definition with the same name, it will
|
||||
* be replaced, so this is an add/edit operation.
|
||||
*
|
||||
* @param oldSet A set to replace, null if the new set is
|
||||
* not a replacement.
|
||||
* @param name The name of the files set.
|
||||
* @param description The description of the files set.
|
||||
* @param ignoresKnownFiles Whether or not the files set ignores
|
||||
* known files.
|
||||
* @param rules The set membership rules for the set.
|
||||
* @param processesUnallocatedSpace Whether or not this set of rules
|
||||
* processes unallocated space
|
||||
* @param oldSet A set to replace, null if the new set is not a
|
||||
* replacement.
|
||||
* @param newSet The new set of rules.
|
||||
* @param rules The set membership rules for the set. If null,
|
||||
* the rules in the new set will be used.
|
||||
*/
|
||||
void replaceFilesSet(FilesSet oldSet, String name, String description, boolean ignoresKnownFiles, boolean ignoresUnallocatedSpace, Map<String, FilesSet.Rule> rules) {
|
||||
private void replaceFilesSet(FilesSet oldSet, FilesSet newSet, Map<String, FilesSet.Rule> rules) {
|
||||
if (oldSet != null) {
|
||||
// Remove the set to be replaced from the working copy if the files
|
||||
// set definitions.
|
||||
this.filesSets.remove(oldSet.getName());
|
||||
}
|
||||
|
||||
FilesSet setToAdd = newSet;
|
||||
|
||||
// Make the new/edited set definition and add it to the working copy of
|
||||
// the files set definitions.
|
||||
FilesSet newSet = new FilesSet(name, description, ignoresKnownFiles, ignoresUnallocatedSpace, rules);
|
||||
this.filesSets.put(newSet.getName(), newSet);
|
||||
if (rules != null) {
|
||||
setToAdd = new FilesSet(
|
||||
newSet.getName(),
|
||||
newSet.getDescription(),
|
||||
newSet.ignoresKnownFiles(),
|
||||
newSet.ingoresUnallocatedSpace(),
|
||||
rules,
|
||||
newSet.isStandardSet(),
|
||||
newSet.getVersionNumber()
|
||||
);
|
||||
}
|
||||
|
||||
this.filesSets.put(setToAdd.getName(), setToAdd);
|
||||
|
||||
// Redo the list model for the files set list component, which will make
|
||||
// everything stays sorted as in the working copy tree set.
|
||||
@ -552,7 +556,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
// Select the new/edited files set definition in the set definitions
|
||||
// list. This will cause the selection listeners to repopulate the
|
||||
// subordinate components.
|
||||
this.setsList.setSelectedValue(newSet, true);
|
||||
this.setsList.setSelectedValue(setToAdd, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1058,7 +1062,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
Map<String, FilesSet.Rule> rules = new HashMap<>(oldSet.getRules());
|
||||
FilesSet.Rule selectedRule = this.rulesList.getSelectedValue();
|
||||
rules.remove(selectedRule.getUuid());
|
||||
this.replaceFilesSet(oldSet, oldSet.getName(), oldSet.getDescription(), oldSet.ignoresKnownFiles(), oldSet.ingoresUnallocatedSpace(), rules);
|
||||
this.replaceFilesSet(oldSet, oldSet, rules);
|
||||
if (!this.rulesListModel.isEmpty()) {
|
||||
this.rulesList.setSelectedIndex(0);
|
||||
} else {
|
||||
@ -1111,13 +1115,8 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
this.doFileSetsDialog(this.setsList.getSelectedValue(), true);
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}//GEN-LAST:event_copySetButtonActionPerformed
|
||||
|
||||
@NbBundle.Messages({
|
||||
"FilesSetDefsPanel.yesOwMsg=Yes, overwrite",
|
||||
"FilesSetDefsPanel.noSkipMsg=No, skip",
|
||||
"FilesSetDefsPanel.cancelImportMsg=Cancel import",
|
||||
"# {0} - FilesSet name",
|
||||
"FilesSetDefsPanel.interesting.overwriteSetPrompt=Interesting files set <{0}> already exists locally, overwrite?",
|
||||
"FilesSetDefsPanel.interesting.importOwConflict=Import Interesting files set conflict",
|
||||
"FilesSetDefsPanel.interesting.failImportMsg=Interesting files set not imported",
|
||||
"FilesSetDefsPanel.interesting.fileExtensionFilterLbl=Autopsy Interesting File Set File (xml)",
|
||||
"FilesSetDefsPanel.interesting.importButtonAction.featureName=Interesting Files Set Import"
|
||||
@ -1157,28 +1156,14 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
logger.log(Level.WARNING, "No Interesting files set definitions were read from the selected file, exception", ex);
|
||||
return;
|
||||
}
|
||||
for (FilesSet set : importedSets) {
|
||||
int choice = JOptionPane.OK_OPTION;
|
||||
if (filesSets.containsKey(set.getName())) {
|
||||
Object[] options = {NbBundle.getMessage(this.getClass(), "FilesSetDefsPanel.yesOwMsg"),
|
||||
NbBundle.getMessage(this.getClass(), "FilesSetDefsPanel.noSkipMsg"),
|
||||
NbBundle.getMessage(this.getClass(), "FilesSetDefsPanel.cancelImportMsg")};
|
||||
choice = JOptionPane.showOptionDialog(this,
|
||||
NbBundle.getMessage(this.getClass(), "FilesSetDefsPanel.interesting.overwriteSetPrompt", set.getName()),
|
||||
NbBundle.getMessage(this.getClass(), "FilesSetDefsPanel.interesting.importOwConflict"),
|
||||
JOptionPane.YES_NO_CANCEL_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
}
|
||||
if (choice == JOptionPane.OK_OPTION) {
|
||||
selectedSet = set;
|
||||
this.filesSets.put(set.getName(), set);
|
||||
} else if (choice == JOptionPane.CANCEL_OPTION) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
importedSets = importedSets
|
||||
.stream()
|
||||
.map((filesSet) -> StandardInterestingFilesSetsLoader.getAsStandardFilesSet(filesSet, false))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
FilesSet newSelected = determineFilesToImport(importedSets);
|
||||
|
||||
// Redo the list model for the files set list component
|
||||
FilesSetDefsPanel.this.setsListModel.clear();
|
||||
this.filesSets.values().forEach((set) -> {
|
||||
@ -1187,12 +1172,234 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
// Select the new/edited files set definition in the set definitions
|
||||
// list. This will cause the selection listeners to repopulate the
|
||||
// subordinate components.
|
||||
this.setsList.setSelectedValue(selectedSet, true);
|
||||
this.setsList.setSelectedValue(newSelected == null ? selectedSet : newSelected, true);
|
||||
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}
|
||||
|
||||
}//GEN-LAST:event_importSetButtonActionPerformed
|
||||
|
||||
/**
|
||||
* From the files sets that can be imported, this method rectifies any
|
||||
* conflicts that may occur.
|
||||
*
|
||||
* @param importedSets The sets to be imported.
|
||||
*
|
||||
* @return The files set to be selected or null if no items imported.
|
||||
*/
|
||||
private FilesSet determineFilesToImport(Collection<FilesSet> importedSets) {
|
||||
FilesSet selectedSet = null;
|
||||
|
||||
for (FilesSet set : importedSets) {
|
||||
Pair<FilesSet, Integer> conflictResult = handleConflict(set, true);
|
||||
int choice = conflictResult.getRight();
|
||||
FilesSet resultingFilesSet = conflictResult.getLeft();
|
||||
|
||||
if (choice == JOptionPane.OK_OPTION) {
|
||||
selectedSet = resultingFilesSet;
|
||||
this.filesSets.put(resultingFilesSet.getName(), resultingFilesSet);
|
||||
} else if (choice == JOptionPane.CANCEL_OPTION) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return selectedSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles any possible conflicts that may arise from importing a files set.
|
||||
*
|
||||
* @param set The set to potentially import.
|
||||
* @param isImport The set with which to handle the conflict is being
|
||||
* imported, otherwise this is a set to be added from the
|
||||
* "New Set" button.
|
||||
*
|
||||
* @return A pair of the files set to be imported (or null if none) and the
|
||||
* integer corresponding to the JOptionPane choice of the
|
||||
* JOptionPane.YES_NO_CANCEL option.
|
||||
*/
|
||||
private Pair<FilesSet, Integer> handleConflict(FilesSet set, boolean isImport) {
|
||||
FilesSet conflict = this.filesSets.get(set.getName());
|
||||
// if no conflict, return the files set as is with the option to proceed
|
||||
if (conflict == null) {
|
||||
return Pair.of(set, JOptionPane.OK_OPTION);
|
||||
}
|
||||
|
||||
if (isImport) {
|
||||
if (conflict.isStandardSet()) {
|
||||
return onImportStandardSetConflict(set);
|
||||
} else {
|
||||
return onImportConflict(set);
|
||||
}
|
||||
} else {
|
||||
if (conflict.isStandardSet()) {
|
||||
return onNewEditSetStandardSetConflict(set);
|
||||
} else {
|
||||
return onNewEditSetConflict(set);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* When a user imports a files set and the files set name collides with a
|
||||
* pre-existing files set (not a standard files set), the user is prompted
|
||||
* for how they would like that handled (overwrite, skip, or cancel whole
|
||||
* operation)
|
||||
*
|
||||
* @param set The set to be imported.
|
||||
*
|
||||
* @return a pair of the files set and the JOptionPane.YES_NO_CANCEL option
|
||||
*/
|
||||
@Messages({
|
||||
"FilesSetDefsPanel.yesOwMsg=Yes, overwrite",
|
||||
"FilesSetDefsPanel.noSkipMsg=No, skip",
|
||||
"FilesSetDefsPanel.cancelImportMsg=Cancel import",
|
||||
"# {0} - FilesSet name",
|
||||
"FilesSetDefsPanel.interesting.overwriteSetPrompt=Interesting files set \"{0}\" already exists locally, overwrite?",
|
||||
"FilesSetDefsPanel.interesting.importOwConflict=Import Interesting files set conflict",})
|
||||
private Pair<FilesSet, Integer> onImportConflict(FilesSet set) {
|
||||
// if there is a conflict, see if it is okay to overwrite.
|
||||
Object[] options = {
|
||||
Bundle.FilesSetDefsPanel_yesOwMsg(),
|
||||
Bundle.FilesSetDefsPanel_noSkipMsg(),
|
||||
Bundle.FilesSetDefsPanel_cancelImportMsg()
|
||||
};
|
||||
int conflictChoice = JOptionPane.showOptionDialog(this,
|
||||
Bundle.FilesSetDefsPanel_interesting_overwriteSetPrompt(set.getName()),
|
||||
Bundle.FilesSetDefsPanel_interesting_importOwConflict(),
|
||||
JOptionPane.YES_NO_CANCEL_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
if (conflictChoice == JOptionPane.OK_OPTION) {
|
||||
// if so, just return the files set to be placed in the map overwriting what is currently present.
|
||||
return Pair.of(set, conflictChoice);
|
||||
}
|
||||
|
||||
return Pair.of(null, conflictChoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a user imports a files set and the files set name collides with a
|
||||
* pre-existing standard files set, the user is prompted for how they would
|
||||
* like that handled (create files set with a " custom" suffix, skip, or
|
||||
* cancel whole operation)
|
||||
*
|
||||
* @param set The set to be imported.
|
||||
*
|
||||
* @return a pair of the files set and the JOptionPane.YES_NO_CANCEL option
|
||||
*/
|
||||
@Messages({
|
||||
"FilesSetDefsPanel.yesStandardFileConflictCreate=Yes, create",
|
||||
"# {0} - FilesSet name",
|
||||
"# {1} - New FilesSet name",
|
||||
"FilesSetDefsPanel.interesting.standardFileConflict=A standard interesting file set already exists with the name \"{0}.\" Would you like to rename your set to \"{1}?\"",})
|
||||
private Pair<FilesSet, Integer> onImportStandardSetConflict(FilesSet set) {
|
||||
// if there is a conflict and the conflicting files set is a standard files set,
|
||||
// see if allowing a custom files set is okay.
|
||||
Object[] options = {
|
||||
Bundle.FilesSetDefsPanel_yesStandardFileConflictCreate(),
|
||||
Bundle.FilesSetDefsPanel_noSkipMsg(),
|
||||
Bundle.FilesSetDefsPanel_cancelImportMsg()
|
||||
};
|
||||
|
||||
String setName = set.getName();
|
||||
String customSetName = Bundle.StandardInterestingFileSetsLoader_customSuffixed(set.getName());
|
||||
|
||||
int conflictChoice = JOptionPane.showOptionDialog(this,
|
||||
Bundle.FilesSetDefsPanel_interesting_standardFileConflict(setName, customSetName),
|
||||
Bundle.FilesSetDefsPanel_interesting_importOwConflict(),
|
||||
JOptionPane.YES_NO_CANCEL_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
// if it is okay to create with custom prefix, try again to see if there is a conflict.
|
||||
if (conflictChoice == JOptionPane.OK_OPTION) {
|
||||
return handleConflict(StandardInterestingFilesSetsLoader.getAsCustomFileSet(set), true);
|
||||
}
|
||||
|
||||
return Pair.of(null, conflictChoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a user creates a files set or edits a files set and the files set
|
||||
* name collides with a pre-existing files set (not a standard files set),
|
||||
* the user is prompted for how they would like that handled (overwrite or
|
||||
* cancel whole operation)
|
||||
*
|
||||
* @param set The set to be added.
|
||||
*
|
||||
* @return a pair of the files set and the JOptionPane.YES_NO_CANCEL option
|
||||
*/
|
||||
@Messages({
|
||||
"FilesSetDefsPanel.cancelNewSetMsg=Cancel",
|
||||
"FilesSetDefsPanel.interesting.newOwConflict=Interesting files set conflict",})
|
||||
private Pair<FilesSet, Integer> onNewEditSetConflict(FilesSet set) {
|
||||
// if there is a conflict, see if it is okay to overwrite.
|
||||
Object[] options = {
|
||||
Bundle.FilesSetDefsPanel_yesOwMsg(),
|
||||
Bundle.FilesSetDefsPanel_cancelNewSetMsg()
|
||||
};
|
||||
int conflictChoice = JOptionPane.showOptionDialog(this,
|
||||
Bundle.FilesSetDefsPanel_interesting_overwriteSetPrompt(set.getName()),
|
||||
Bundle.FilesSetDefsPanel_interesting_newOwConflict(),
|
||||
JOptionPane.OK_CANCEL_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
if (conflictChoice == JOptionPane.OK_OPTION) {
|
||||
// if so, just return the files set to be placed in the map overwriting what is currently present.
|
||||
return Pair.of(set, conflictChoice);
|
||||
}
|
||||
|
||||
return Pair.of(null, conflictChoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a user creates a files set and the files set name collides with a
|
||||
* pre-existing standard files set, the user is prompted for how they would
|
||||
* like that handled (create files set with a " custom" suffix or cancel
|
||||
* whole operation)
|
||||
*
|
||||
* @param set The set to be adedd.
|
||||
*
|
||||
* @return a pair of the files set and the JOptionPane.YES_NO_CANCEL option
|
||||
*/
|
||||
private Pair<FilesSet, Integer> onNewEditSetStandardSetConflict(FilesSet set) {
|
||||
// if there is a conflict and the conflicting files set is a standard files set,
|
||||
// see if allowing a custom files set is okay.
|
||||
Object[] options = {
|
||||
Bundle.FilesSetDefsPanel_yesStandardFileConflictCreate(),
|
||||
Bundle.FilesSetDefsPanel_cancelNewSetMsg()
|
||||
};
|
||||
|
||||
String setName = set.getName();
|
||||
String customSetName = Bundle.StandardInterestingFileSetsLoader_customSuffixed(set.getName());
|
||||
|
||||
int conflictChoice = JOptionPane.showOptionDialog(this,
|
||||
Bundle.FilesSetDefsPanel_interesting_standardFileConflict(setName, customSetName),
|
||||
Bundle.FilesSetDefsPanel_interesting_newOwConflict(),
|
||||
JOptionPane.OK_CANCEL_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
// if it is okay to create with custom prefix, try again to see if there is a conflict.
|
||||
if (conflictChoice == JOptionPane.OK_OPTION) {
|
||||
return handleConflict(StandardInterestingFilesSetsLoader.getAsCustomFileSet(set), false);
|
||||
}
|
||||
|
||||
return Pair.of(null, conflictChoice);
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"FilesSetDefsPanel.interesting.exportButtonAction.featureName=Interesting Files Set Export",
|
||||
"# {0} - file name",
|
||||
"FilesSetDefsPanel.exportButtonActionPerformed.fileExistPrompt=File {0} exists, overwrite?",
|
||||
|
@ -26,6 +26,7 @@ import java.io.Serializable;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -35,6 +36,7 @@ import java.util.regex.PatternSyntaxException;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.util.io.NbObjectInputStream;
|
||||
import org.openide.util.io.NbObjectOutputStream;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -46,9 +48,13 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.MetaTypeCond
|
||||
import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.MimeTypeCondition;
|
||||
import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.ParentPathCondition;
|
||||
import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.DateCondition;
|
||||
import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager.FilesSetsManagerException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class InterestingItemsFilesSetSettings implements Serializable {
|
||||
|
||||
@ -79,6 +85,8 @@ class InterestingItemsFilesSetSettings implements Serializable {
|
||||
private static final Logger logger = Logger.getLogger(InterestingItemsFilesSetSettings.class.getName());
|
||||
private static final String TYPE_FILTER_ATTR = "typeFilter"; //NON-NLS
|
||||
private static final String EXTENSION_RULE_TAG = "EXTENSION"; //NON-NLS
|
||||
private static final String STANDARD_SET = "standardSet";
|
||||
private static final String VERSION_NUMBER = "versionNumber";
|
||||
|
||||
private Map<String, FilesSet> filesSets;
|
||||
|
||||
@ -378,6 +386,25 @@ class InterestingItemsFilesSetSettings implements Serializable {
|
||||
if (!ignoreUnallocated.isEmpty()) {
|
||||
ignoreUnallocatedSpace = Boolean.parseBoolean(ignoreUnallocated);
|
||||
}
|
||||
|
||||
String isStandardSetString = setElem.getAttribute(STANDARD_SET);
|
||||
boolean isStandardSet = false;
|
||||
if (StringUtils.isNotBlank(isStandardSetString)) {
|
||||
isStandardSet = Boolean.parseBoolean(isStandardSetString);
|
||||
}
|
||||
|
||||
String versionNumberString = setElem.getAttribute(VERSION_NUMBER);
|
||||
int versionNumber = 0;
|
||||
if (StringUtils.isNotBlank(versionNumberString)) {
|
||||
try {
|
||||
versionNumber = Integer.parseInt(versionNumberString);
|
||||
} catch (NumberFormatException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
String.format("Unable to parse version number for files set named: %s with provided input: '%s'", setName, versionNumberString),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the set membership rules, if any.
|
||||
Map<String, FilesSet.Rule> rules = new HashMap<>();
|
||||
NodeList allRuleElems = setElem.getChildNodes();
|
||||
@ -401,7 +428,7 @@ class InterestingItemsFilesSetSettings implements Serializable {
|
||||
// Make the files set. Note that degenerate sets with no rules are
|
||||
// allowed to facilitate the separation of set definition and rule
|
||||
// definitions. A set without rules is simply the empty set.
|
||||
FilesSet set = new FilesSet(setName, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules);
|
||||
FilesSet set = new FilesSet(setName, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules, isStandardSet, versionNumber);
|
||||
filesSets.put(set.getName(), set);
|
||||
}
|
||||
// Note: This method takes a file path to support the possibility of
|
||||
@ -446,31 +473,51 @@ class InterestingItemsFilesSetSettings implements Serializable {
|
||||
* org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager.FilesSetsManagerException
|
||||
*/
|
||||
static Map<String, FilesSet> readDefinitionsXML(File xmlFile) throws FilesSetsManager.FilesSetsManagerException {
|
||||
Map<String, FilesSet> filesSets = new HashMap<>();
|
||||
if (!xmlFile.exists()) {
|
||||
return filesSets;
|
||||
return new HashMap<>();
|
||||
}
|
||||
// Check if the file can be read.
|
||||
if (!xmlFile.canRead()) {
|
||||
logger.log(Level.SEVERE, "FilesSet definition file at {0} exists, but cannot be read", xmlFile.getPath()); // NON-NLS
|
||||
return filesSets;
|
||||
return new HashMap<>();
|
||||
}
|
||||
// Parse the XML in the file.
|
||||
|
||||
Document doc = XMLUtil.loadDoc(InterestingItemsFilesSetSettings.class, xmlFile.getPath());
|
||||
return readDefinitionsXML(doc, xmlFile.getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an XML file and returns a map of fileSets. Allows for legacy XML
|
||||
* support as well as importing of file sets to XMLs.
|
||||
*
|
||||
*
|
||||
* @param doc The xml document.
|
||||
*
|
||||
* @return fileSets - a Map<String, Filesset> of the definition(s) found in
|
||||
* the xml file for logging purposes (can provide null).
|
||||
*
|
||||
* @throws
|
||||
* org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager.FilesSetsManagerException
|
||||
*/
|
||||
static Map<String, FilesSet> readDefinitionsXML(Document doc, String resourceName) throws FilesSetsManager.FilesSetsManagerException {
|
||||
// Parse the XML in the file.
|
||||
Map<String, FilesSet> filesSets = new HashMap<>();
|
||||
|
||||
if (doc == null) {
|
||||
logger.log(Level.SEVERE, "FilesSet definition file at {0}", xmlFile.getPath()); // NON-NLS
|
||||
logger.log(Level.SEVERE, "FilesSet definition file at {0}", resourceName); // NON-NLS
|
||||
return filesSets;
|
||||
}
|
||||
// Get the root element.
|
||||
Element root = doc.getDocumentElement();
|
||||
if (root == null) {
|
||||
logger.log(Level.SEVERE, "Failed to get root {0} element tag of FilesSet definition file at {1}", new Object[]{FILE_SETS_ROOT_TAG, xmlFile.getPath()}); // NON-NLS
|
||||
logger.log(Level.SEVERE, "Failed to get root {0} element tag of FilesSet definition file at {1}",
|
||||
new Object[]{FILE_SETS_ROOT_TAG, resourceName}); // NON-NLS
|
||||
return filesSets;
|
||||
}
|
||||
// Read in the files set definitions.
|
||||
NodeList setElems = root.getElementsByTagName(FILE_SET_TAG);
|
||||
for (int i = 0; i < setElems.getLength(); ++i) {
|
||||
readFilesSet((Element) setElems.item(i), filesSets, xmlFile.getPath());
|
||||
readFilesSet((Element) setElems.item(i), filesSets, resourceName);
|
||||
}
|
||||
return filesSets;
|
||||
}
|
||||
@ -493,6 +540,34 @@ class InterestingItemsFilesSetSettings implements Serializable {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates an alphabetically sorted list based on the provided collection and Function to retrieve a string field from each object.
|
||||
* @param itemsToSort The items to be sorted into the newly generated list.
|
||||
* @param getName The method to retrieve the given field from the object.
|
||||
* @return The newly generated list sorted alphabetically by the given field.
|
||||
*/
|
||||
private static <T> List<T> sortOnField(Collection<T> itemsToSort, final Function<T, String> getName) {
|
||||
Comparator<T> comparator = (a,b) -> {
|
||||
String aName = getName.apply(a);
|
||||
String bName = getName.apply(b);
|
||||
if (aName == null) {
|
||||
aName = "";
|
||||
}
|
||||
|
||||
if (bName == null) {
|
||||
bName = "";
|
||||
}
|
||||
|
||||
return aName.compareToIgnoreCase(bName);
|
||||
};
|
||||
|
||||
return itemsToSort.stream()
|
||||
.sorted(comparator)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write the FilesSets to a file as an xml.
|
||||
@ -512,15 +587,27 @@ class InterestingItemsFilesSetSettings implements Serializable {
|
||||
Element rootElement = doc.createElement(FILE_SETS_ROOT_TAG);
|
||||
doc.appendChild(rootElement);
|
||||
// Add the interesting files sets to the document.
|
||||
for (FilesSet set : interestingFilesSets) {
|
||||
|
||||
List<FilesSet> sortedFilesSets = sortOnField(
|
||||
interestingFilesSets,
|
||||
filesSet -> filesSet == null ? null : filesSet.getName());
|
||||
|
||||
for (FilesSet set : sortedFilesSets) {
|
||||
// Add the files set element and its attributes.
|
||||
Element setElement = doc.createElement(FILE_SET_TAG);
|
||||
setElement.setAttribute(NAME_ATTR, set.getName());
|
||||
setElement.setAttribute(DESC_ATTR, set.getDescription());
|
||||
setElement.setAttribute(IGNORE_KNOWN_FILES_ATTR, Boolean.toString(set.ignoresKnownFiles()));
|
||||
setElement.setAttribute(STANDARD_SET, Boolean.toString(set.isStandardSet()));
|
||||
setElement.setAttribute(VERSION_NUMBER, Integer.toString(set.getVersionNumber()));
|
||||
// Add the child elements for the set membership rules.
|
||||
// All conditions of a rule will be written as a single element in the xml
|
||||
for (FilesSet.Rule rule : set.getRules().values()) {
|
||||
|
||||
List<FilesSet.Rule> sortedRules = sortOnField(
|
||||
set.getRules().values(),
|
||||
rule -> rule == null ? null : rule.getName());
|
||||
|
||||
for (FilesSet.Rule rule : sortedRules) {
|
||||
// Add a rule element with the appropriate name Condition
|
||||
// type tag.
|
||||
Element ruleElement;
|
||||
@ -577,13 +664,13 @@ class InterestingItemsFilesSetSettings implements Serializable {
|
||||
ruleElement.setAttribute(FS_SIZE_ATTR, Integer.toString(sizeCondition.getSizeValue()));
|
||||
ruleElement.setAttribute(FS_UNITS_ATTR, sizeCondition.getUnit().getName());
|
||||
}
|
||||
|
||||
//Add the optional date condition
|
||||
|
||||
//Add the optional date condition
|
||||
DateCondition dateCondition = rule.getDateCondition();
|
||||
if (dateCondition != null) {
|
||||
ruleElement.setAttribute(DAYS_INCLUDED_ATTR, Integer.toString(dateCondition.getDaysIncluded()));
|
||||
}
|
||||
|
||||
|
||||
setElement.appendChild(ruleElement);
|
||||
}
|
||||
rootElement.appendChild(setElement);
|
||||
|
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.modules.interestingitems;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.modules.InstalledFileLocator;
|
||||
import org.openide.modules.OnStart;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* When the interesting items module loads, this runnable loads standard
|
||||
* interesting file set rules.
|
||||
*/
|
||||
@OnStart
|
||||
public class StandardInterestingFilesSetsLoader implements Runnable {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(StandardInterestingFilesSetsLoader.class.getName());
|
||||
|
||||
private static final String CONFIG_DIR = "InterestingFileSetRules";
|
||||
|
||||
private static final FilenameFilter DEFAULT_XML_FILTER = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".xml");
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Map<String, FilesSet> standardInterestingFileSets = readStandardFileXML();
|
||||
|
||||
// Call FilesSetManager.getInterestingFilesSets() to get a Map<String, FilesSet> of the existing rule sets.
|
||||
Map<String, FilesSet> userConfiguredSettings = null;
|
||||
try {
|
||||
userConfiguredSettings = FilesSetsManager.getInstance().getInterestingFilesSets();
|
||||
} catch (FilesSetsManager.FilesSetsManagerException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to properly read user-configured interesting files sets.", ex);
|
||||
}
|
||||
|
||||
if (userConfiguredSettings == null) {
|
||||
userConfiguredSettings = new HashMap<>();
|
||||
}
|
||||
|
||||
// Add each FilesSet read from the standard rules set XML files that is missing from the Map to the Map.
|
||||
copyOnNewer(standardInterestingFileSets, userConfiguredSettings, true);
|
||||
|
||||
try {
|
||||
// Call FilesSetManager.setInterestingFilesSets with the updated Map.
|
||||
FilesSetsManager.getInstance().setInterestingFilesSets(userConfiguredSettings);
|
||||
} catch (FilesSetsManager.FilesSetsManagerException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to write updated configuration for interesting files sets to config directory.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads xml definitions for each file found in the standard interesting
|
||||
* file set config directory and marks the files set as a standard
|
||||
* interesting file if it isn't already.
|
||||
*
|
||||
* @return The mapping of files set keys to the file sets.
|
||||
*/
|
||||
private static Map<String, FilesSet> readStandardFileXML() {
|
||||
Map<String, FilesSet> standardInterestingFileSets = new HashMap<>();
|
||||
|
||||
File[] standardFileSets = InstalledFileLocator.getDefault()
|
||||
.locate(CONFIG_DIR, StandardInterestingFilesSetsLoader.class.getPackage().getName(), false)
|
||||
.listFiles(DEFAULT_XML_FILTER);
|
||||
|
||||
for (File standardFileSetsFile : standardFileSets) { //NON-NLS
|
||||
try {
|
||||
Map<String, FilesSet> thisFilesSet = InterestingItemsFilesSetSettings.readDefinitionsXML(standardFileSetsFile);
|
||||
|
||||
// ensure that read resources are standard sets
|
||||
thisFilesSet = thisFilesSet.values()
|
||||
.stream()
|
||||
.map((filesSet) -> getAsStandardFilesSet(filesSet, true))
|
||||
.collect(Collectors.toMap(FilesSet::getName, Function.identity()));
|
||||
|
||||
copyOnNewer(thisFilesSet, standardInterestingFileSets);
|
||||
} catch (FilesSetsManager.FilesSetsManagerException ex) {
|
||||
LOGGER.log(Level.WARNING, String.format("There was a problem importing the standard interesting file set at: %s.",
|
||||
standardFileSetsFile.getAbsoluteFile()), ex);
|
||||
}
|
||||
}
|
||||
return standardInterestingFileSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a copy of the Files Set forcing the standard file set flag to what
|
||||
* is provided as a parameter.
|
||||
*
|
||||
* @param origFilesSet The fileset to get a copy of.
|
||||
* @param standardFilesSet Whether or not the copy should be a standard
|
||||
* files set.
|
||||
*
|
||||
* @return The copy.
|
||||
*/
|
||||
static FilesSet getAsStandardFilesSet(FilesSet origFilesSet, boolean standardFilesSet) {
|
||||
return new FilesSet(
|
||||
origFilesSet.getName(),
|
||||
origFilesSet.getDescription(),
|
||||
origFilesSet.ignoresKnownFiles(),
|
||||
origFilesSet.ingoresUnallocatedSpace(),
|
||||
origFilesSet.getRules(),
|
||||
standardFilesSet,
|
||||
origFilesSet.getVersionNumber()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the entries in the src map to the destination map if the src item
|
||||
* has a newer version than what is in dest or no equivalent entry exists
|
||||
* within the dest map.
|
||||
*
|
||||
* @param src The source map.
|
||||
* @param dest The destination map.
|
||||
*/
|
||||
private static void copyOnNewer(Map<String, FilesSet> src, Map<String, FilesSet> dest) {
|
||||
copyOnNewer(src, dest, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the entries in the src map to the destination map if the src item
|
||||
* has a newer version than what is in dest or no equivalent entry exists
|
||||
* within the dest map.
|
||||
*
|
||||
* @param src The source map.
|
||||
* @param dest The destination map.
|
||||
* @param appendCustom On conflict, if one of the items is readonly and one
|
||||
* is not, this flag can be set so the item that is not
|
||||
* readonly will have " (custom)" appended.
|
||||
*/
|
||||
private static void copyOnNewer(Map<String, FilesSet> src, Map<String, FilesSet> dest, boolean appendCustom) {
|
||||
for (Map.Entry<String, FilesSet> srcEntry : src.entrySet()) {
|
||||
String key = srcEntry.getKey();
|
||||
FilesSet srcFileSet = srcEntry.getValue();
|
||||
FilesSet destFileSet = dest.get(key);
|
||||
if (destFileSet != null) {
|
||||
// If and only if there is a naming conflict with a user-defined rule set, append “(Custom)”
|
||||
// to the user-defined rule set and add it back to the Map.
|
||||
if (appendCustom && srcFileSet.isStandardSet() != destFileSet.isStandardSet()) {
|
||||
if (srcFileSet.isStandardSet()) {
|
||||
addCustomFile(dest, destFileSet);
|
||||
dest.put(key, srcFileSet);
|
||||
} else {
|
||||
addCustomFile(dest, srcFileSet);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace each FilesSet read from the standard rules set XML files that has a newer version
|
||||
// number than the corresponding FilesSet in the Map with the updated FilesSet.
|
||||
if (destFileSet.getVersionNumber() >= srcEntry.getValue().getVersionNumber()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
dest.put(srcEntry.getKey(), srcEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the destination map where the name will be the same as
|
||||
* the key with " (custom)" appended.
|
||||
*
|
||||
* @param dest The destination map.
|
||||
* @param srcFilesSet The FilesSet to append as custom. A non-readonly
|
||||
* filesset must be provided.
|
||||
*/
|
||||
private static void addCustomFile(Map<String, FilesSet> dest, FilesSet srcFilesSet) {
|
||||
if (srcFilesSet.isStandardSet()) {
|
||||
LOGGER.log(Level.SEVERE, "An attempt to create a custom file that was a standard set.");
|
||||
return;
|
||||
}
|
||||
|
||||
FilesSet srcToAdd = srcFilesSet;
|
||||
|
||||
do {
|
||||
srcToAdd = getAsCustomFileSet(srcToAdd);
|
||||
} while (dest.containsKey(srcToAdd.getName()));
|
||||
|
||||
dest.put(srcToAdd.getName(), srcToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the FilesSet as a non-standard files set with " (custom)"
|
||||
* appended.
|
||||
*
|
||||
* @param srcFilesSet The files set.
|
||||
*
|
||||
* @return The altered copy.
|
||||
*/
|
||||
@Messages({
|
||||
"# {0} - filesSetName",
|
||||
"StandardInterestingFileSetsLoader.customSuffixed={0} (Custom)"
|
||||
})
|
||||
static FilesSet getAsCustomFileSet(FilesSet srcFilesSet) {
|
||||
String customKey = Bundle.StandardInterestingFileSetsLoader_customSuffixed(srcFilesSet.getName());
|
||||
return new FilesSet(
|
||||
customKey,
|
||||
srcFilesSet.getDescription(),
|
||||
srcFilesSet.ignoresKnownFiles(),
|
||||
srcFilesSet.ingoresUnallocatedSpace(),
|
||||
srcFilesSet.getRules(),
|
||||
false,
|
||||
srcFilesSet.getVersionNumber()
|
||||
);
|
||||
}
|
||||
}
|
@ -81,6 +81,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
|
||||
static final boolean DEFAULT_CONFIG_KEEP_CORRUPTED_FILES = false;
|
||||
|
||||
private static final String PHOTOREC_DIRECTORY = "photorec_exec"; //NON-NLS
|
||||
private static final String PHOTOREC_SUBDIRECTORY = "bin"; //NON-NLS
|
||||
private static final String PHOTOREC_EXECUTABLE = "photorec_win.exe"; //NON-NLS
|
||||
private static final String PHOTOREC_LINUX_EXECUTABLE = "photorec";
|
||||
private static final String PHOTOREC_RESULTS_BASE = "results"; //NON-NLS
|
||||
@ -454,6 +455,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds and returns the path to the executable, if able.
|
||||
*
|
||||
@ -468,7 +470,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
|
||||
Path execName;
|
||||
String photorec_linux_directory = "/usr/bin";
|
||||
if (PlatformUtil.isWindowsOS()) {
|
||||
execName = Paths.get(PHOTOREC_DIRECTORY, PHOTOREC_EXECUTABLE);
|
||||
execName = Paths.get(PHOTOREC_DIRECTORY, PHOTOREC_SUBDIRECTORY, PHOTOREC_EXECUTABLE);
|
||||
exeFile = InstalledFileLocator.getDefault().locate(execName.toString(), PhotoRecCarverFileIngestModule.class.getPackage().getName(), false);
|
||||
} else {
|
||||
File usrBin = new File("/usr/bin/photorec");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user