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.Collection;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.List;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.logging.Level;
36 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 = StringUtils.buildCSVString(RELATIONSHIP_ARTIFACT_TYPE_IDS);
87 CaseDbConnection connection = db.getConnection();
89 Statement statement = null;
90 ResultSet resultSet = null;
93 statement = connection.createStatement();
95 int count = readAccountTypes();
100 statement.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + type.getTypeName() +
"', '" + type.getDisplayName() +
"')");
101 }
catch (SQLException ex) {
102 resultSet = connection.executeQuery(statement,
"SELECT COUNT(*) AS count FROM account_types WHERE type_name = '" + type.getTypeName() +
"'");
104 if (resultSet.getLong(
"count") == 0) {
110 ResultSet rs2 = connection.executeQuery(statement,
"SELECT account_type_id FROM account_types WHERE type_name = '" + type.getTypeName() +
"'");
112 int typeID = rs2.getInt(
"account_type_id");
116 this.accountTypeToTypeIdMap.put(accountType, typeID);
117 this.typeNameToAccountTypeMap.put(type.getTypeName(), accountType);
120 }
catch (SQLException ex) {
121 LOGGER.log(Level.SEVERE,
"Failed to add row to account_types", ex);
123 closeResultSet(resultSet);
124 closeStatement(statement);
139 CaseDbConnection connection = db.getConnection();
141 Statement statement = null;
142 ResultSet resultSet = null;
146 statement = connection.createStatement();
149 resultSet = connection.executeQuery(statement,
"SELECT COUNT(*) AS count FROM account_types");
151 if (resultSet.getLong(
"count") > 0) {
154 resultSet = connection.executeQuery(statement,
"SELECT * FROM account_types");
155 while (resultSet.next()) {
156 Account.
Type accountType =
new Account.
Type(resultSet.getString(
"type_name"), resultSet.getString(
"display_name"));
157 this.accountTypeToTypeIdMap.put(accountType, resultSet.getInt(
"account_type_id"));
158 this.typeNameToAccountTypeMap.put(accountType.getTypeName(), accountType);
160 count = this.typeNameToAccountTypeMap.size();
163 }
catch (SQLException ex) {
166 closeResultSet(resultSet);
167 closeStatement(statement);
201 if (this.accountTypeToTypeIdMap.containsKey(accountType)) {
205 CaseDbConnection connection = db.getConnection();
210 connection.beginTransaction();
211 s = connection.createStatement();
212 rs = connection.executeQuery(s,
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName +
"'");
216 s.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + accountTypeName +
"', '" + displayName +
"')");
219 rs = connection.executeQuery(s,
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName +
"'");
222 int typeID = rs.getInt(
"account_type_id");
223 accountType =
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
225 this.accountTypeToTypeIdMap.put(accountType, typeID);
226 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
228 connection.commitTransaction();
232 int typeID = rs.getInt(
"account_type_id");
234 accountType =
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
235 this.accountTypeToTypeIdMap.put(accountType, typeID);
239 }
catch (SQLException ex) {
240 connection.rollbackTransaction();
272 Account account = getOrCreateAccount(accountType, normalizeAccountID(accountType, accountUniqueID));
280 BlackboardArtifact accountArtifact = getOrCreateAccountFileInstanceArtifact(accountType, normalizeAccountID(accountType, accountUniqueID), moduleName, sourceFile);
307 CaseDbConnection connection = db.getConnection();
312 s = connection.createStatement();
313 rs = connection.executeQuery(s,
"SELECT * FROM accounts WHERE account_type_id = " + getAccountTypeId(accountType)
314 +
" AND account_unique_identifier = '" + normalizeAccountID(accountType, accountUniqueID) +
"'");
317 account =
new Account(rs.getInt(
"account_id"), accountType,
318 rs.getString(
"account_unique_identifier"));
320 }
catch (SQLException ex) {
321 throw new TskCoreException(
"Error getting account type id", ex);
358 if (relationshipType.isCreatableFrom(sourceArtifact) ==
false) {
359 throw new TskDataException(
"Can not make a " + relationshipType.getDisplayName()
360 +
" relationship from a" + sourceArtifact.getDisplayName());
369 List<Long> accountIDs =
new ArrayList<>();
371 if (null != sender) {
372 accountIDs.add(sender.getAccount().getAccountID());
373 if (sender.getDataSourceObjectID() != sourceArtifact.getDataSourceObjectID()) {
374 throw new TskDataException(
"Sender and relationship are from different data sources :"
375 +
"Sender source ID" + sender.getDataSourceObjectID() +
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
380 accountIDs.add(recipient.getAccount().getAccountID());
381 if (recipient.getDataSourceObjectID() != sourceArtifact.getDataSourceObjectID()) {
382 throw new TskDataException(
"Recipient and relationship are from different data sources :"
383 +
"Recipient source ID" + recipient.getDataSourceObjectID() +
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
388 String query =
"INTO account_relationships (account1_id, account2_id, relationship_source_obj_id, date_time, relationship_type, data_source_obj_id ) "
389 +
"VALUES (?,?,?,?,?,?)";
392 query =
"INSERT " + query +
" ON CONFLICT DO NOTHING";
395 query =
"INSERT OR IGNORE " + query;
398 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
404 PreparedStatement preparedStatement = connection.getPreparedStatement(query, Statement.NO_GENERATED_KEYS);
406 for (
int i = 0; i < accountIDs.size(); i++) {
407 for (
int j = i + 1; j < accountIDs.size(); j++) {
408 long account1_id = accountIDs.get(i);
409 long account2_id = accountIDs.get(j);
411 preparedStatement.clearParameters();
412 preparedStatement.setLong(1, account1_id);
413 preparedStatement.setLong(2, account2_id);
414 preparedStatement.setLong(3, sourceArtifact.getId());
416 preparedStatement.setLong(4, dateTime);
418 preparedStatement.setNull(4, java.sql.Types.BIGINT);
420 preparedStatement.setInt(5, relationshipType.getTypeID());
421 preparedStatement.setLong(6, sourceArtifact.getDataSourceObjectID());
423 connection.executeUpdate(preparedStatement);
427 }
catch (SQLException ex) {
429 throw new TskCoreException(
"Error adding accounts relationship", ex);
449 if (null == account) {
450 String query =
" INTO accounts (account_type_id, account_unique_identifier) "
451 +
"VALUES ( " + getAccountTypeId(accountType) +
", '"
452 + normalizeAccountID(accountType, accountUniqueID) +
"'" +
")";
455 query =
"INSERT " + query +
" ON CONFLICT DO NOTHING";
458 query =
"INSERT OR IGNORE " + query;
461 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
464 CaseDbConnection connection = db.getConnection();
469 connection.beginTransaction();
470 s = connection.createStatement();
474 connection.commitTransaction();
475 account =
getAccount(accountType, accountUniqueID);
476 }
catch (SQLException ex) {
477 connection.rollbackTransaction();
478 throw new TskCoreException(
"Error adding an account", ex);
507 private BlackboardArtifact getOrCreateAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile)
throws TskCoreException {
508 BlackboardArtifact accountArtifact = getAccountFileInstanceArtifact(accountType, accountUniqueID, sourceFile);
509 if (accountArtifact == null) {
510 accountArtifact = db.
newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT, sourceFile.getId());
511 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
512 attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, moduleName, accountType.getTypeName()));
513 attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID, moduleName, accountUniqueID));
517 }
catch (BlackboardException ex) {
518 LOGGER.log(Level.SEVERE, String.format(
"Error posting new account artifact to the blackboard (object ID = %d)", accountArtifact.getId()), ex);
521 return accountArtifact;
537 private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, Content sourceFile)
throws TskCoreException {
538 BlackboardArtifact accountArtifact = null;
539 CaseDbConnection connection = db.getConnection();
545 s = connection.createStatement();
546 String queryStr =
"SELECT artifacts.artifact_id AS artifact_id,"
547 +
" artifacts.obj_id AS obj_id,"
548 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
549 +
" artifacts.data_source_obj_id AS data_source_obj_id,"
550 +
" artifacts.artifact_type_id AS artifact_type_id,"
551 +
" artifacts.review_status_id AS review_status_id"
552 +
" FROM blackboard_artifacts AS artifacts"
553 +
" JOIN blackboard_attributes AS attr_account_type"
554 +
" ON artifacts.artifact_id = attr_account_type.artifact_id"
555 +
" JOIN blackboard_attributes AS attr_account_id"
556 +
" ON artifacts.artifact_id = attr_account_id.artifact_id"
557 +
" AND attr_account_id.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID()
558 +
" AND attr_account_id.value_text = '" + accountUniqueID +
"'"
559 +
" WHERE artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()
560 +
" AND attr_account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
561 +
" AND attr_account_type.value_text = '" + accountType.getTypeName() +
"'"
562 +
" AND artifacts.obj_id = " + sourceFile.getId();
564 rs = connection.executeQuery(s, queryStr);
566 BlackboardArtifact.Type bbartType = db.
getArtifactType(rs.getInt(
"artifact_type_id"));
568 accountArtifact =
new BlackboardArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"), rs.getLong(
"data_source_obj_id"),
569 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
570 BlackboardArtifact.ReviewStatus.withID(rs.getInt(
"review_status_id")));
572 }
catch (SQLException ex) {
573 throw new TskCoreException(
"Error getting account", ex);
581 return accountArtifact;
595 if (this.typeNameToAccountTypeMap.containsKey(accountTypeName)) {
596 return this.typeNameToAccountTypeMap.get(accountTypeName);
599 CaseDbConnection connection = db.getConnection();
605 s = connection.createStatement();
606 rs = connection.executeQuery(s,
"SELECT account_type_id, type_name, display_name FROM account_types WHERE type_name = '" + accountTypeName +
"'");
609 accountType =
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
610 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
611 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
614 }
catch (SQLException ex) {
615 throw new TskCoreException(
"Error getting account type id", ex);
639 CaseDbConnection connection = db.getConnection();
645 s = connection.createStatement();
648 Set<String> applicableInnerQueryFilters =
new HashSet<String>(Arrays.asList(
653 String relationshipFilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
655 String relationshipLimitSQL = getMostRecentFilterLimitSQL(filter);
657 String relTblfilterQuery
659 +
"FROM account_relationships as relationships"
660 + (relationshipFilterSQL.isEmpty() ?
"" :
" WHERE " + relationshipFilterSQL)
661 + (relationshipLimitSQL.isEmpty() ?
"" : relationshipLimitSQL);
663 String uniqueAccountQueryTemplate
664 =
" SELECT %1$1s as account_id,"
665 +
" data_source_obj_id"
666 +
" FROM ( " + relTblfilterQuery +
")AS %2$s";
668 String relationshipTableFilterQuery1 = String.format(uniqueAccountQueryTemplate,
"account1_id",
"union_query_1");
669 String relationshipTableFilterQuery2 = String.format(uniqueAccountQueryTemplate,
"account2_id",
"union_query_2");
672 String uniqueAccountQuery
673 =
"SELECT DISTINCT account_id, data_source_obj_id"
674 +
" FROM ( " + relationshipTableFilterQuery1 +
" UNION " + relationshipTableFilterQuery2 +
" ) AS inner_union"
675 +
" GROUP BY account_id, data_source_obj_id";
678 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
682 String accountTypeFilterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
686 " accounts.account_id AS account_id,"
687 +
" accounts.account_unique_identifier AS account_unique_identifier,"
689 +
" account_types.type_name AS type_name,"
691 +
" data_source_info.device_id AS device_id"
692 +
" FROM ( " + uniqueAccountQuery +
" ) AS account_device_instances"
693 +
" JOIN accounts AS accounts"
694 +
" ON accounts.account_id = account_device_instances.account_id"
695 +
" JOIN account_types AS account_types"
696 +
" ON accounts.account_type_id = account_types.account_type_id"
697 +
" JOIN data_source_info AS data_source_info"
698 +
" ON account_device_instances.data_source_obj_id = data_source_info.obj_id"
699 + (accountTypeFilterSQL.isEmpty() ?
"" :
" WHERE " + accountTypeFilterSQL);
703 queryStr =
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
706 queryStr =
"SELECT " + queryStr +
" GROUP BY accounts.account_id, data_source_info.device_id";
709 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
712 rs = connection.executeQuery(s, queryStr);
713 ArrayList<AccountDeviceInstance> accountDeviceInstances =
new ArrayList<AccountDeviceInstance>();
715 long account_id = rs.getLong(
"account_id");
716 String deviceID = rs.getString(
"device_id");
717 final String type_name = rs.getString(
"type_name");
718 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
720 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
721 Account account =
new Account(account_id, accountType, account_unique_identifier);
725 return accountDeviceInstances;
726 }
catch (SQLException ex) {
727 throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
757 Set<Long> accountIDs =
new HashSet<Long>();
758 Set<String> accountDeviceIDs =
new HashSet<String>();
760 accountIDs.add(adi.getAccount().getAccountID());
761 accountDeviceIDs.add(
"'" + adi.getDeviceId() +
"'");
764 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
770 String accountIDsCSL = StringUtils.buildCSVString(accountIDs);
771 String accountDeviceIDsCSL = StringUtils.buildCSVString(accountDeviceIDs);
772 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
774 final String queryString
775 =
" SELECT count(DISTINCT relationships.relationship_source_obj_id) AS count,"
776 +
" data_source_info.device_id AS device_id,"
778 +
" accounts1.account_id AS account1_id,"
779 +
" accounts1.account_unique_identifier AS account1_unique_identifier,"
780 +
" account_types1.type_name AS type_name1,"
781 +
" account_types1.display_name AS display_name1,"
783 +
" accounts2.account_id AS account2_id,"
784 +
" accounts2.account_unique_identifier AS account2_unique_identifier,"
785 +
" account_types2.type_name AS type_name2,"
786 +
" account_types2.display_name AS display_name2"
787 +
" FROM account_relationships AS relationships"
788 +
" JOIN data_source_info AS data_source_info"
789 +
" ON relationships.data_source_obj_id = data_source_info.obj_id "
791 +
" JOIN accounts AS accounts1 "
792 +
" ON accounts1.account_id = relationships.account1_id"
793 +
" JOIN account_types AS account_types1"
794 +
" ON accounts1.account_type_id = account_types1.account_type_id"
796 +
" JOIN accounts AS accounts2 "
797 +
" ON accounts2.account_id = relationships.account2_id"
798 +
" JOIN account_types AS account_types2"
799 +
" ON accounts2.account_type_id = account_types2.account_type_id"
800 +
" WHERE (( relationships.account1_id IN (" + accountIDsCSL +
")) "
801 +
" AND ( relationships.account2_id IN ( " + accountIDsCSL +
" ))"
802 +
" AND ( data_source_info.device_id IN (" + accountDeviceIDsCSL +
"))) "
803 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL)
804 +
" GROUP BY data_source_info.device_id, "
805 +
" accounts1.account_id, "
806 +
" account_types1.type_name, "
807 +
" account_types1.display_name, "
808 +
" accounts2.account_id, "
809 +
" account_types2.type_name, "
810 +
" account_types2.display_name";
811 CaseDbConnection connection = db.getConnection();
816 Map<AccountPair, Long> results =
new HashMap<AccountPair, Long>();
819 s = connection.createStatement();
820 rs = connection.executeQuery(s, queryString);
826 rs.getString(
"account1_unique_identifier")),
827 rs.getString(
"device_id"));
832 rs.getString(
"account2_unique_identifier")),
833 rs.getString(
"device_id"));
836 long count = rs.getLong(
"count");
839 Long oldCount = results.get(relationshipKey);
840 if (oldCount != null) {
843 results.put(relationshipKey, count);
846 }
catch (SQLException ex) {
847 throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
873 long account_id = accountDeviceInstance.getAccount().
getAccountID();
876 String datasourceObjIdsCSV = StringUtils.buildCSVString(
877 db.getDataSourceObjIds(accountDeviceInstance.getDeviceId()));
880 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
884 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
886 CaseDbConnection connection = db.getConnection();
892 s = connection.createStatement();
894 String innerQuery =
" account_relationships AS relationships";
895 String limitStr = getMostRecentFilterLimitSQL(filter);
897 if (!limitStr.isEmpty()) {
898 innerQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
902 =
"SELECT count(DISTINCT relationships.relationship_source_obj_id) as count "
903 +
" FROM" + innerQuery
904 +
" WHERE relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV +
" )"
905 +
" AND ( relationships.account1_id = " + account_id
906 +
" OR relationships.account2_id = " + account_id +
" )"
907 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL);
909 rs = connection.executeQuery(s, queryStr);
911 return (rs.getLong(
"count"));
912 }
catch (SQLException ex) {
913 throw new TskCoreException(
"Error getting relationships count for account device instance. " + ex.getMessage(), ex);
940 if (accountDeviceInstanceList.isEmpty()) {
942 return Collections.emptySet();
945 Map<Long, Set<Long>> accountIdToDatasourceObjIdMap =
new HashMap<Long, Set<Long>>();
947 long accountID = accountDeviceInstance.getAccount().
getAccountID();
948 List<Long> dataSourceObjIds = db.getDataSourceObjIds(accountDeviceInstance.getDeviceId());
950 if (accountIdToDatasourceObjIdMap.containsKey(accountID)) {
951 accountIdToDatasourceObjIdMap.get(accountID).addAll(dataSourceObjIds);
953 accountIdToDatasourceObjIdMap.put(accountID,
new HashSet<Long>(dataSourceObjIds));
957 List<String> adiSQLClauses =
new ArrayList<String>();
958 for (Map.Entry<Long, Set<Long>> entry : accountIdToDatasourceObjIdMap.entrySet()) {
959 final Long accountID = entry.getKey();
960 String datasourceObjIdsCSV = StringUtils.buildCSVString(entry.getValue());
963 "( ( relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV +
" ) )"
964 +
" AND ( relationships.account1_id = " + accountID
965 +
" OR relationships.account2_id = " + accountID +
" ) )"
968 String adiSQLClause = StringUtils.joinAsStrings(adiSQLClauses,
" OR ");
971 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
977 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
979 String limitQuery =
" account_relationships AS relationships";
980 String limitStr = getMostRecentFilterLimitSQL(filter);
981 if (!limitStr.isEmpty()) {
982 limitQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
985 CaseDbConnection connection = db.getConnection();
991 s = connection.createStatement();
993 =
"SELECT DISTINCT artifacts.artifact_id AS artifact_id,"
994 +
" artifacts.obj_id AS obj_id,"
995 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
996 +
" artifacts.data_source_obj_id AS data_source_obj_id, "
997 +
" artifacts.artifact_type_id AS artifact_type_id, "
998 +
" artifacts.review_status_id AS review_status_id "
999 +
" FROM blackboard_artifacts as artifacts"
1000 +
" JOIN " + limitQuery
1001 +
" ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id"
1003 +
" WHERE (" + adiSQLClause +
" )"
1005 + (filterSQL.isEmpty() ?
"" :
" AND (" + filterSQL +
" )");
1007 rs = connection.executeQuery(s, queryStr);
1008 Set<Content> relationshipSources =
new HashSet<Content>();
1012 rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"),
1013 rs.getLong(
"data_source_obj_id"), bbartType.getTypeID(),
1014 bbartType.getTypeName(), bbartType.getDisplayName(),
1018 return relationshipSources;
1019 }
catch (SQLException ex) {
1020 throw new TskCoreException(
"Error getting relationships for account. " + ex.getMessage(), ex);
1045 final List<Long> dataSourceObjIds
1046 = getSleuthkitCase().getDataSourceObjIds(accountDeviceInstance.getDeviceId());
1049 Set<String> applicableInnerQueryFilters =
new HashSet<String>(Arrays.asList(
1055 String innerQueryfilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
1057 String innerQueryTemplate
1058 =
" SELECT %1$1s as account_id,"
1059 +
" data_source_obj_id"
1060 +
" FROM account_relationships as relationships"
1061 +
" WHERE %2$1s = " + accountDeviceInstance.getAccount().getAccountID() +
""
1062 +
" AND data_source_obj_id IN (" + StringUtils.buildCSVString(dataSourceObjIds) +
")"
1063 + (innerQueryfilterSQL.isEmpty() ?
"" :
" AND " + innerQueryfilterSQL);
1065 String innerQuery1 = String.format(innerQueryTemplate,
"account1_id",
"account2_id");
1066 String innerQuery2 = String.format(innerQueryTemplate,
"account2_id",
"account1_id");
1069 String combinedInnerQuery
1070 =
"SELECT account_id, data_source_obj_id "
1071 +
" FROM ( " + innerQuery1 +
" UNION " + innerQuery2 +
" ) AS inner_union"
1072 +
" GROUP BY account_id, data_source_obj_id";
1075 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
1079 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
1083 " accounts.account_id AS account_id,"
1084 +
" accounts.account_unique_identifier AS account_unique_identifier,"
1086 +
" account_types.type_name AS type_name,"
1088 +
" data_source_info.device_id AS device_id"
1089 +
" FROM ( " + combinedInnerQuery +
" ) AS account_device_instances"
1090 +
" JOIN accounts AS accounts"
1091 +
" ON accounts.account_id = account_device_instances.account_id"
1092 +
" JOIN account_types AS account_types"
1093 +
" ON accounts.account_type_id = account_types.account_type_id"
1094 +
" JOIN data_source_info AS data_source_info"
1095 +
" ON account_device_instances.data_source_obj_id = data_source_info.obj_id"
1096 + (filterSQL.isEmpty() ?
"" :
" WHERE " + filterSQL);
1100 queryStr =
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
1103 queryStr =
"SELECT " + queryStr +
" GROUP BY accounts.account_id, data_source_info.device_id";
1106 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
1109 CaseDbConnection connection = db.getConnection();
1112 ResultSet rs = null;
1115 s = connection.createStatement();
1117 rs = connection.executeQuery(s, queryStr);
1118 ArrayList<AccountDeviceInstance> accountDeviceInstances =
new ArrayList<AccountDeviceInstance>();
1120 long account_id = rs.getLong(
"account_id");
1121 String deviceID = rs.getString(
"device_id");
1122 final String type_name = rs.getString(
"type_name");
1123 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
1125 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
1126 Account account =
new Account(account_id, accountType, account_unique_identifier);
1130 return accountDeviceInstances;
1131 }
catch (SQLException ex) {
1132 throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
1160 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
1166 String limitQuery =
" account_relationships AS relationships";
1167 String limitStr = getMostRecentFilterLimitSQL(filter);
1168 if (!limitStr.isEmpty()) {
1169 limitQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
1172 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
1173 final String queryString =
"SELECT artifacts.artifact_id AS artifact_id,"
1174 +
" artifacts.obj_id AS obj_id,"
1175 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
1176 +
" artifacts.data_source_obj_id AS data_source_obj_id,"
1177 +
" artifacts.artifact_type_id AS artifact_type_id,"
1178 +
" artifacts.review_status_id AS review_status_id"
1179 +
" FROM blackboard_artifacts AS artifacts"
1180 +
" JOIN " + limitQuery
1181 +
" ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id"
1182 +
" WHERE (( relationships.account1_id = " + account1.getAccount().getAccountID()
1183 +
" AND relationships.account2_id = " + account2.getAccount().getAccountID()
1184 +
" ) OR ( relationships.account2_id = " + account1.getAccount().getAccountID()
1185 +
" AND relationships.account1_id =" + account2.getAccount().getAccountID() +
" ))"
1186 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL);
1187 CaseDbConnection connection = db.getConnection();
1190 ResultSet rs = null;
1192 s = connection.createStatement();
1193 rs = connection.executeQuery(s, queryString);
1195 ArrayList<Content> artifacts =
new ArrayList<Content>();
1198 artifacts.add(
new BlackboardArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"), rs.getLong(
"data_source_obj_id"),
1199 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
1204 }
catch (SQLException ex) {
1205 throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
1225 List<AccountFileInstance> accountFileInstanceList =
new ArrayList<>();
1229 if (artifactList != null && !artifactList.isEmpty()) {
1235 if (!accountFileInstanceList.isEmpty()) {
1236 return accountFileInstanceList;
1251 CaseDbConnection connection = db.getConnection();
1254 ResultSet rs = null;
1255 List<
Account.
Type> inUseAccounts =
new ArrayList<>();
1258 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";
1259 s = connection.createStatement();
1260 rs = connection.executeQuery(s, query);
1263 String accountTypeName = rs.getString(
"type_name");
1264 accountType = this.typeNameToAccountTypeMap.get(accountTypeName);
1266 if (accountType == null) {
1267 accountType =
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
1268 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
1271 inUseAccounts.add(accountType);
1273 return inUseAccounts;
1274 }
catch (SQLException ex) {
1275 throw new TskCoreException(
"Error getting account type id", ex);
1294 if (artifact == null) {
1295 throw new IllegalArgumentException(
"null arugment passed to getAccountsRelatedToArtifact");
1298 List<Account> accountList =
new ArrayList<>();
1299 try (CaseDbConnection connection = db.getConnection()) {
1306 String query = String.format(
"SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1308 +
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1310 +
" JOIN account_relationships ON account1_id = account_id"
1311 +
" WHERE relationship_source_obj_id = %d"
1313 +
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1315 +
" JOIN account_relationships ON account2_id = account_id"
1316 +
" WHERE relationship_source_obj_id = %d) AS unionOfRelationships", artifact.getId(), artifact.getId());
1317 try (Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(query)) {
1320 int accountTypeId = rs.getInt(
"account_type_id");
1321 for (Map.Entry<
Account.
Type, Integer> entry : accountTypeToTypeIdMap.entrySet()) {
1322 if (entry.getValue() == accountTypeId) {
1323 accountType = entry.getKey();
1328 accountList.add(
new Account(rs.getInt(
"account_id"), accountType, rs.getString(
"account_unique_identifier")));
1330 }
catch (SQLException ex) {
1331 throw new TskCoreException(
"Unable to get account list for give artifact " + artifact.getId(), ex);
1350 if (accountTypeToTypeIdMap.containsKey(accountType)) {
1351 return accountTypeToTypeIdMap.get(accountType);
1368 private String normalizeAccountID(Account.Type accountType, String accountUniqueID)
throws InvalidAccountIDException {
1370 if (accountUniqueID == null || accountUniqueID.isEmpty()) {
1371 throw new InvalidAccountIDException(
"Account id is null or empty.");
1374 String normalizedAccountID;
1375 if (accountType.equals(Account.Type.PHONE)) {
1376 normalizedAccountID = CommunicationsUtils.normalizePhoneNum(accountUniqueID);
1377 }
else if (accountType.equals(Account.Type.EMAIL)) {
1378 normalizedAccountID = CommunicationsUtils.normalizeEmailAddress(accountUniqueID);
1380 normalizedAccountID = accountUniqueID.toLowerCase().trim();
1383 return normalizedAccountID;
1398 private String getCommunicationsFilterSQL(CommunicationsFilter commFilter, Set<String> applicableFilters) {
1399 if (null == commFilter || commFilter.getAndFilters().isEmpty()) {
1404 StringBuilder sqlSB =
new StringBuilder();
1405 boolean first =
true;
1406 for (CommunicationsFilter.SubFilter subFilter : commFilter.getAndFilters()) {
1409 if (applicableFilters.contains(subFilter.getClass().getName())) {
1410 String subfilterSQL = subFilter.getSQL(
this);
1411 if (!subfilterSQL.isEmpty()) {
1415 sqlSB.append(
" AND ");
1418 sqlSB.append(subfilterSQL);
1424 if (!sqlSB.toString().isEmpty()) {
1425 sqlStr =
"( " + sqlSB.toString() +
" )";
1438 private String getMostRecentFilterLimitSQL(CommunicationsFilter filter) {
1439 String limitStr =
"";
1441 if (filter != null && !filter.getAndFilters().isEmpty()) {
1443 for (CommunicationsFilter.SubFilter subFilter : filter.getAndFilters()) {
1444 if (subFilter.getClass().getName().equals(CommunicationsFilter.MostRecentFilter.class.getName())) {
1445 limitStr = subFilter.getSQL(
this);
Set< Content > getRelationshipSources(Set< AccountDeviceInstance > accountDeviceInstanceList, CommunicationsFilter filter)
void postArtifact(BlackboardArtifact artifact, String moduleName)
CaseDbTransaction beginTransaction()
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
Blackboard getBlackboard()
void addAttributes(Collection< BlackboardAttribute > attributes)
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()
BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id)
static final List< Account.Type > PREDEFINED_ACCOUNT_TYPES
void acquireSingleUserCaseWriteLock()
BlackboardArtifact.Type getArtifactType(String artTypeName)
void releaseSingleUserCaseWriteLock()
List< Content > getRelationshipSources(AccountDeviceInstance account1, AccountDeviceInstance account2, CommunicationsFilter filter)
long getRelationshipSourcesCount(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter)
void acquireSingleUserCaseReadLock()
List< AccountDeviceInstance > getAccountDeviceInstancesWithRelationships(CommunicationsFilter filter)
static ReviewStatus withID(int id)
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)