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.Objects;
28 import java.util.UUID;
29 import org.apache.commons.lang3.StringUtils;
30 import org.openide.util.NbBundle;
32
40
45 LOW(1,
"Low confidence"),
47 HIGH(3,
"High confidence");
48
51
54 this.level_id = level;
55
56 }
57
58 @Override
61 }
62
64 return this.level_id;
65 }
66
69 if (confidence.getLevelId() == value) {
70 return confidence;
71 }
72 }
74 }
75
76 }
77
82
88
91
94 this.description = description;
95 }
96
97 @Override
99 return description;
100 }
101
103 return this.status_id;
104 }
105
110 }
111 }
113 }
114 }
115
116 // primary key in the Personas table in CR database
117 private final long id;
125
126 @NbBundle.Messages("Persona.defaultName=Unnamed")
128 return Bundle.Persona_defaultName();
129 }
130
133 }
134
137 }
138
141 }
142
145 }
146
149 }
150
153 }
154
157 }
158
161 }
162
168 this.createdDate = created_date;
169 this.modifiedDate = modified_date;
172 }
173
174 @Override
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
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 }
194 if (this.
id != other.
getId()) {
195 return false;
196 }
197 return this.uuidStr.equalsIgnoreCase(other.
getUuidStr());
198 }
199
217 persona.
addAccount(account, justification, confidence);
218 return persona;
219 }
220
235 // generate a UUID for the persona
236 String uuidStr = UUID.randomUUID().toString();
238
239 Instant instant = Instant.now();
240 Long timeStampMillis = instant.toEpochMilli();
241 String insertClause = " INTO personas (uuid, comment, name, created_date, modified_date, status_id, examiner_id ) "
242 + "VALUES ( '" + uuidStr + "', "
243 + "'" + ((StringUtils.isBlank(comment) ? "" : SleuthkitCase.escapeSingleQuotes(comment))) + "',"
244 +
"'" + ((StringUtils.isBlank(name) ?
getDefaultName() : SleuthkitCase.escapeSingleQuotes(name))) +
"',"
245 + timeStampMillis.toString() + ","
246 + timeStampMillis.toString() + ","
249 + ")";
250
253 }
254
263 String updateClause =
"UPDATE personas SET comment = '" + comment +
"' WHERE id = " +
id;
265 if (cr != null) {
267 }
268 }
269
278 String updateClause =
"UPDATE personas SET name = '" + name +
"' WHERE id = " +
id;
280 if (cr != null) {
282 }
283 }
284
298 return PersonaAccount.addPersonaAccount(
this, account, justification, confidence);
299 }
300
311 }
312
324 PersonaAccount.modifyPersonaAccount(account.getId(), confidence, justification);
325 }
326
331 String deleteSQL =
"UPDATE personas SET status_id = " +
PersonaStatus.
DELETED.status_id +
" WHERE id = " + this.
id;
333 if (cr != null) {
335 }
336 }
337
342
343 private final Collection<Persona>
personaList =
new ArrayList<>();
344
345 @Override
346 public void process(ResultSet rs)
throws SQLException {
347
348 while (rs.next()) {
350 rs.getInt("examiner_id"),
351 rs.getString("login_name"));
352
355 rs.getInt("id"),
356 rs.getString("uuid"),
357 rs.getString("name"),
358 rs.getString("comment"),
359 Long.parseLong(rs.getString("created_date")),
360 Long.parseLong(rs.getString("modified_date")),
361 status,
362 examiner
363 );
364
365 personaList.add(persona);
366 }
367 }
368
369 Collection<Persona> getPersonas() {
370 return Collections.unmodifiableCollection(personaList);
371 }
372 };
373
374 // Partial query string to select from personas table,
375 // just supply the where clause.
377 "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 "
378 + "FROM personas as p "
379 + "INNER JOIN examiners as e ON e.id = p.examiner_id ";
380
381
394
395 String queryClause =
396 PERSONA_QUERY
397 + "WHERE p.uuid = '" + uuid + "'";
398
401
402 Collection<Persona> personas = queryCallback.getPersonas();
403
404 return personas.isEmpty() ? null : personas.iterator().next();
405 }
406
419
420 String queryClause = PERSONA_QUERY
422 " AND LOWER(p.name) LIKE " + "LOWER('%" + partialName + "%')" ;
423
426
427 return queryCallback.getPersonas();
428 }
429
442 String queryClause = "SELECT DISTINCT accounts.id as a_id,"
443 + "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"
444 + " FROM accounts"
445 + " JOIN persona_accounts as pa ON pa.account_id = accounts.id"
446 + " JOIN personas as p ON p.id = pa.persona_id"
447 + " JOIN examiners as e ON e.id = p.examiner_id"
448 + " WHERE LOWER(accounts.account_unique_identifier) LIKE LOWER('%" + partialName + "%')"
450 + " GROUP BY p.id";
451
454 if (cr != null) {
456 }
457
458 return queryCallback.getPersonas();
459 }
460
472 return PersonaAlias.addPersonaAlias(
this, alias, justification, confidence);
473 }
474
485 }
486
498 PersonaAlias.modifyPersonaAlias(key, confidence, justification);
499 }
500
510 }
511
524 return PersonaMetadata.addPersonaMetadata(this.
getId(), name, value, justification, confidence);
525 }
526
537 }
538
551 }
552
562 }
563
574 }
575
581
582 Collection<CorrelationCase> correlationCases = new ArrayList<>();
583
584 @Override
586
587 while (resultSet.next()) {
588 // get Case for case_id
590 correlationCases.add(correlationCase);
591 }
592 }
593
594 Collection<CorrelationCase> getCases() {
595 return Collections.unmodifiableCollection(correlationCases);
596 }
597 };
598
606 public Collection<CorrelationCase>
getCases() throws CentralRepoException {
607
608 Collection<CorrelationCase> casesForPersona = new ArrayList<>();
609
610 // get all accounts for this persona
611 Collection<CentralRepoAccount> accounts =
PersonaAccount.getAccountsForPersona(this.
getId());
613 int corrTypeId = account.getAccountType().getCorrelationTypeId();
615
617 String querySql = "SELECT DISTINCT case_id FROM " + tableName
618 + " WHERE account_id = " + account.getId();
619
622
623 // Add any cases that aren't already on the list.
625 if (!casesForPersona.stream().anyMatch(p -> p.getCaseUUID().equalsIgnoreCase(corrCase.getCaseUUID()))) {
626 casesForPersona.add(corrCase);
627 }
628 }
629 }
630
631 return casesForPersona;
632 }
633
639
640 Collection<CorrelationDataSource> correlationDataSources = new ArrayList<>();
641
642 @Override
643 public void process(ResultSet resultSet)
throws CentralRepoException, SQLException {
644
645 while (resultSet.next()) {
646 // get Case for case_id
647
650
651 // Add data source to list if not already on it.
652 if (!correlationDataSources.stream().anyMatch(p -> Objects.equals(p.getDataSourceObjectID(), correlationDatasource.
getDataSourceObjectID()))) {
653 correlationDataSources.add(correlationDatasource);
654 }
655 }
656 }
657
658 Collection<CorrelationDataSource> getDataSources() {
659 return Collections.unmodifiableCollection(correlationDataSources);
660 }
661 };
662
671 public Collection<CorrelationDataSource>
getDataSources() throws CentralRepoException {
672 Collection<CorrelationDataSource> correlationDataSources = new ArrayList<>();
673
674 Collection<CentralRepoAccount> accounts =
PersonaAccount.getAccountsForPersona(this.
getId());
676 int corrTypeId = account.getAccountType().getCorrelationTypeId();
678
680 String querySql = "SELECT case_id, data_source_id FROM " + tableName
681 + " WHERE account_id = " + account.getId();
682
685
686 // Add any data sources that aren't already on the list.
688 if (!correlationDataSources.stream().anyMatch(p -> Objects.equals(p.getDataSourceObjectID(), correlationDatasource.getDataSourceObjectID()))) {
689 correlationDataSources.add(correlationDatasource);
690 }
691 }
692 }
693
694 return correlationDataSources;
695 }
696
701
702 Collection<Persona> personasList = new ArrayList<>();
703
704 @Override
705 public void process(ResultSet resultSet)
throws CentralRepoException, SQLException {
706
707 while (resultSet.next()) {
708
709 // examiner that created the persona
711 resultSet.getInt("persona_examiner_id"),
712 resultSet.getString("persona_examiner_login_name"));
713
714 // create persona
717 resultSet.getInt("persona_id"),
718 resultSet.getString("uuid"),
719 resultSet.getString("name"),
720 resultSet.getString("comment"),
721 Long.parseLong(resultSet.getString("created_date")),
722 Long.parseLong(resultSet.getString("modified_date")),
723 status,
724 personaExaminer
725 );
726
727 personasList.add(persona);
728 }
729 }
730
731 Collection<Persona> getPersonasList() {
732 return Collections.unmodifiableCollection(personasList);
733 }
734 };
735
745
746 int corrTypeId = crAccountType.getCorrelationTypeId();
748
750 return "SELECT " + instanceTableName + ".account_id, case_id, data_source_id, "
751 + " personas.id as persona_id, personas.uuid, personas.name, personas.comment, personas.created_date, personas.modified_date, personas.status_id, "
752 + " 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 "
753 + " FROM " + instanceTableName
754 + " JOIN persona_accounts as pa on pa.account_id = " + instanceTableName + ".account_id"
755 + " JOIN personas as personas on personas.id = pa.persona_id"
756 + " JOIN examiners as persona_examiner ON persona_examiner.id = personas.examiner_id ";
757
758 }
759
769 Collection<Persona> personaList = new ArrayList<>();
770
773
775 + " WHERE case_id = " + correlationCase.getID()
777
780
781 // Add persona that aren't already on the list.
782 for (
Persona persona : queryCallback.getPersonasList()) {
783 if (!personaList.stream().anyMatch(p -> Objects.equals(p.getUuidStr(), persona.getUuidStr()))) {
784 personaList.add(persona);
785 }
786 }
787
788 }
789 return personaList;
790 }
791
801 Collection<Persona> personaList = new ArrayList<>();
802
805
807 + " WHERE data_source_id = " + dataSource.getID()
809
812
813 // Add persona that aren't already on the list.
814 for (
Persona persona : queryCallback.getPersonasList()) {
815 if (!personaList.stream().anyMatch(p -> Objects.equals(p.getUuidStr(), persona.getUuidStr()))) {
816 personaList.add(persona);
817 }
818 }
819
820 }
821 return personaList;
822 }
823
824
835
836 if(instance == null) {
837 throw new CentralRepoException("Failed to get instance of CentralRespository, CR was null");
838 }
839
840 return instance;
841 }
842 }
void executeSelectSQL(String sql, CentralRepositoryDbQueryCallback queryCallback)
static CentralRepository getCRInstance()
void removeAlias(PersonaAlias alias)
CorrelationCase getCaseById(int caseId)
void modifyAlias(PersonaAlias key, Confidence confidence, String justification)
static Persona getPersonaByUUID(String uuid)
Collection< PersonaAccount > getPersonaAccounts()
Confidence(int level, String name)
static Collection< Persona > getPersonaByName(String partialName)
static Persona createPersonaForAccount(String personaName, String comment, PersonaStatus status, CentralRepoAccount account, String justification, Persona.Confidence confidence)
void setName(String name)
PersonaAlias addAlias(String alias, String justification, Persona.Confidence confidence)
PersonaAccount addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
void removeAccount(PersonaAccount account)
Collection< CentralRepoAccountType > getAllAccountTypes()
CentralRepoExaminer getOrInsertExaminer(String examinerLoginName)
void modifyAccount(PersonaAccount account, Confidence confidence, String justification)
PersonaMetadata addMetadata(String name, String value, String justification, Persona.Confidence confidence)
CentralRepoExaminer getExaminer()
Collection< CorrelationDataSource > getDataSources()
void modifyMetadata(PersonaMetadata key, Confidence confidence, String justification)
void process(ResultSet resultSet)
Collection< PersonaAlias > getAliases()
static Collection< Persona > getPersonasForCase(CorrelationCase correlationCase)
Collection< CorrelationCase > getCases()
static String correlationTypeToInstanceTableName(CorrelationAttributeInstance.Type type)
static String getPersonaFromInstanceTableQueryTemplate(CentralRepoAccount.CentralRepoAccountType crAccountType)
PersonaStatus getStatus()
void setComment(String comment)
void executeUpdateSQL(String sql)
PersonaStatus(int status, String description)
static Collection< PersonaAlias > getPersonaAliases(long personaId)
static final String PERSONA_QUERY
final CentralRepoExaminer examiner
static Persona createPersona(String name, String comment, PersonaStatus status)
final PersonaStatus status
void process(ResultSet resultSet)
Long getDataSourceObjectID()
void process(ResultSet resultSet)
final Collection< Persona > personaList
boolean equals(Object obj)
static PersonaStatus fromId(int value)
static Confidence fromId(int value)
CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId)
void executeInsertSQL(String sql)
static Collection< Persona > getPersonasForDataSource(CorrelationDataSource dataSource)
static Collection< Persona > getPersonaByAccountIdentifierLike(String partialName)
void process(ResultSet rs)
static CentralRepository getInstance()
Collection< PersonaMetadata > getMetadata()
static String getDefaultName()
CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId)
void removeMetadata(PersonaMetadata metadata)