Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
Persona.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.centralrepository.datamodel;
20 
21 import java.sql.ResultSet;
22 import java.sql.SQLException;
23 import java.time.Instant;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Objects;
29 import java.util.UUID;
30 import org.apache.commons.lang3.StringUtils;
31 import org.openide.util.NbBundle;
32 
39 public class Persona {
40 
44  public enum Confidence {
45  LOW(1, "Low confidence"),
46  MODERATE(2, "Moderate confidence"),
47  HIGH(3, "High confidence");
48 
49  private final String name;
50  private final int level_id;
51 
52  Confidence(int level, String name) {
53  this.name = name;
54  this.level_id = level;
55 
56  }
57 
58  @Override
59  public String toString() {
60  return name;
61  }
62 
63  public int getLevelId() {
64  return this.level_id;
65  }
66 
67  static Confidence fromId(int value) {
68  for (Confidence confidence : Confidence.values()) {
69  if (confidence.getLevelId() == value) {
70  return confidence;
71  }
72  }
73  return Confidence.LOW;
74  }
75 
76  }
77 
81  public enum PersonaStatus {
82 
83  UNKNOWN(1, "Unknown"),
84  ACTIVE(2, "Active"),
85  MERGED(3, "Merged"),
86  SPLIT(4, "Split"),
87  DELETED(5, "Deleted");
88 
89  private final String description;
90  private final int status_id;
91 
92  PersonaStatus(int status, String description) {
93  this.status_id = status;
94  this.description = description;
95  }
96 
97  @Override
98  public String toString() {
99  return description;
100  }
101 
102  public int getStatusId() {
103  return this.status_id;
104  }
105 
106  static PersonaStatus fromId(int value) {
107  for (PersonaStatus status : PersonaStatus.values()) {
108  if (status.getStatusId() == value) {
109  return status;
110  }
111  }
112  return PersonaStatus.UNKNOWN;
113  }
114  }
115 
116  // primary key in the Personas table in CR database
117  private final long id;
118  private final String uuidStr;
119  private final String name;
120  private final String comment;
121  private final long createdDate;
122  private final long modifiedDate;
123  private final PersonaStatus status;
125 
126  @NbBundle.Messages("Persona.defaultName=Unnamed")
127  public static String getDefaultName() {
128  return Bundle.Persona_defaultName();
129  }
130 
131  public long getId() {
132  return id;
133  }
134 
135  public String getUuidStr() {
136  return uuidStr;
137  }
138 
139  public String getName() {
140  return name;
141  }
142 
143  public String getComment() {
144  return comment;
145  }
146 
147  public long getCreatedDate() {
148  return createdDate;
149  }
150 
151  public long getModifiedDate() {
152  return modifiedDate;
153  }
154 
156  return status;
157  }
158 
160  return examiner;
161  }
162 
163  Persona(long id, String uuidStr, String name, String comment, long created_date, long modified_date, PersonaStatus status, CentralRepoExaminer examiner) {
164  this.id = id;
165  this.uuidStr = uuidStr;
166  this.name = name;
167  this.comment = comment;
168  this.createdDate = created_date;
169  this.modifiedDate = modified_date;
170  this.status = status;
171  this.examiner = examiner;
172  }
173 
174  @Override
175  public int hashCode() {
176  int hash = 7;
177  hash = 67 * hash + (int) (this.id ^ (this.id >>> 32));
178  hash = 67 * hash + Objects.hashCode(this.uuidStr);
179  return hash;
180  }
181 
182  @Override
183  public boolean equals(Object obj) {
184  if (this == obj) {
185  return true;
186  }
187  if (obj == null) {
188  return false;
189  }
190  if (getClass() != obj.getClass()) {
191  return false;
192  }
193  final Persona other = (Persona) obj;
194  if (this.id != other.getId()) {
195  return false;
196  }
197  return this.uuidStr.equalsIgnoreCase(other.getUuidStr());
198  }
199 
216  public static Persona createPersonaForAccount(String personaName, String comment, PersonaStatus status, CentralRepoAccount account, String justification, Persona.Confidence confidence) throws CentralRepoException {
217  Persona persona = createPersona(personaName, comment, status);
218  persona.addAccount(account, justification, confidence);
219  return persona;
220  }
221 
235  private static Persona createPersona(String name, String comment, PersonaStatus status) throws CentralRepoException {
236  // generate a UUID for the persona
237  String uuidStr = UUID.randomUUID().toString();
238  CentralRepoExaminer examiner = getCRInstance().getOrInsertExaminer(System.getProperty("user.name"));
239 
240  Instant instant = Instant.now();
241  Long timeStampMillis = instant.toEpochMilli();
242 
243  String insertPersonaSQL = "INSERT INTO personas (uuid, comment, name, created_date, modified_date, status_id, examiner_id ) " //NON-NLS
244  + " VALUES (?, ?, ?, ?, ?, ?, ?)";
245  List<Object> params = new ArrayList<>();
246  params.add(uuidStr);
247  params.add(StringUtils.isBlank(comment) ? "" : comment);
248  params.add(StringUtils.isBlank(name) ? getDefaultName() : name);
249  params.add(timeStampMillis);
250  params.add(timeStampMillis);
251  params.add(status.getStatusId());
252  params.add(examiner.getId());
253 
254  getCRInstance().executeCommand(insertPersonaSQL, params);
255  return getPersonaByUUID(uuidStr);
256  }
257 
265  public void setComment(String comment) throws CentralRepoException {
266  String updateSQL = "UPDATE personas SET comment = ? WHERE id = ?";
268  if (cr != null) {
269  List<Object> params = new ArrayList<>();
270  params.add(StringUtils.isBlank(comment) ? "" : comment);
271  params.add(id);
272 
273  getCRInstance().executeCommand(updateSQL, params);
274  }
275  }
276 
284  public void setName(String name) throws CentralRepoException {
285  String updateSQL = "UPDATE personas SET name = ? WHERE id = ?";
287  if (cr != null) {
288  List<Object> params = new ArrayList<>();
289  params.add(StringUtils.isBlank(name) ? getDefaultName() : name);
290  params.add(id);
291 
292  getCRInstance().executeCommand(updateSQL, params);
293  }
294  }
295 
309  public PersonaAccount addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence) throws CentralRepoException {
310  return PersonaAccount.addPersonaAccount(this, account, justification, confidence);
311  }
312 
321  public void removeAccount(PersonaAccount account) throws CentralRepoException {
322  PersonaAccount.removePersonaAccount(account.getId());
323  }
324 
335  public void modifyAccount(PersonaAccount account, Confidence confidence, String justification) throws CentralRepoException {
336  PersonaAccount.modifyPersonaAccount(account.getId(), confidence, justification);
337  }
338 
342  public void delete() throws CentralRepoException {
343  String deleteSQL = "UPDATE personas SET status_id = ? WHERE id = ?";
345  if (cr != null) {
346  List<Object> params = new ArrayList<>();
347  params.add(PersonaStatus.DELETED.getStatusId());
348  params.add(id);
349 
350  getCRInstance().executeCommand(deleteSQL, params);
351  }
352  }
353 
357  private static class PersonaQueryCallback implements CentralRepositoryDbQueryCallback {
358 
359  private final Collection<Persona> personaList = new ArrayList<>();
360 
361  @Override
362  public void process(ResultSet rs) throws SQLException {
363 
364  while (rs.next()) {
366  rs.getInt("examiner_id"),
367  rs.getString("login_name"));
368 
369  PersonaStatus status = PersonaStatus.fromId(rs.getInt("status_id"));
370  Persona persona = new Persona(
371  rs.getInt("id"),
372  rs.getString("uuid"),
373  rs.getString("name"),
374  rs.getString("comment"),
375  Long.parseLong(rs.getString("created_date")),
376  Long.parseLong(rs.getString("modified_date")),
377  status,
378  examiner
379  );
380 
381  personaList.add(persona);
382  }
383  }
384 
385  Collection<Persona> getPersonas() {
386  return Collections.unmodifiableCollection(personaList);
387  }
388  };
389 
390  // Partial query string to select from personas table,
391  // just supply the where clause.
392  private static final String PERSONA_QUERY
393  = "SELECT p.id, p.uuid, p.name, p.comment, p.created_date, p.modified_date, p.status_id, p.examiner_id, e.login_name, e.display_name "
394  + "FROM personas as p "
395  + "INNER JOIN examiners as e ON e.id = p.examiner_id ";
396 
409  private static Persona getPersonaByUUID(String uuid) throws CentralRepoException {
410 
411  String queryClause
412  = PERSONA_QUERY
413  + "WHERE p.uuid = ?";
414 
415  List<Object> params = new ArrayList<>();
416  params.add(uuid);
417 
418  PersonaQueryCallback queryCallback = new PersonaQueryCallback();
419  getCRInstance().executeQuery(queryClause, params, queryCallback);
420 
421  Collection<Persona> personas = queryCallback.getPersonas();
422 
423  return personas.isEmpty() ? null : personas.iterator().next();
424  }
425 
438  public static Collection<Persona> getPersonaByName(String partialName) throws CentralRepoException {
439 
440  String queryClause = PERSONA_QUERY
441  + "WHERE p.status_id != ? "
442  + " AND LOWER(p.name) LIKE LOWER(?) ESCAPE '!'";
443 
444  List<Object> params = new ArrayList<>();
445  params.add(PersonaStatus.DELETED.getStatusId());
446  params.add("%" + getLikeEscaped(partialName) + "%"); // partial substring search
447 
448  PersonaQueryCallback queryCallback = new PersonaQueryCallback();
449  getCRInstance().executeQuery(queryClause, params, queryCallback);
450 
451  return queryCallback.getPersonas();
452  }
453 
466  private static String getLikeEscaped(String initial) {
467  if (initial == null) {
468  return null;
469  }
470 
471  return initial
472  .replace("!", "!!")
473  .replace("%", "!%")
474  .replace("_", "!_");
475  }
476 
489  public static Collection<Persona> getPersonaByAccountIdentifierLike(String partialName) throws CentralRepoException {
490  String queryClause = "SELECT p.id, p.uuid, p.name, p.comment, p.created_date, p.modified_date, p.status_id, p.examiner_id, e.login_name\n"
491  + "FROM personas p\n"
492  + "LEFT JOIN examiners e ON e.id = p.examiner_id\n"
493  + "WHERE p.status_id <> ?\n"
494  + "AND p.id IN (\n"
495  + " SELECT pa.persona_id\n"
496  + " FROM persona_accounts pa\n"
497  + " INNER JOIN accounts a ON a.id = pa.account_id\n"
498  + " WHERE LOWER(a.account_unique_identifier) LIKE LOWER(?) ESCAPE '!'\n"
499  + ")";
500 
501  PersonaQueryCallback queryCallback = new PersonaQueryCallback();
502 
503  List<Object> params = new ArrayList<>();
504  params.add(PersonaStatus.DELETED.getStatusId());
505  params.add("%" + getLikeEscaped(partialName) + "%"); // partial substring search
506 
507  getCRInstance().executeQuery(queryClause, params, queryCallback);
508  return queryCallback.getPersonas();
509  }
510 
522  public PersonaAlias addAlias(String alias, String justification, Persona.Confidence confidence) throws CentralRepoException {
523  return PersonaAlias.addPersonaAlias(this, alias, justification, confidence);
524  }
525 
534  public void removeAlias(PersonaAlias alias) throws CentralRepoException {
535  PersonaAlias.removePersonaAlias(alias);
536  }
537 
548  public void modifyAlias(PersonaAlias key, Confidence confidence, String justification) throws CentralRepoException {
549  PersonaAlias.modifyPersonaAlias(key, confidence, justification);
550  }
551 
559  public Collection<PersonaAlias> getAliases() throws CentralRepoException {
560  return PersonaAlias.getPersonaAliases(this.getId());
561  }
562 
575  public PersonaMetadata addMetadata(String name, String value, String justification, Persona.Confidence confidence) throws CentralRepoException {
576  return PersonaMetadata.addPersonaMetadata(this.getId(), name, value, justification, confidence);
577  }
578 
587  public void removeMetadata(PersonaMetadata metadata) throws CentralRepoException {
588  PersonaMetadata.removePersonaMetadata(metadata);
589  }
590 
601  public void modifyMetadata(PersonaMetadata key, Confidence confidence, String justification) throws CentralRepoException {
602  PersonaMetadata.modifyPersonaMetadata(key, confidence, justification);
603  }
604 
612  public Collection<PersonaMetadata> getMetadata() throws CentralRepoException {
613  return PersonaMetadata.getPersonaMetadata(this.getId());
614  }
615 
624  public Collection<PersonaAccount> getPersonaAccounts() throws CentralRepoException {
625  return PersonaAccount.getPersonaAccountsForPersona(this.getId());
626  }
627 
632  private static class CaseForAccountInstanceQueryCallback implements CentralRepositoryDbQueryCallback {
633 
634  Collection<CorrelationCase> correlationCases = new ArrayList<>();
635 
636  @Override
637  public void process(ResultSet resultSet) throws CentralRepoException, SQLException {
638 
639  while (resultSet.next()) {
640  // get Case for case_id
641  CorrelationCase correlationCase = getCRInstance().getCaseById(resultSet.getInt("case_id"));
642  correlationCases.add(correlationCase);
643  }
644  }
645 
646  Collection<CorrelationCase> getCases() {
647  return Collections.unmodifiableCollection(correlationCases);
648  }
649  };
650 
659  public Collection<CorrelationCase> getCases() throws CentralRepoException {
660 
661  Collection<CorrelationCase> casesForPersona = new ArrayList<>();
662 
663  // get all accounts for this persona
664  Collection<CentralRepoAccount> accounts = PersonaAccount.getAccountsForPersona(this.getId());
665  for (CentralRepoAccount account : accounts) {
666  int corrTypeId = account.getAccountType().getCorrelationTypeId();
668 
669  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(correlationType);
670  String querySql = "SELECT DISTINCT case_id FROM " + tableName
671  + " WHERE account_id = ?"; // param 1
672 
673  List<Object> params = new ArrayList<>();
674  params.add(account.getId());
675 
677  getCRInstance().executeQuery(querySql, params, queryCallback);
678 
679  // Add any cases that aren't already on the list.
680  for (CorrelationCase corrCase : queryCallback.getCases()) {
681  if (!casesForPersona.stream().anyMatch(p -> p.getCaseUUID().equalsIgnoreCase(corrCase.getCaseUUID()))) {
682  casesForPersona.add(corrCase);
683  }
684  }
685  }
686 
687  return casesForPersona;
688  }
689 
694  private static class DatasourceForAccountInstanceQueryCallback implements CentralRepositoryDbQueryCallback {
695 
696  Collection<CorrelationDataSource> correlationDataSources = new ArrayList<>();
697 
698  @Override
699  public void process(ResultSet resultSet) throws CentralRepoException, SQLException {
700 
701  while (resultSet.next()) {
702  // get Case for case_id
703 
704  CorrelationCase correlationCase = getCRInstance().getCaseById(resultSet.getInt("case_id"));
705  CorrelationDataSource correlationDatasource = getCRInstance().getDataSourceById(correlationCase, resultSet.getInt("data_source_id"));
706 
707  // Add data source to list if not already on it.
708  if (!correlationDataSources.stream().anyMatch(p -> Objects.equals(p.getDataSourceObjectID(), correlationDatasource.getDataSourceObjectID()))) {
709  correlationDataSources.add(correlationDatasource);
710  }
711  }
712  }
713 
714  Collection<CorrelationDataSource> getDataSources() {
715  return Collections.unmodifiableCollection(correlationDataSources);
716  }
717  };
718 
727  public Collection<CorrelationDataSource> getDataSources() throws CentralRepoException {
728  Collection<CorrelationDataSource> correlationDataSources = new ArrayList<>();
729 
730  Collection<CentralRepoAccount> accounts = PersonaAccount.getAccountsForPersona(this.getId());
731  for (CentralRepoAccount account : accounts) {
732  int corrTypeId = account.getAccountType().getCorrelationTypeId();
734 
735  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(correlationType);
736  String querySql = "SELECT case_id, data_source_id FROM " + tableName
737  + " WHERE account_id = ?"; // param 1
738 
739  List<Object> params = new ArrayList<>();
740  params.add(account.getId());
741 
743  getCRInstance().executeQuery(querySql, params, queryCallback);
744 
745  // Add any data sources that aren't already on the list.
746  for (CorrelationDataSource correlationDatasource : queryCallback.getDataSources()) {
747  if (!correlationDataSources.stream().anyMatch(p -> Objects.equals(p.getDataSourceObjectID(), correlationDatasource.getDataSourceObjectID()))) {
748  correlationDataSources.add(correlationDatasource);
749  }
750  }
751  }
752 
753  return correlationDataSources;
754  }
755 
759  private static class PersonaFromAccountInstanceQueryCallback implements CentralRepositoryDbQueryCallback {
760 
761  Collection<Persona> personasList = new ArrayList<>();
762 
763  @Override
764  public void process(ResultSet resultSet) throws CentralRepoException, SQLException {
765 
766  while (resultSet.next()) {
767 
768  // examiner that created the persona
769  CentralRepoExaminer personaExaminer = new CentralRepoExaminer(
770  resultSet.getInt("persona_examiner_id"),
771  resultSet.getString("persona_examiner_login_name"));
772 
773  // create persona
774  PersonaStatus status = PersonaStatus.fromId(resultSet.getInt("status_id"));
775  Persona persona = new Persona(
776  resultSet.getInt("persona_id"),
777  resultSet.getString("uuid"),
778  resultSet.getString("name"),
779  resultSet.getString("comment"),
780  Long.parseLong(resultSet.getString("created_date")),
781  Long.parseLong(resultSet.getString("modified_date")),
782  status,
783  personaExaminer
784  );
785 
786  personasList.add(persona);
787  }
788  }
789 
790  Collection<Persona> getPersonasList() {
791  return Collections.unmodifiableCollection(personasList);
792  }
793  };
794 
805  private static String getPersonaFromInstanceTableQueryTemplate(CentralRepoAccount.CentralRepoAccountType crAccountType) throws CentralRepoException {
806 
807  int corrTypeId = crAccountType.getCorrelationTypeId();
809 
810  String instanceTableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(correlationType);
811  return "SELECT " + instanceTableName + ".account_id, case_id, data_source_id, "
812  + " personas.id as persona_id, personas.uuid, personas.name, personas.comment, personas.created_date, personas.modified_date, personas.status_id, "
813  + " personas.examiner_id as persona_examiner_id, persona_examiner.login_name as persona_examiner_login_name, persona_examiner.display_name as persona_examiner_display_name "
814  + " FROM " + instanceTableName
815  + " JOIN persona_accounts as pa on pa.account_id = " + instanceTableName + ".account_id"
816  + " JOIN personas as personas on personas.id = pa.persona_id"
817  + " JOIN examiners as persona_examiner ON persona_examiner.id = personas.examiner_id ";
818 
819  }
820 
830  public static Collection<Persona> getPersonasForCase(CorrelationCase correlationCase) throws CentralRepoException {
831  Collection<Persona> personaList = new ArrayList<>();
832 
834  for (CentralRepoAccount.CentralRepoAccountType crAccountType : accountTypes) {
835 
836  String querySql = getPersonaFromInstanceTableQueryTemplate(crAccountType)
837  + " WHERE case_id = ?" // param 1
838  + " AND personas.status_id != ?"; // param 2
839 
840  List<Object> params = new ArrayList<>();
841  params.add(correlationCase.getID());
842  params.add(Persona.PersonaStatus.DELETED.getStatusId());
843 
845  getCRInstance().executeQuery(querySql, params, queryCallback);
846 
847  // Add persona that aren't already on the list.
848  for (Persona persona : queryCallback.getPersonasList()) {
849  if (!personaList.stream().anyMatch(p -> Objects.equals(p.getUuidStr(), persona.getUuidStr()))) {
850  personaList.add(persona);
851  }
852  }
853 
854  }
855  return personaList;
856  }
857 
867  public static Collection<Persona> getPersonasForDataSource(CorrelationDataSource dataSource) throws CentralRepoException {
868  Collection<Persona> personaList = new ArrayList<>();
869 
871  for (CentralRepoAccount.CentralRepoAccountType crAccountType : accountTypes) {
872 
873  String querySql = getPersonaFromInstanceTableQueryTemplate(crAccountType)
874  + " WHERE data_source_id = ?"
875  + " AND personas.status_id != ?";
876 
877  List<Object> params = new ArrayList<>();
878  params.add(dataSource.getID());
879  params.add(Persona.PersonaStatus.DELETED.getStatusId());
880 
882  getCRInstance().executeQuery(querySql, params, queryCallback);
883 
884  // Add persona that aren't already on the list.
885  for (Persona persona : queryCallback.getPersonasList()) {
886  if (!personaList.stream().anyMatch(p -> Objects.equals(p.getUuidStr(), persona.getUuidStr()))) {
887  personaList.add(persona);
888  }
889  }
890 
891  }
892  return personaList;
893  }
894 
903  private static CentralRepository getCRInstance() throws CentralRepoException {
905 
906  if (instance == null) {
907  throw new CentralRepoException("Failed to get instance of CentralRespository, CR was null");
908  }
909 
910  return instance;
911  }
912 }
void modifyAlias(PersonaAlias key, Confidence confidence, String justification)
Definition: Persona.java:548
void executeQuery(String sql, List< Object > params, CentralRepositoryDbQueryCallback queryCallback)
static Collection< Persona > getPersonaByName(String partialName)
Definition: Persona.java:438
static Persona createPersonaForAccount(String personaName, String comment, PersonaStatus status, CentralRepoAccount account, String justification, Persona.Confidence confidence)
Definition: Persona.java:216
PersonaAlias addAlias(String alias, String justification, Persona.Confidence confidence)
Definition: Persona.java:522
PersonaAccount addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
Definition: Persona.java:309
CentralRepoExaminer getOrInsertExaminer(String examinerLoginName)
void modifyAccount(PersonaAccount account, Confidence confidence, String justification)
Definition: Persona.java:335
PersonaMetadata addMetadata(String name, String value, String justification, Persona.Confidence confidence)
Definition: Persona.java:575
Collection< CorrelationDataSource > getDataSources()
Definition: Persona.java:727
void modifyMetadata(PersonaMetadata key, Confidence confidence, String justification)
Definition: Persona.java:601
static Collection< Persona > getPersonasForCase(CorrelationCase correlationCase)
Definition: Persona.java:830
static String correlationTypeToInstanceTableName(CorrelationAttributeInstance.Type type)
static String getPersonaFromInstanceTableQueryTemplate(CentralRepoAccount.CentralRepoAccountType crAccountType)
Definition: Persona.java:805
static Collection< PersonaAlias > getPersonaAliases(long personaId)
static Persona createPersona(String name, String comment, PersonaStatus status)
Definition: Persona.java:235
CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId)
static Collection< Persona > getPersonasForDataSource(CorrelationDataSource dataSource)
Definition: Persona.java:867
static Collection< Persona > getPersonaByAccountIdentifierLike(String partialName)
Definition: Persona.java:489
CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.