Merge branch 'develop' of github.com:sleuthkit/autopsy into 6412-updatedDialogs

This commit is contained in:
Greg DiCristofaro 2020-06-24 10:15:18 -04:00
commit 2b144413c6
32 changed files with 1897 additions and 1016 deletions

View File

@ -53,7 +53,7 @@ public interface CentralRepository {
case SQLITE:
return SqliteCentralRepo.getInstance();
default:
return null;
throw new CentralRepoException("Failed to get CentralRepository instance, Central Repositiory is not enabled.");
}
}

View File

@ -329,7 +329,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);
}
}

View File

@ -121,22 +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"));
Instant instant = Instant.now();
@ -151,7 +147,7 @@ public class PersonaAccount {
+ currentExaminer.getId()
+ ")";
CentralRepository.getInstance().executeInsertSQL(insertClause);
cr.executeInsertSQL(insertClause);
String queryClause = PERSONA_ACCOUNTS_QUERY_CLAUSE
+ "WHERE persona_id = " + persona.getId()
@ -249,19 +245,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();
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
cr.executeSelectSQL(queryClause, queryCallback);
return queryCallback.getPersonaAccountsList();
}
return new ArrayList<>();
return queryCallback.getPersonaAccountsList();
}
/**
@ -279,16 +269,10 @@ public class PersonaAccount {
+ " WHERE persona_accounts.account_id = " + accountId
+ " AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId();
CentralRepository cr = CentralRepository.getInstance();
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
if (cr != null) {
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
cr.executeSelectSQL(queryClause, queryCallback);
return queryCallback.getPersonaAccountsList();
}
return new ArrayList<>();
return queryCallback.getPersonaAccountsList();
}
/**
@ -308,15 +292,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();
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
return queryCallback.getPersonaAccountsList();
}
return new ArrayList<>();
return queryCallback.getPersonaAccountsList();
}
/**
@ -335,14 +314,10 @@ 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();
}
PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback();
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
return queryCallback.getPersonaAccountsList();
return new ArrayList<>();
}
/**
@ -351,36 +326,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);
CentralRepository.getInstance().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);
CentralRepository.getInstance().executeUpdateSQL(updateClause);
}
/**
@ -418,28 +381,25 @@ 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();
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;
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();
cr.executeSelectSQL(queryClause, queryCallback);
AccountsForPersonaQueryCallback queryCallback = new AccountsForPersonaQueryCallback();
CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback);
return queryCallback.getAccountsList();
}
return queryCallback.getAccountsList();
return new ArrayList<>();
}
}

View File

@ -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,19 @@ 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

View File

@ -3,10 +3,13 @@ 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_dup_msg=An account with this identifier and type already exists.
CreatePersonaAccountDialog_dup_Title=Account creation failure
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 +26,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 +46,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 +79,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 +103,26 @@ 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_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

View File

@ -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

View File

@ -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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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&lt;&gt;(getAllAccountTypes())" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType&gt;"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okBtnActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,270 @@
/*
* 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);
}
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 access central repository", e);
JOptionPane.showMessageDialog(this,
Bundle.PersonaAccountDialog_get_types_exception_Title(),
Bundle.PersonaAccountDialog_get_types_exception_msg(),
JOptionPane.ERROR_MESSAGE);
}
return ret;
}
@Messages({
"CreatePersonaAccountDialog_dup_Title=Account creation failure",
"CreatePersonaAccountDialog_dup_msg=An account with this identifier and type already exists.",})
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) {
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
}

View File

@ -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();
}

View File

@ -27,9 +27,7 @@
</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,7 +44,7 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jSplitPane1" alignment="0" pref="692" max="32767" attributes="0"/>
<Component id="jSplitPane1" alignment="0" pref="794" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@ -70,9 +68,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">
<Component id="jSeparator1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="createBtn" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -89,6 +88,10 @@
<EmptySpace max="32767" attributes="0"/>
<Component id="searchBtn" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="createAccountBtn" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -106,7 +109,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="457" 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 +117,10 @@
<Component id="deleteBtn" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSeparator1" 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 +129,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, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.searchField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -133,7 +140,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, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.searchNameRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -143,7 +150,7 @@
<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, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.searchAccountRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -157,20 +164,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, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.resultsTable.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.resultsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.resultsTable.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Title>
<Editor/>
<Renderer/>
@ -187,36 +194,48 @@
<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="PersonaManagerTopComponent.searchBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.searchBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="editBtn">
<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.editBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.createAccountBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="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.deleteBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonasTopComponent.createBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
</AuxValues>
</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="PersonasTopComponent.editBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JSeparator" name="jSeparator1">
</Component>
</SubComponents>
</Container>
<Component class="org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel" name="detailsPanel">

View File

@ -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;
}
@ -262,39 +271,43 @@ public final class PersonaManagerTopComponent extends TopComponent {
resultsPane = new javax.swing.JScrollPane();
resultsTable = new javax.swing.JTable();
searchBtn = new javax.swing.JButton();
editBtn = new javax.swing.JButton();
createAccountBtn = new javax.swing.JButton();
createBtn = new javax.swing.JButton();
editBtn = new javax.swing.JButton();
deleteBtn = new javax.swing.JButton();
jSeparator1 = new javax.swing.JSeparator();
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
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
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(searchBtn, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.searchBtn.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(editBtn, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.editBtn.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(createAccountBtn, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.createAccountBtn.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(createBtn, org.openide.util.NbBundle.getMessage(PersonasTopComponent.class, "PersonasTopComponent.createBtn.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);
javax.swing.GroupLayout searchPanelLayout = new javax.swing.GroupLayout(searchPanel);
@ -304,6 +317,7 @@ public final class PersonaManagerTopComponent extends TopComponent {
.addGroup(searchPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSeparator1)
.addGroup(searchPanelLayout.createSequentialGroup()
.addComponent(createBtn)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -317,7 +331,10 @@ 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()
.addComponent(createAccountBtn)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
searchPanelLayout.setVerticalGroup(
@ -331,12 +348,16 @@ 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, 457, 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(jSeparator1, 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())
);
@ -347,7 +368,7 @@ public final class PersonaManagerTopComponent extends TopComponent {
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 692, Short.MAX_VALUE)
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 794, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -356,10 +377,12 @@ public final class PersonaManagerTopComponent extends TopComponent {
}// </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.JButton deleteBtn;
private org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel detailsPanel;
private javax.swing.JButton editBtn;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JScrollPane resultsPane;
private javax.swing.JTable resultsTable;

View File

@ -981,4 +981,3 @@ CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1
CallLogArtifactViewer.localAccountPersonaButton.text=jButton1
ContactArtifactViewer.personasLabel.text=Personas
MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts
ContactArtifactViewer.contactImage.text=

View File

@ -35,15 +35,23 @@ 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
CallLogArtifactViewer_heading_metadata=Metadata
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_missing_account_label=Missing Account:
ContactArtifactViewer_persona_account_justification=Account found in Contact artifact
ContactArtifactViewer_persona_button_new=Create

View File

@ -35,6 +35,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 +67,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 +93,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 +106,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 +291,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 +300,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 +314,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 +325,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 +336,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 +406,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 +464,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 +475,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 +490,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;
}

View File

@ -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;
}
/**

View File

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<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"/>
@ -11,217 +14,8 @@
<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"/>
<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"/>
<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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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>

View File

@ -1,4 +1,4 @@
/**
/*
* Autopsy Forensic Browser
*
* Copyright 2020 Basis Technology Corp.
@ -22,116 +22,138 @@ 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.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({
"# {0} - Persona count",
"PersonaDisplayTask_persona_count_suffix=(1 of {0})"
})
class PersonaSearchAndDisplayTask extends SwingWorker<Collection<Persona>, Void> {
private final static Logger logger = Logger.getLogger(PersonaAccountFetcher.class.getName());
private final static Logger logger = Logger.getLogger(PersonaSearchAndDisplayTask.class.getName());
private final Component parentComponent;
private final AccountPersonaSearcherData personaSearcherData;
private final BlackboardArtifact artifact;
private final List<AccountPersonaSearcherData> personaSearchDataList;
private final Component parentComponent;
PersonaSearchAndDisplayTask(Component parentComponent, AccountPersonaSearcherData personaSearcherData) {
this.parentComponent = parentComponent;
this.personaSearcherData = personaSearcherData;
}
/**
* 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 Collection<Persona> doInBackground() throws Exception {
@Override
protected Map<String, Collection<Persona>> doInBackground() throws Exception {
Map<String, Collection<Persona>> accountMap = new HashMap<>();
Collection<Persona> personas = new ArrayList<>();
CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
if (CentralRepository.isEnabled()) {
Collection<CentralRepoAccount> accountCandidates
= CentralRepoAccount.getAccountsWithIdentifier(personaSearcherData.getAccountIdentifer());
List<Account> relatedAccountList = commManager.getAccountsRelatedToArtifact(artifact);
if (accountCandidates.isEmpty() == false) {
CentralRepoAccount account = accountCandidates.iterator().next();
for (Account account : relatedAccountList) {
// get personas for the account
Collection<PersonaAccount> personaAccountsList = PersonaAccount.getPersonaAccountsForAccount(account.getId());
personas = personaAccountsList.stream().map(PersonaAccount::getPersona)
.collect(Collectors.toList());
}
}
return personas;
}
@Override
protected void done() {
Collection<Persona> personas;
try {
personas = super.get();
if (this.isCancelled()) {
return;
}
//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
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();
}
/**
* 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;
if (personas == null || 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);
}
/**
* Action listener for Create persona button.
*/
@ -177,7 +199,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 +239,5 @@ class PersonaSearchAndDisplayTask extends SwingWorker<Collection<Persona>, Void>
// nothing to do
}
}
}

View File

@ -290,6 +290,62 @@ public final class ContentUtils {
return totalRead;
}
/**
* Reads all the data from any content object and writes (extracts) it to a
* file, using a cancellation check instead of a Future object method.
*
* @param content Any content object.
* @param outputFile Will be created if it doesn't exist, and overwritten
* if it does
* @param cancelCheck A function used to check if the file write process
* should be terminated.
* @param startingOffset the starting offset to start reading the file
* @param endingOffset the ending offset to read of the file to write
*
* @return number of bytes extracted
*
* @throws IOException if file could not be written
*/
public static long writeToFile(Content content, java.io.File outputFile,
Supplier<Boolean> cancelCheck, long startingOffset, long endingOffset) throws IOException {
InputStream in = new ReadContentInputStream(content);
long totalRead = 0;
try (FileOutputStream out = new FileOutputStream(outputFile, false)) {
long offsetSkipped = in.skip(startingOffset);
if (offsetSkipped != startingOffset) {
in.close();
throw new IOException(String.format("Skipping file to starting offset {0} was not successful only skipped to offset {1}.", startingOffset, offsetSkipped));
}
byte[] buffer = new byte[TO_FILE_BUFFER_SIZE];
int len = in.read(buffer);
long writeFileLength = endingOffset - startingOffset;
writeFileLength = writeFileLength - TO_FILE_BUFFER_SIZE;
while (len != -1 && writeFileLength != 0) {
out.write(buffer, 0, len);
totalRead += len;
if (cancelCheck.get()) {
break;
}
if (writeFileLength > TO_FILE_BUFFER_SIZE) {
len = in.read(buffer);
writeFileLength = writeFileLength - TO_FILE_BUFFER_SIZE;
} else {
int writeLength = (int)writeFileLength;
byte[] lastBuffer = new byte[writeLength];
len = in.read(lastBuffer);
out.write(lastBuffer, 0, len);
totalRead += len;
writeFileLength = 0;
}
}
} finally {
in.close();
}
return totalRead;
}
/**
* Helper to ignore the '.' and '..' directories
*

View File

@ -777,10 +777,6 @@ public class TimeLineController {
case CONTENT_TAG_DELETED:
future = executor.submit(() -> filteredEvents.handleContentTagDeleted((ContentTagDeletedEvent) evt));
break;
case CURRENT_CASE:
//close timeline on case changes.
SwingUtilities.invokeLater(TimeLineController.this::shutDownTimeLine);
break;
case DATA_SOURCE_ADDED:
future = executor.submit(() -> {
filteredEvents.handleDataSourceAdded();

View File

@ -86,19 +86,13 @@ public class TimeLineModule {
@Override
public void propertyChange(PropertyChangeEvent evt) {
try {
getController().handleCaseEvent(evt);
} catch (NoCurrentCaseException ex) {
// ignore
return;
} catch (TskCoreException ex) {
MessageNotifyUtil.Message.error("Error creating timeline controller.");
logger.log(Level.SEVERE, "Error creating timeline controller", ex);
}
if (Case.Events.valueOf(evt.getPropertyName()).equals(CURRENT_CASE)) {
// we care only about case closing here
if (evt.getNewValue() == null) {
/*
* Current case is closing, shut down the timeline top
* component and set the pre case singleton controller
* reference to null.
*/
synchronized (controllerLock) {
if (controller != null) {
SwingUtilities.invokeLater(controller::shutDownTimeLine);
@ -106,6 +100,13 @@ public class TimeLineModule {
controller = null;
}
}
} else {
try {
getController().handleCaseEvent(evt);
} catch (NoCurrentCaseException ignored) {
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error handling application event", ex);
}
}
}
}

View File

@ -55,6 +55,7 @@ ExtractOs.windowsVolume.label=OS Drive (Windows)
ExtractOs.yellowDogLinuxOs.label=Linux (Yellow Dog)
ExtractOs.yellowDogLinuxVolume.label=OS Drive (Linux Yellow Dog)
ExtractOS_progressMessage=Checking for OS
ExtractPrefetch_module_name=Windows Prefetch Extractor
ExtractRecycleBin_module_name=Recycle Bin
ExtractSafari_Error_Getting_History=An error occurred while processing Safari history files.
ExtractSafari_Error_Parsing_Bookmark=An error occured while processing Safari Bookmark files

View File

@ -0,0 +1,388 @@
/*
*
* Autopsy Forensic Browser
*
* 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.
*/
package org.sleuthkit.autopsy.recentactivity;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import org.openide.modules.InstalledFileLocator;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.SQLiteDBConnect;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Extract the Prefetch Files and process them thru an External program. The data will then be added to the
* TSK_PROG_RUN artifact. Associated artifacts will be created if possible.
*/
final class ExtractPrefetch extends Extract {
private static final Logger logger = Logger.getLogger(ExtractPrefetch.class.getName());
private IngestJobContext context;
private static final String MODULE_NAME = "extractPREFETCH"; //NON-NLS
private static final String PREFETCH_TSK_COMMENT = "Prefetch File";
private static final String PREFETCH_FILE_LOCATION = "/Windows/Prefetch";
private static final String PREFETCH_TOOL_FOLDER = "markmckinnon"; //NON-NLS
private static final String PREFETCH_TOOL_NAME_WINDOWS_64 = "parse_prefetch_x64.exe"; //NON-NLS
private static final String PREFETCH_TOOL_NAME_WINDOWS_32 = "parse_prefetch_x32.exe"; //NON-NLS
private static final String PREFETCH_TOOL_NAME_MACOS = "parse_prefetch_macos"; //NON-NLS
private static final String PREFETCH_TOOL_NAME_LINUX = "parse_prefetch_linux"; //NON-NLS
private static final String PREFETCH_OUTPUT_FILE_NAME = "Output.txt"; //NON-NLS
private static final String PREFETCH_ERROR_FILE_NAME = "Error.txt"; //NON-NLS
private static final String PREFETCH_PARSER_DB_FILE = "Autopsy_PF_DB.db3"; //NON-NLS
private static final String PREFETCH_DIR_NAME = "prefetch"; //NON-NLS
@Messages({
"ExtractPrefetch_module_name=Windows Prefetch Extractor"
})
ExtractPrefetch() {
this.moduleName = Bundle.ExtractPrefetch_module_name();
}
@Override
void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
this.context = context;
String modOutPath = Case.getCurrentCase().getModuleDirectory() + File.separator + PREFETCH_DIR_NAME;
File dir = new File(modOutPath);
if (dir.exists() == false) {
boolean dirMade = dir.mkdirs();
if (!dirMade) {
logger.log(Level.SEVERE, "Error creating directory to store prefetch output database"); //NON-NLS
return; //If we cannot create the directory then we need to exit
}
}
extractPrefetchFiles(dataSource);
final String prefetchDumper = getPathForPrefetchDumper();
if (prefetchDumper == null) {
logger.log(Level.SEVERE, "Error finding parse_prefetch program"); //NON-NLS
return; //If we cannot find the parse_prefetch program we cannot proceed
}
if (context.dataSourceIngestIsCancelled()) {
return;
}
String modOutFile = modOutPath + File.separator + PREFETCH_PARSER_DB_FILE;
try {
String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), PREFETCH_DIR_NAME );
parsePrefetchFiles(prefetchDumper, tempDirPath, modOutFile, modOutPath);
createAppExecArtifacts(modOutFile, dataSource);
} catch (IOException ex) {
logger.log(Level.WARNING, "Error runing parse_prefetch or creating artifacts.", ex); //NON-NLS
}
}
/**
* Extract prefetch file to temp directory to process. Checks to make sure that the prefetch files only
* come from the /Windows/Prefetch directory
*
* @param dataSource - datasource to search for prefetch files
*
*/
void extractPrefetchFiles(Content dataSource) {
List<AbstractFile> pFiles;
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
try {
pFiles = fileManager.findFiles(dataSource, "%.pf"); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to find prefetch files.", ex); //NON-NLS
return; // No need to continue
}
for (AbstractFile pFile : pFiles) {
if (context.dataSourceIngestIsCancelled()) {
return;
}
String prefetchFile = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), PREFETCH_DIR_NAME) + File.separator + pFile.getName();
if (pFile.getParentPath().contains(PREFETCH_FILE_LOCATION)) {
try {
ContentUtils.writeToFile(pFile, new File(prefetchFile));
} catch (IOException ex) {
logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", pFile.getName(), prefetchFile), ex); //NON-NLS
}
}
}
}
/**
* Run the export parse_prefetch program against the prefetch files
*
* @param prefetchExePath - Path to the Executable to run
* @param prefetchDir - Directory where the prefetch files reside to be processed.
* @param tempOutFile - Output database file name and path.
* @param tempOutPath - Directory to store the output and error files.
*
* @throws FileNotFoundException
* @throws IOException
*/
void parsePrefetchFiles(String prefetchExePath, String prefetchDir, String tempOutFile, String tempOutPath) throws FileNotFoundException, IOException {
final Path outputFilePath = Paths.get(tempOutPath, PREFETCH_OUTPUT_FILE_NAME);
final Path errFilePath = Paths.get(tempOutPath, PREFETCH_ERROR_FILE_NAME);
List<String> commandLine = new ArrayList<>();
commandLine.add(prefetchExePath);
commandLine.add(prefetchDir); //NON-NLS
commandLine.add(tempOutFile);
ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
processBuilder.redirectOutput(outputFilePath.toFile());
processBuilder.redirectError(errFilePath.toFile());
ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context));
}
/**
* Get the path and executable for the parse_prefetch program. Checks for specific version of OS to
* get proper executable.
*
* @return - path and executable to run.
*
*/
private String getPathForPrefetchDumper() {
Path path = null;
if (PlatformUtil.isWindowsOS()) {
if (PlatformUtil.is64BitOS()) {
path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_WINDOWS_64);
} else {
path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_WINDOWS_32);
}
} else {
if ("Linux".equals(PlatformUtil.getOSName())) {
path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_LINUX);
} else {
path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_MACOS);
}
}
File prefetchToolFile = InstalledFileLocator.getDefault().locate(path.toString(),
ExtractPrefetch.class.getPackage().getName(), false);
if (prefetchToolFile != null) {
return prefetchToolFile.getAbsolutePath();
}
return null;
}
/**
* Create the artifacts from external run of the parse_prefetch program
*
* @param prefetchDb - Database file to read from running the parse_prefetch program.
* @param dataSource - The datasource to search in
*
*/
private void createAppExecArtifacts(String prefetchDb, Content dataSource) {
List<BlackboardArtifact> blkBrdArtList = new ArrayList<>();
String sqlStatement = "SELECT prefetch_File_Name, actual_File_Name, file_path, Number_time_file_run, Embeded_date_Time_Unix_1, " +
" Embeded_date_Time_Unix_2, Embeded_date_Time_Unix_3, Embeded_date_Time_Unix_4, Embeded_date_Time_Unix_5," +
" Embeded_date_Time_Unix_6, Embeded_date_Time_Unix_7, Embeded_date_Time_Unix_8 " +
" FROM prefetch_file_info;"; //NON-NLS
try (SQLiteDBConnect tempdbconnect = new SQLiteDBConnect("org.sqlite.JDBC", "jdbc:sqlite:" + prefetchDb); //NON-NLS
ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) {
while (resultSet.next()) {
if (context.dataSourceIngestIsCancelled()) {
logger.log(Level.INFO, "Cancelled Prefetch Artifact Creation."); //NON-NLS
return;
}
String prefetchFileName = resultSet.getString("prefetch_File_Name");
String applicationName = resultSet.getString("actual_File_Name"); //NON-NLS
List<Long> executionTimes = new ArrayList<>();
executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_1")));
executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_2")));
executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_3")));
executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_4")));
executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_5")));
executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_6")));
executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_7")));
executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_8")));
String timesProgramRun = resultSet.getString("Number_time_file_run");
String filePath = resultSet.getString("file_path");
AbstractFile pfAbstractFile = getAbstractFile(prefetchFileName, PREFETCH_FILE_LOCATION, dataSource);
List<Long> prefetchExecutionTimes = findNonZeroExecutionTimes(executionTimes);
if (pfAbstractFile != null) {
for (Long executionTime : prefetchExecutionTimes) {
// only add prefetch file entries that have an actual date associated with them
Collection<BlackboardAttribute> blkBrdAttributes = Arrays.asList(
new BlackboardAttribute(
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, getName(),
applicationName),//NON-NLS
new BlackboardAttribute(
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, getName(),
executionTime),
new BlackboardAttribute(
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COUNT, getName(), Integer.valueOf(timesProgramRun)),
new BlackboardAttribute(
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, getName(), PREFETCH_TSK_COMMENT));
try {
BlackboardArtifact blkBrdArt = pfAbstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN);
blkBrdArt.addAttributes(blkBrdAttributes);
blkBrdArtList.add(blkBrdArt);
BlackboardArtifact associatedBbArtifact = createAssociatedArtifact(applicationName.toLowerCase(), filePath, blkBrdArt, dataSource);
if (associatedBbArtifact != null) {
blkBrdArtList.add(associatedBbArtifact);
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Exception Adding Artifact.", ex);//NON-NLS
}
}
} else {
logger.log(Level.SEVERE, "File has a null value " + prefetchFileName);//NON-NLS
}
}
} catch (SQLException ex) {
logger.log(Level.SEVERE, "Error while trying to read into a sqlite db.", ex);//NON-NLS
}
if (!blkBrdArtList.isEmpty()) {
try {
blackboard.postArtifacts(blkBrdArtList, MODULE_NAME);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Error Posting Artifact.", ex);//NON-NLS
}
}
}
/**
* Cycle thru the execution times list and only return a new list of times that are greater than zero.
*
* @param executionTimes - list of prefetch execution times 8 possible timestamps
*
* @return List of timestamps that are greater than zero
*/
private List<Long> findNonZeroExecutionTimes(List<Long> executionTimes) {
List<Long> prefetchExecutionTimes = new ArrayList<>();
for (Long executionTime : executionTimes) { // only add prefetch file entries that have an actual date associated with them
if (executionTime > 0) {
prefetchExecutionTimes.add(executionTime);
}
}
return prefetchExecutionTimes;
}
/**
* Create associated artifacts using file path name and the artifact it associates with
*
* @param fileName the filename to search for
* @param filePathName file and path of object being associated with
* @param bba blackboard artifact to associate with
* @param dataSource - The datasource to search in
*
* @returnv BlackboardArtifact or a null value
*/
private BlackboardArtifact createAssociatedArtifact(String fileName, String filePathName, BlackboardArtifact bba, Content dataSource) {
AbstractFile sourceFile = getAbstractFile(fileName, filePathName, dataSource);
if (sourceFile != null) {
Collection<BlackboardAttribute> bbattributes2 = new ArrayList<>();
bbattributes2.addAll(Arrays.asList(
new BlackboardAttribute(TSK_ASSOCIATED_ARTIFACT, this.getName(),
bba.getArtifactID())));
BlackboardArtifact associatedObjectBba = createArtifactWithAttributes(TSK_ASSOCIATED_OBJECT, sourceFile, bbattributes2);
if (associatedObjectBba != null) {
return associatedObjectBba;
}
}
return null;
}
/**
* Get the abstract file for the prefetch file.
*
* @param fileName - File name of the prefetch file to find.
* @param filePath - Path where the prefetch file is located.
* @param dataSource - The datasource to search in
*
* @return Abstract file of the prefetch file.
*
*/
AbstractFile getAbstractFile(String fileName, String filePath, Content dataSource) {
List<AbstractFile> files;
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
try {
files = fileManager.findFiles(dataSource, fileName, filePath); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to find prefetch files.", ex); //NON-NLS
return null; // No need to continue
}
if (!files.isEmpty()) {
return files.get(0);
} else {
return null;
}
}
}

View File

@ -79,6 +79,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule {
Extract zoneInfo = new ExtractZoneIdentifier();
Extract recycleBin = new ExtractRecycleBin();
Extract sru = new ExtractSru();
Extract prefetch = new ExtractPrefetch();
extractors.add(chrome);
extractors.add(firefox);
@ -93,6 +94,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule {
extractors.add(zoneInfo); // this needs to run after the web browser modules
extractors.add(recycleBin); // this needs to run after ExtractRegistry and ExtractOS
extractors.add(sru);
extractors.add(prefetch);
browserExtractors.add(chrome);
browserExtractors.add(firefox);

View File

@ -1,5 +1,5 @@
#Updated by build script
#Fri, 12 Jun 2020 14:50:38 -0400
#Fri, 19 Jun 2020 10:14:47 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314
SPLASH_WIDTH=538

View File

@ -1,4 +1,4 @@
#Updated by build script
#Fri, 12 Jun 2020 14:50:38 -0400
#Fri, 19 Jun 2020 10:14:47 -0400
CTL_MainWindow_Title=Autopsy 4.15.0
CTL_MainWindow_Title_No_Project=Autopsy 4.15.0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,6 +6,15 @@
<code-name-base>org.sleuthkit.autopsy.thunderbirdparser</code-name-base>
<suite-component/>
<module-dependencies>
<dependency>
<code-name-base>org.netbeans.api.progress</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<release-version>1</release-version>
<specification-version>1.47.1</specification-version>
</run-dependency>
</dependency>
<dependency>
<code-name-base>org.openide.util</code-name-base>
<build-prerequisite/>

View File

@ -54,6 +54,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.Relationship;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
@ -76,6 +77,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
private Blackboard blackboard;
private CommunicationArtifactsHelper communicationArtifactsHelper;
private static final int MBOX_SIZE_TO_SPLIT = 1048576000;
private Case currentCase;
/**
@ -309,12 +311,75 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
return ProcessResult.OK;
}
try {
ContentUtils.writeToFile(abstractFile, file, context::fileIngestIsCancelled);
} catch (IOException ex) {
logger.log(Level.WARNING, "Failed writing mbox file to disk.", ex); //NON-NLS
return ProcessResult.OK;
if (abstractFile.getSize() < MBOX_SIZE_TO_SPLIT) {
try {
ContentUtils.writeToFile(abstractFile, file, context::fileIngestIsCancelled);
} catch (IOException ex) {
logger.log(Level.WARNING, "Failed writing mbox file to disk.", ex); //NON-NLS
return ProcessResult.OK;
}
processMboxFile(file, abstractFile, emailFolder);
if (file.delete() == false) {
logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
}
} else {
List<Long> mboxSplitOffsets = new ArrayList<>();
try{
mboxSplitOffsets = findMboxSplitOffset(abstractFile, file);
} catch (IOException ex) {
logger.log(Level.WARNING, String.format("Failed finding split offsets for mbox file {0}.", fileName), ex); //NON-NLS
return ProcessResult.OK;
}
long startingOffset = 0;
for (Long mboxSplitOffset : mboxSplitOffsets) {
File splitFile = new File(fileName + "-" + mboxSplitOffset);
try {
ContentUtils.writeToFile(abstractFile, splitFile, context::fileIngestIsCancelled, startingOffset, mboxSplitOffset);
} catch (IOException ex) {
logger.log(Level.WARNING, "Failed writing split mbox file to disk.", ex); //NON-NLS
return ProcessResult.OK;
}
processMboxFile(splitFile, abstractFile, emailFolder);
startingOffset = mboxSplitOffset;
if (splitFile.delete() == false) {
logger.log(Level.INFO, "Failed to delete temp file: {0}", splitFile); //NON-NLS
}
}
}
return ProcessResult.OK;
}
private List<Long> findMboxSplitOffset(AbstractFile abstractFile, File file) throws IOException {
List<Long> mboxSplitOffset = new ArrayList<>();
byte[] buffer = new byte[7];
ReadContentInputStream in = new ReadContentInputStream(abstractFile);
in.skip(MBOX_SIZE_TO_SPLIT);
int len = in.read(buffer);
while (len != -1) {
len = in.read(buffer);
if (buffer[0] == 13 && buffer[1] == 10 && buffer[2] == 70 && buffer[3] == 114 &&
buffer[4] == 111 && buffer[5] == 109 && buffer[6] == 32) {
mboxSplitOffset.add(in.getCurPosition() - 5 );
in.skip(MBOX_SIZE_TO_SPLIT);
}
}
return mboxSplitOffset;
}
private void processMboxFile(File file, AbstractFile abstractFile, String emailFolder) {
MboxParser emailIterator = MboxParser.getEmailIterator( emailFolder, file, abstractFile.getId());
List<EmailMessage> emails = new ArrayList<>();
@ -325,7 +390,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
emails.add(emailMessage);
}
}
String errors = emailIterator.getErrors();
if (!errors.isEmpty()) {
postErrorMessage(
@ -335,11 +400,6 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
}
processEmails(emails, MboxParser.getEmailIterator( emailFolder, file, abstractFile.getId()), abstractFile);
if (file.delete() == false) {
logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
}
return ProcessResult.OK;
}
/**
@ -755,4 +815,5 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
public void shutDown() {
// nothing to shut down
}
}