19 package org.sleuthkit.datamodel;
21 import java.sql.PreparedStatement;
22 import java.sql.ResultSet;
23 import java.sql.SQLException;
24 import java.sql.Statement;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
33 import java.util.concurrent.ConcurrentHashMap;
34 import java.util.logging.Level;
35 import java.util.logging.Logger;
53 private final Map<
Account.
Type, Integer> accountTypeToTypeIdMap
54 =
new ConcurrentHashMap<>();
55 private final Map<String,
Account.
Type> typeNameToAccountTypeMap
56 =
new ConcurrentHashMap<>();
59 private static final Set<Integer> RELATIONSHIP_ARTIFACT_TYPE_IDS =
new HashSet<Integer>(Arrays.asList(
65 private static final String RELATIONSHIP_ARTIFACT_TYPE_IDS_CSV_STR = CommManagerSqlStringUtils.buildCSVString(RELATIONSHIP_ARTIFACT_TYPE_IDS);
88 try (CaseDbConnection connection = db.getConnection();
89 Statement statement = connection.createStatement();) {
91 int count = readAccountTypes();
96 statement.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + type.getTypeName() +
"', '" + type.getDisplayName() +
"')");
97 }
catch (SQLException ex) {
98 try (ResultSet resultSet = connection.executeQuery(statement,
"SELECT COUNT(*) AS count FROM account_types WHERE type_name = '" + type.getTypeName() +
"'")) {
100 if (resultSet.getLong(
"count") == 0) {
106 try (ResultSet rs2 = connection.executeQuery(statement,
"SELECT account_type_id FROM account_types WHERE type_name = '" + type.getTypeName() +
"'")) {
108 int typeID = rs2.getInt(
"account_type_id");
111 this.accountTypeToTypeIdMap.put(accountType, typeID);
112 this.typeNameToAccountTypeMap.put(type.getTypeName(), accountType);
116 }
catch (SQLException ex) {
117 LOGGER.log(Level.SEVERE,
"Failed to add row to account_types", ex);
132 CaseDbConnection connection = null;
133 Statement statement = null;
134 ResultSet resultSet = null;
139 connection = db.getConnection();
140 statement = connection.createStatement();
143 resultSet = connection.executeQuery(statement,
"SELECT COUNT(*) AS count FROM account_types");
145 if (resultSet.getLong(
"count") > 0) {
148 resultSet = connection.executeQuery(statement,
"SELECT * FROM account_types");
149 while (resultSet.next()) {
150 Account.
Type accountType =
new Account.
Type(resultSet.getString(
"type_name"), resultSet.getString(
"display_name"));
151 this.accountTypeToTypeIdMap.put(accountType, resultSet.getInt(
"account_type_id"));
152 this.typeNameToAccountTypeMap.put(accountType.getTypeName(), accountType);
154 count = this.typeNameToAccountTypeMap.size();
157 }
catch (SQLException ex) {
160 closeResultSet(resultSet);
161 closeStatement(statement);
162 closeConnection(connection);
195 if (this.accountTypeToTypeIdMap.containsKey(accountType)) {
203 s = trans.getConnection().createStatement();
204 rs = trans.getConnection().executeQuery(s,
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName +
"'");
208 s.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + accountTypeName +
"', '" + displayName +
"')");
211 rs = trans.getConnection().executeQuery(s,
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName +
"'");
214 int typeID = rs.getInt(
"account_type_id");
215 accountType =
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
217 this.accountTypeToTypeIdMap.put(accountType, typeID);
218 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
224 int typeID = rs.getInt(
"account_type_id");
226 accountType =
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
227 this.accountTypeToTypeIdMap.put(accountType, typeID);
231 }
catch (SQLException ex) {
267 Account account = getOrCreateAccount(accountType, normalizeAccountID(accountType, accountUniqueID));
275 BlackboardArtifact accountArtifact = getOrCreateAccountFileInstanceArtifact(accountType, normalizeAccountID(accountType, accountUniqueID), moduleName, sourceFile, attributes, ingestJobId);
332 try (CaseDbConnection connection = db.getConnection();
333 Statement s = connection.createStatement();
334 ResultSet rs = connection.executeQuery(s,
"SELECT * FROM accounts WHERE account_type_id = " + getAccountTypeId(accountType)
335 +
" AND account_unique_identifier = '" + normalizeAccountID(accountType, accountUniqueID) +
"'");) {
338 account =
new Account(rs.getInt(
"account_id"), accountType,
339 rs.getString(
"account_unique_identifier"));
341 }
catch (SQLException ex) {
342 throw new TskCoreException(
"Error getting account type id", ex);
376 if (sourceArtifact.getDataSourceObjectID() == null) {
377 throw new TskDataException(
"Source Artifact does not have a valid data source.");
380 if (relationshipType.isCreatableFrom(sourceArtifact) ==
false) {
381 throw new TskDataException(
"Can not make a " + relationshipType.getDisplayName()
382 +
" relationship from a" + sourceArtifact.getDisplayName());
391 List<Long> accountIDs =
new ArrayList<>();
393 if (null != sender) {
394 accountIDs.add(sender.getAccount().getAccountID());
395 if (!sender.getDataSourceObjectID().equals(sourceArtifact.getDataSourceObjectID())) {
396 throw new TskDataException(
"Sender and relationship are from different data sources :"
397 +
"Sender source ID" + sender.getDataSourceObjectID() +
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
402 accountIDs.add(recipient.getAccount().getAccountID());
403 if (!recipient.getDataSourceObjectID().equals(sourceArtifact.getDataSourceObjectID())) {
404 throw new TskDataException(
"Recipient and relationship are from different data sources :"
405 +
"Recipient source ID" + recipient.getDataSourceObjectID() +
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
410 String query =
"INTO account_relationships (account1_id, account2_id, relationship_source_obj_id, date_time, relationship_type, data_source_obj_id ) "
411 +
"VALUES (?,?,?,?,?,?)";
414 query =
"INSERT " + query +
" ON CONFLICT DO NOTHING";
417 query =
"INSERT OR IGNORE " + query;
420 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
426 PreparedStatement preparedStatement = connection.getPreparedStatement(query, Statement.NO_GENERATED_KEYS);
428 for (
int i = 0; i < accountIDs.size(); i++) {
429 for (
int j = i + 1; j < accountIDs.size(); j++) {
430 long account1_id = accountIDs.get(i);
431 long account2_id = accountIDs.get(j);
433 preparedStatement.clearParameters();
434 preparedStatement.setLong(1, account1_id);
435 preparedStatement.setLong(2, account2_id);
436 preparedStatement.setLong(3, sourceArtifact.getId());
438 preparedStatement.setLong(4, dateTime);
440 preparedStatement.setNull(4, java.sql.Types.BIGINT);
442 preparedStatement.setInt(5, relationshipType.getTypeID());
443 preparedStatement.setLong(6, sourceArtifact.getDataSourceObjectID());
445 connection.executeUpdate(preparedStatement);
449 }
catch (SQLException ex) {
451 throw new TskCoreException(
"Error adding accounts relationship", ex);
471 if (null == account) {
472 String query =
" INTO accounts (account_type_id, account_unique_identifier) "
473 +
"VALUES ( " + getAccountTypeId(accountType) +
", '"
474 + normalizeAccountID(accountType, accountUniqueID) +
"'" +
")";
477 query =
"INSERT " + query +
" ON CONFLICT DO NOTHING";
480 query =
"INSERT OR IGNORE " + query;
483 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
490 s = trans.getConnection().createStatement();
495 account =
getAccount(accountType, accountUniqueID);
496 }
catch (SQLException ex) {
498 throw new TskCoreException(
"Error adding an account", ex);
528 private BlackboardArtifact getOrCreateAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, String moduleName,
529 Content sourceFile, List<BlackboardAttribute> originalAttrs, Long ingestJobId)
throws TskCoreException {
530 if (sourceFile == null) {
531 throw new TskCoreException(
"Source file not provided.");
534 BlackboardArtifact accountArtifact = getAccountFileInstanceArtifact(accountType, accountUniqueID, sourceFile);
535 if (accountArtifact == null) {
536 List<BlackboardAttribute> attributes =
new ArrayList<>();
537 attributes.add(
new BlackboardAttribute(BlackboardAttribute.Type.TSK_ACCOUNT_TYPE, moduleName, accountType.getTypeName()));
538 attributes.add(
new BlackboardAttribute(BlackboardAttribute.Type.TSK_ID, moduleName, accountUniqueID));
539 if (originalAttrs != null) {
540 attributes.addAll(originalAttrs);
543 accountArtifact = sourceFile.newDataArtifact(ACCOUNT_TYPE, attributes);
547 }
catch (BlackboardException ex) {
548 LOGGER.log(Level.SEVERE, String.format(
"Error posting new account artifact to the blackboard (object ID = %d)", accountArtifact.getId()), ex);
551 return accountArtifact;
567 private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, Content sourceFile)
throws TskCoreException {
568 BlackboardArtifact accountArtifact = null;
570 String queryStr =
"SELECT artifacts.artifact_id AS artifact_id,"
571 +
" artifacts.obj_id AS obj_id,"
572 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
573 +
" artifacts.data_source_obj_id AS data_source_obj_id,"
574 +
" artifacts.artifact_type_id AS artifact_type_id,"
575 +
" artifacts.review_status_id AS review_status_id,"
576 +
" tsk_data_artifacts.os_account_obj_id AS os_account_obj_id"
577 +
" FROM blackboard_artifacts AS artifacts"
578 +
" JOIN blackboard_attributes AS attr_account_type"
579 +
" ON artifacts.artifact_id = attr_account_type.artifact_id"
580 +
" JOIN blackboard_attributes AS attr_account_id"
581 +
" ON artifacts.artifact_id = attr_account_id.artifact_id"
582 +
" AND attr_account_id.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID()
583 +
" AND attr_account_id.value_text = '" + accountUniqueID +
"'"
584 +
" LEFT JOIN tsk_data_artifacts ON tsk_data_artifacts.artifact_obj_id = artifacts.artifact_obj_id"
585 +
" WHERE artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()
586 +
" AND attr_account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
587 +
" AND attr_account_type.value_text = '" + accountType.getTypeName() +
"'"
588 +
" AND artifacts.obj_id = " + sourceFile.getId();
591 try (CaseDbConnection connection = db.getConnection();
592 Statement s = connection.createStatement();
593 ResultSet rs = connection.executeQuery(s, queryStr);) {
597 accountArtifact =
new DataArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"),
598 rs.getObject(
"data_source_obj_id") != null ? rs.getLong(
"data_source_obj_id") : null,
599 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
600 BlackboardArtifact.ReviewStatus.withID(rs.getInt(
"review_status_id")), rs.getLong(
"os_account_obj_id"),
false);
602 }
catch (SQLException ex) {
603 throw new TskCoreException(
"Error getting account", ex);
608 return accountArtifact;
622 if (this.typeNameToAccountTypeMap.containsKey(accountTypeName)) {
623 return this.typeNameToAccountTypeMap.get(accountTypeName);
627 try (CaseDbConnection connection = db.getConnection();
628 Statement s = connection.createStatement();
629 ResultSet rs = connection.executeQuery(s,
"SELECT account_type_id, type_name, display_name FROM account_types WHERE type_name = '" + accountTypeName +
"'");) {
632 accountType =
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
633 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
634 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
637 }
catch (SQLException ex) {
638 throw new TskCoreException(
"Error getting account type id", ex);
661 Set<String> applicableInnerQueryFilters =
new HashSet<String>(Arrays.asList(
666 String relationshipFilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
668 String relationshipLimitSQL = getMostRecentFilterLimitSQL(filter);
670 String relTblfilterQuery
672 +
"FROM account_relationships as relationships"
673 + (relationshipFilterSQL.isEmpty() ?
"" :
" WHERE " + relationshipFilterSQL)
674 + (relationshipLimitSQL.isEmpty() ?
"" : relationshipLimitSQL);
676 String uniqueAccountQueryTemplate
677 =
" SELECT %1$1s as account_id,"
678 +
" data_source_obj_id"
679 +
" FROM ( " + relTblfilterQuery +
")AS %2$s";
681 String relationshipTableFilterQuery1 = String.format(uniqueAccountQueryTemplate,
"account1_id",
"union_query_1");
682 String relationshipTableFilterQuery2 = String.format(uniqueAccountQueryTemplate,
"account2_id",
"union_query_2");
685 String uniqueAccountQuery
686 =
"SELECT DISTINCT account_id, data_source_obj_id"
687 +
" FROM ( " + relationshipTableFilterQuery1 +
" UNION " + relationshipTableFilterQuery2 +
" ) AS inner_union"
688 +
" GROUP BY account_id, data_source_obj_id";
691 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
695 String accountTypeFilterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
699 " accounts.account_id AS account_id,"
700 +
" accounts.account_unique_identifier AS account_unique_identifier,"
702 +
" account_types.type_name AS type_name,"
704 +
" data_source_info.device_id AS device_id"
705 +
" FROM ( " + uniqueAccountQuery +
" ) AS account_device_instances"
706 +
" JOIN accounts AS accounts"
707 +
" ON accounts.account_id = account_device_instances.account_id"
708 +
" JOIN account_types AS account_types"
709 +
" ON accounts.account_type_id = account_types.account_type_id"
710 +
" JOIN data_source_info AS data_source_info"
711 +
" ON account_device_instances.data_source_obj_id = data_source_info.obj_id"
712 + (accountTypeFilterSQL.isEmpty() ?
"" :
" WHERE " + accountTypeFilterSQL);
716 queryStr =
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
719 queryStr =
"SELECT " + queryStr +
" GROUP BY accounts.account_id, data_source_info.device_id";
722 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
726 try (CaseDbConnection connection = db.getConnection();
727 Statement s = connection.createStatement();
728 ResultSet rs = connection.executeQuery(s, queryStr);) {
729 ArrayList<AccountDeviceInstance> accountDeviceInstances =
new ArrayList<AccountDeviceInstance>();
731 long account_id = rs.getLong(
"account_id");
732 String deviceID = rs.getString(
"device_id");
733 final String type_name = rs.getString(
"type_name");
734 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
736 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
737 Account account =
new Account(account_id, accountType, account_unique_identifier);
741 return accountDeviceInstances;
742 }
catch (SQLException ex) {
743 throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
770 Set<Long> accountIDs =
new HashSet<Long>();
771 Set<String> accountDeviceIDs =
new HashSet<String>();
773 accountIDs.add(adi.getAccount().getAccountID());
774 accountDeviceIDs.add(
"'" + adi.getDeviceId() +
"'");
777 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
783 String accountIDsCSL = CommManagerSqlStringUtils.buildCSVString(accountIDs);
784 String accountDeviceIDsCSL = CommManagerSqlStringUtils.buildCSVString(accountDeviceIDs);
785 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
787 final String queryString
788 =
" SELECT count(DISTINCT relationships.relationship_source_obj_id) AS count,"
789 +
" data_source_info.device_id AS device_id,"
791 +
" accounts1.account_id AS account1_id,"
792 +
" accounts1.account_unique_identifier AS account1_unique_identifier,"
793 +
" account_types1.type_name AS type_name1,"
794 +
" account_types1.display_name AS display_name1,"
796 +
" accounts2.account_id AS account2_id,"
797 +
" accounts2.account_unique_identifier AS account2_unique_identifier,"
798 +
" account_types2.type_name AS type_name2,"
799 +
" account_types2.display_name AS display_name2"
800 +
" FROM account_relationships AS relationships"
801 +
" JOIN data_source_info AS data_source_info"
802 +
" ON relationships.data_source_obj_id = data_source_info.obj_id "
804 +
" JOIN accounts AS accounts1 "
805 +
" ON accounts1.account_id = relationships.account1_id"
806 +
" JOIN account_types AS account_types1"
807 +
" ON accounts1.account_type_id = account_types1.account_type_id"
809 +
" JOIN accounts AS accounts2 "
810 +
" ON accounts2.account_id = relationships.account2_id"
811 +
" JOIN account_types AS account_types2"
812 +
" ON accounts2.account_type_id = account_types2.account_type_id"
813 +
" WHERE (( relationships.account1_id IN (" + accountIDsCSL +
")) "
814 +
" AND ( relationships.account2_id IN ( " + accountIDsCSL +
" ))"
815 +
" AND ( data_source_info.device_id IN (" + accountDeviceIDsCSL +
"))) "
816 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL)
817 +
" GROUP BY data_source_info.device_id, "
818 +
" accounts1.account_id, "
819 +
" account_types1.type_name, "
820 +
" account_types1.display_name, "
821 +
" accounts2.account_id, "
822 +
" account_types2.type_name, "
823 +
" account_types2.display_name";
825 Map<AccountPair, Long> results =
new HashMap<AccountPair, Long>();
828 try (CaseDbConnection connection = db.getConnection();
829 Statement s = connection.createStatement();
830 ResultSet rs = connection.executeQuery(s, queryString);) {
836 rs.getString(
"account1_unique_identifier")),
837 rs.getString(
"device_id"));
842 rs.getString(
"account2_unique_identifier")),
843 rs.getString(
"device_id"));
846 long count = rs.getLong(
"count");
849 Long oldCount = results.get(relationshipKey);
850 if (oldCount != null) {
853 results.put(relationshipKey, count);
856 }
catch (SQLException ex) {
857 throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
880 long account_id = accountDeviceInstance.getAccount().
getAccountID();
883 String datasourceObjIdsCSV = CommManagerSqlStringUtils.buildCSVString(
884 db.getDataSourceObjIds(accountDeviceInstance.getDeviceId()));
887 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
891 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
893 String innerQuery =
" account_relationships AS relationships";
894 String limitStr = getMostRecentFilterLimitSQL(filter);
896 if (!limitStr.isEmpty()) {
897 innerQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
901 =
"SELECT count(DISTINCT relationships.relationship_source_obj_id) as count "
902 +
" FROM" + innerQuery
903 +
" WHERE relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV +
" )"
904 +
" AND ( relationships.account1_id = " + account_id
905 +
" OR relationships.account2_id = " + account_id +
" )"
906 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL);
909 try (CaseDbConnection connection = db.getConnection();
910 Statement s = connection.createStatement();
911 ResultSet rs = connection.executeQuery(s, queryStr);) {
913 return (rs.getLong(
"count"));
914 }
catch (SQLException ex) {
915 throw new TskCoreException(
"Error getting relationships count for account device instance. " + ex.getMessage(), ex);
939 if (accountDeviceInstanceList.isEmpty()) {
940 LOGGER.log(Level.WARNING,
"Empty accountDeviceInstanceList passed to getRelationshipSources");
941 return Collections.emptySet();
946 Map<Long, Set<Long>> accountIdToDatasourceObjIdMap =
new HashMap<>();
948 long accountID = accountDeviceInstance.getAccount().
getAccountID();
949 List<Long> dataSourceObjIds = db.getDataSourceObjIds(accountDeviceInstance.getDeviceId());
951 if (accountIdToDatasourceObjIdMap.containsKey(accountID)) {
952 accountIdToDatasourceObjIdMap.get(accountID).addAll(dataSourceObjIds);
954 accountIdToDatasourceObjIdMap.put(accountID,
new HashSet<>(dataSourceObjIds));
959 List<String> adiSQLClauses =
new ArrayList<>();
960 for (Map.Entry<Long, Set<Long>> entry : accountIdToDatasourceObjIdMap.entrySet()) {
961 final Long accountID = entry.getKey();
962 String datasourceObjIdsCSV = CommManagerSqlStringUtils.buildCSVString(entry.getValue());
966 + (!datasourceObjIdsCSV.isEmpty() ?
"( relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV +
" ) ) AND" :
"")
967 +
" ( relationships.account1_id = " + accountID
968 +
" OR relationships.account2_id = " + accountID +
" ) )"
971 String adiSQLClause = CommManagerSqlStringUtils.joinAsStrings(adiSQLClauses,
" OR ");
973 if(adiSQLClause.isEmpty()) {
974 LOGGER.log(Level.SEVERE,
"There set of AccountDeviceInstances had no valid data source ids.");
975 return Collections.emptySet();
979 Set<String> applicableFilters =
new HashSet<>(Arrays.asList(
985 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
988 String limitQuery =
" account_relationships AS relationships";
992 String limitStr = getMostRecentFilterLimitSQL(filter);
993 if (!limitStr.isEmpty()) {
994 limitQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
998 =
"SELECT DISTINCT artifacts.artifact_id AS artifact_id,"
999 +
" artifacts.obj_id AS obj_id,"
1000 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
1001 +
" artifacts.data_source_obj_id AS data_source_obj_id, "
1002 +
" artifacts.artifact_type_id AS artifact_type_id, "
1003 +
" artifacts.review_status_id AS review_status_id,"
1004 +
" tsk_data_artifacts.os_account_obj_id as os_account_obj_id"
1005 +
" FROM blackboard_artifacts as artifacts"
1006 +
" JOIN " + limitQuery
1007 +
" ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id"
1008 +
" LEFT JOIN tsk_data_artifacts ON artifacts.artifact_obj_id = tsk_data_artifacts.artifact_obj_id"
1010 +
" WHERE (" + adiSQLClause +
" )"
1012 + (filterSQL.isEmpty() ?
"" :
" AND (" + filterSQL +
" )");
1015 try (CaseDbConnection connection = db.getConnection();
1016 Statement s = connection.createStatement();
1017 ResultSet rs = connection.executeQuery(s, queryStr);) {
1018 Set<Content> relationshipSources =
new HashSet<>();
1019 relationshipSources.addAll(getDataArtifactsFromResult(rs));
1020 return relationshipSources;
1021 }
catch (SQLException ex) {
1022 throw new TskCoreException(
"Error getting relationships for account. " + ex.getMessage(), ex);
1044 final List<Long> dataSourceObjIds
1045 = getSleuthkitCase().getDataSourceObjIds(accountDeviceInstance.getDeviceId());
1048 Set<String> applicableInnerQueryFilters =
new HashSet<String>(Arrays.asList(
1054 String innerQueryfilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
1056 String innerQueryTemplate
1057 =
" SELECT %1$1s as account_id,"
1058 +
" data_source_obj_id"
1059 +
" FROM account_relationships as relationships"
1060 +
" WHERE %2$1s = " + accountDeviceInstance.getAccount().getAccountID() +
""
1061 +
" AND data_source_obj_id IN (" + CommManagerSqlStringUtils.buildCSVString(dataSourceObjIds) +
")"
1062 + (innerQueryfilterSQL.isEmpty() ?
"" :
" AND " + innerQueryfilterSQL);
1064 String innerQuery1 = String.format(innerQueryTemplate,
"account1_id",
"account2_id");
1065 String innerQuery2 = String.format(innerQueryTemplate,
"account2_id",
"account1_id");
1068 String combinedInnerQuery
1069 =
"SELECT account_id, data_source_obj_id "
1070 +
" FROM ( " + innerQuery1 +
" UNION " + innerQuery2 +
" ) AS inner_union"
1071 +
" GROUP BY account_id, data_source_obj_id";
1074 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
1078 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
1082 " accounts.account_id AS account_id,"
1083 +
" accounts.account_unique_identifier AS account_unique_identifier,"
1085 +
" account_types.type_name AS type_name,"
1087 +
" data_source_info.device_id AS device_id"
1088 +
" FROM ( " + combinedInnerQuery +
" ) AS account_device_instances"
1089 +
" JOIN accounts AS accounts"
1090 +
" ON accounts.account_id = account_device_instances.account_id"
1091 +
" JOIN account_types AS account_types"
1092 +
" ON accounts.account_type_id = account_types.account_type_id"
1093 +
" JOIN data_source_info AS data_source_info"
1094 +
" ON account_device_instances.data_source_obj_id = data_source_info.obj_id"
1095 + (filterSQL.isEmpty() ?
"" :
" WHERE " + filterSQL);
1099 queryStr =
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
1102 queryStr =
"SELECT " + queryStr +
" GROUP BY accounts.account_id, data_source_info.device_id";
1105 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
1109 try (CaseDbConnection connection = db.getConnection();
1110 Statement s = connection.createStatement();
1111 ResultSet rs = connection.executeQuery(s, queryStr);) {
1112 ArrayList<AccountDeviceInstance> accountDeviceInstances =
new ArrayList<AccountDeviceInstance>();
1114 long account_id = rs.getLong(
"account_id");
1115 String deviceID = rs.getString(
"device_id");
1116 final String type_name = rs.getString(
"type_name");
1117 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
1119 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
1120 Account account =
new Account(account_id, accountType, account_unique_identifier);
1124 return accountDeviceInstances;
1125 }
catch (SQLException ex) {
1126 throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
1151 Set<String> applicableFilters =
new HashSet<>(Arrays.asList(
1157 String limitQuery =
" account_relationships AS relationships";
1158 String limitStr = getMostRecentFilterLimitSQL(filter);
1159 if (!limitStr.isEmpty()) {
1160 limitQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
1163 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
1164 final String queryString =
"SELECT artifacts.artifact_id AS artifact_id,"
1165 +
" artifacts.obj_id AS obj_id,"
1166 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
1167 +
" artifacts.data_source_obj_id AS data_source_obj_id,"
1168 +
" artifacts.artifact_type_id AS artifact_type_id,"
1169 +
" artifacts.review_status_id AS review_status_id,"
1170 +
" tsk_data_artifacts.os_account_obj_id AS os_account_obj_id"
1171 +
" FROM blackboard_artifacts AS artifacts"
1172 +
" JOIN " + limitQuery
1173 +
" ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id"
1174 +
" LEFT JOIN tsk_data_artifacts ON artifacts.artifact_obj_id = tsk_data_artifacts.artifact_obj_id"
1175 +
" WHERE (( relationships.account1_id = " + account1.getAccount().getAccountID()
1176 +
" AND relationships.account2_id = " + account2.getAccount().getAccountID()
1177 +
" ) OR ( relationships.account2_id = " + account1.getAccount().getAccountID()
1178 +
" AND relationships.account1_id =" + account2.getAccount().getAccountID() +
" ))"
1179 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL);
1182 try (CaseDbConnection connection = db.getConnection();
1183 Statement s = connection.createStatement();
1184 ResultSet rs = connection.executeQuery(s, queryString);) {
1186 ArrayList<Content> artifacts =
new ArrayList<>();
1187 artifacts.addAll(getDataArtifactsFromResult(rs));
1189 }
catch (SQLException ex) {
1190 throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
1207 List<AccountFileInstance> accountFileInstanceList =
new ArrayList<>();
1208 @SuppressWarnings(
"deprecation")
1211 if (artifactList != null && !artifactList.isEmpty()) {
1217 if (!accountFileInstanceList.isEmpty()) {
1218 return accountFileInstanceList;
1234 String query =
"SELECT DISTINCT accounts.account_type_id, type_name, display_name FROM accounts JOIN account_types ON accounts.account_type_id = account_types.account_type_id";
1235 List<
Account.
Type> inUseAccounts =
new ArrayList<>();
1238 try (CaseDbConnection connection = db.getConnection();
1239 Statement s = connection.createStatement();
1240 ResultSet rs = connection.executeQuery(s, query);) {
1243 String accountTypeName = rs.getString(
"type_name");
1244 accountType = this.typeNameToAccountTypeMap.get(accountTypeName);
1246 if (accountType == null) {
1247 accountType =
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
1248 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
1251 inUseAccounts.add(accountType);
1253 return inUseAccounts;
1254 }
catch (SQLException ex) {
1255 throw new TskCoreException(
"Error getting account type id", ex);
1271 if (artifact == null) {
1272 throw new IllegalArgumentException(
"null arugment passed to getAccountsRelatedToArtifact");
1275 List<Account> accountList =
new ArrayList<>();
1277 try (CaseDbConnection connection = db.getConnection()) {
1283 String query = String.format(
"SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1285 +
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1287 +
" JOIN account_relationships ON account1_id = account_id"
1288 +
" WHERE relationship_source_obj_id = %d"
1290 +
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1292 +
" JOIN account_relationships ON account2_id = account_id"
1293 +
" WHERE relationship_source_obj_id = %d) AS unionOfRelationships", artifact.getId(), artifact.getId());
1294 try (Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(query)) {
1297 int accountTypeId = rs.getInt(
"account_type_id");
1298 for (Map.Entry<
Account.
Type, Integer> entry : accountTypeToTypeIdMap.entrySet()) {
1299 if (entry.getValue() == accountTypeId) {
1300 accountType = entry.getKey();
1305 accountList.add(
new Account(rs.getInt(
"account_id"), accountType, rs.getString(
"account_unique_identifier")));
1307 }
catch (SQLException ex) {
1308 throw new TskCoreException(
"Unable to get account list for give artifact " + artifact.getId(), ex);
1327 if (accountTypeToTypeIdMap.containsKey(accountType)) {
1328 return accountTypeToTypeIdMap.get(accountType);
1345 private String normalizeAccountID(Account.Type accountType, String accountUniqueID)
throws InvalidAccountIDException {
1347 if (accountUniqueID == null || accountUniqueID.isEmpty()) {
1348 throw new InvalidAccountIDException(
"Account id is null or empty.");
1351 String normalizedAccountID;
1352 if (accountType.equals(Account.Type.PHONE)) {
1353 normalizedAccountID = CommunicationsUtils.normalizePhoneNum(accountUniqueID);
1354 }
else if (accountType.equals(Account.Type.EMAIL)) {
1355 normalizedAccountID = CommunicationsUtils.normalizeEmailAddress(accountUniqueID);
1357 normalizedAccountID = accountUniqueID.toLowerCase().trim();
1360 return normalizedAccountID;
1375 private String getCommunicationsFilterSQL(CommunicationsFilter commFilter, Set<String> applicableFilters) {
1376 if (null == commFilter || commFilter.getAndFilters().isEmpty()) {
1381 StringBuilder sqlSB =
new StringBuilder();
1382 boolean first =
true;
1383 for (CommunicationsFilter.SubFilter subFilter : commFilter.getAndFilters()) {
1386 if (applicableFilters.contains(subFilter.getClass().getName())) {
1387 String subfilterSQL = subFilter.getSQL(
this);
1388 if (!subfilterSQL.isEmpty()) {
1392 sqlSB.append(
" AND ");
1395 sqlSB.append(subfilterSQL);
1401 if (!sqlSB.toString().isEmpty()) {
1402 sqlStr =
"( " + sqlSB.toString() +
" )";
1415 private String getMostRecentFilterLimitSQL(CommunicationsFilter filter) {
1416 String limitStr =
"";
1418 if (filter != null && !filter.getAndFilters().isEmpty()) {
1420 for (CommunicationsFilter.SubFilter subFilter : filter.getAndFilters()) {
1421 if (subFilter.getClass().getName().equals(CommunicationsFilter.MostRecentFilter.class.getName())) {
1422 limitStr = subFilter.getSQL(
this);
1442 private List<BlackboardArtifact> getDataArtifactsFromResult(ResultSet resultSet)
throws SQLException, TskCoreException {
1443 List<BlackboardArtifact> artifacts =
new ArrayList<>();
1444 while (resultSet.next()) {
1446 artifacts.add(
new DataArtifact(db, resultSet.getLong(
"artifact_id"),
1447 resultSet.getLong(
"obj_id"), resultSet.getLong(
"artifact_obj_id"),
1448 resultSet.getObject(
"data_source_obj_id") != null ? resultSet.getLong(
"data_source_obj_id") : null,
1449 bbartType.getTypeID(),
1450 bbartType.getTypeName(), bbartType.getDisplayName(),
1451 BlackboardArtifact.ReviewStatus.withID(resultSet.getInt(
"review_status_id")),
1452 resultSet.getLong(
"os_account_obj_id"),
false));
Set< Content > getRelationshipSources(Set< AccountDeviceInstance > accountDeviceInstanceList, CommunicationsFilter filter)
void postArtifact(BlackboardArtifact artifact, String moduleName)
CaseDbTransaction beginTransaction()
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
Blackboard getBlackboard()
List< AccountDeviceInstance > getRelatedAccountDeviceInstances(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter)
org.sleuthkit.datamodel.Account.Type getAccountType(String accountTypeName)
AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile)
org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeName, String displayName)
List< Account > getAccountsRelatedToArtifact(BlackboardArtifact artifact)
String getTypeSpecificID()
Map< AccountPair, Long > getRelationshipCountsPairwise(Set< AccountDeviceInstance > accounts, CommunicationsFilter filter)
void releaseSingleUserCaseReadLock()
List< Account.Type > getAccountTypesInUse()
static final List< Account.Type > PREDEFINED_ACCOUNT_TYPES
BlackboardArtifact.Type getArtifactType(String artTypeName)
void acquireSingleUserCaseWriteLock()
void releaseSingleUserCaseWriteLock()
List< Content > getRelationshipSources(AccountDeviceInstance account1, AccountDeviceInstance account2, CommunicationsFilter filter)
long getRelationshipSourcesCount(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter)
AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile, List< BlackboardAttribute > attributes, Long ingestJobId)
void acquireSingleUserCaseReadLock()
List< AccountDeviceInstance > getAccountDeviceInstancesWithRelationships(CommunicationsFilter filter)
void addRelationships(AccountFileInstance sender, List< AccountFileInstance > recipients, BlackboardArtifact sourceArtifact, org.sleuthkit.datamodel.Relationship.Type relationshipType, long dateTime)
Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID)
List< AccountFileInstance > getAccountFileInstances(Account account)