19 package org.sleuthkit.datamodel;
21 import java.sql.ResultSet;
22 import java.sql.SQLException;
23 import java.sql.Statement;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
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;
51 private final Map<
Account.
Type, Integer> accountTypeToTypeIdMap
52 =
new ConcurrentHashMap<>();
53 private final Map<String,
Account.
Type> typeNameToAccountTypeMap
54 =
new ConcurrentHashMap<>();
57 private static final Set<Integer> RELATIONSHIP_ARTIFACT_TYPE_IDS =
new HashSet<Integer>(Arrays.asList(
63 private static final String RELATIONSHIP_ARTIFACT_TYPE_IDS_CSV_STR = StringUtils.buildCSVString(RELATIONSHIP_ARTIFACT_TYPE_IDS);
85 CaseDbConnection connection = db.getConnection();
87 Statement statement = null;
88 ResultSet resultSet = null;
91 statement = connection.createStatement();
93 int count = readAccountTypes();
98 statement.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + type.getTypeName() +
"', '" + type.getDisplayName() +
"')");
99 }
catch (SQLException ex) {
100 resultSet = connection.executeQuery(statement,
"SELECT COUNT(*) AS count FROM account_types WHERE type_name = '" + type.getTypeName() +
"'");
102 if (resultSet.getLong(
"count") == 0) {
108 ResultSet rs2 = connection.executeQuery(statement,
"SELECT account_type_id FROM account_types WHERE type_name = '" + type.getTypeName() +
"'");
110 int typeID = rs2.getInt(
"account_type_id");
114 this.accountTypeToTypeIdMap.put(accountType, typeID);
115 this.typeNameToAccountTypeMap.put(type.getTypeName(), accountType);
118 }
catch (SQLException ex) {
119 LOGGER.log(Level.SEVERE,
"Failed to add row to account_types", ex);
121 closeResultSet(resultSet);
122 closeStatement(statement);
137 CaseDbConnection connection = db.getConnection();
139 Statement statement = null;
140 ResultSet resultSet = null;
144 statement = connection.createStatement();
147 resultSet = connection.executeQuery(statement,
"SELECT COUNT(*) AS count FROM account_types");
149 if (resultSet.getLong(
"count") > 0) {
152 resultSet = connection.executeQuery(statement,
"SELECT * FROM account_types");
153 while (resultSet.next()) {
154 Account.
Type accountType =
new Account.
Type(resultSet.getString(
"type_name"), resultSet.getString(
"display_name"));
155 this.accountTypeToTypeIdMap.put(accountType, resultSet.getInt(
"account_type_id"));
156 this.typeNameToAccountTypeMap.put(accountType.getTypeName(), accountType);
158 count = this.typeNameToAccountTypeMap.size();
161 }
catch (SQLException ex) {
164 closeResultSet(resultSet);
165 closeStatement(statement);
199 if (this.accountTypeToTypeIdMap.containsKey(accountType)) {
203 CaseDbConnection connection = db.getConnection();
208 connection.beginTransaction();
209 s = connection.createStatement();
210 rs = connection.executeQuery(s,
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName +
"'");
214 s.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + accountTypeName +
"', '" + displayName +
"')");
217 rs = connection.executeQuery(s,
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName +
"'");
220 int typeID = rs.getInt(
"account_type_id");
221 accountType =
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
223 this.accountTypeToTypeIdMap.put(accountType, typeID);
224 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
226 connection.commitTransaction();
230 int typeID = rs.getInt(
"account_type_id");
232 accountType =
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
233 this.accountTypeToTypeIdMap.put(accountType, typeID);
237 }
catch (SQLException ex) {
238 connection.rollbackTransaction();
270 Account account = getOrCreateAccount(accountType, normalizeAccountID(accountType, accountUniqueID));
278 BlackboardArtifact accountArtifact = getOrCreateAccountFileInstanceArtifact(accountType, normalizeAccountID(accountType, accountUniqueID), moduleName, sourceFile);
305 CaseDbConnection connection = db.getConnection();
310 s = connection.createStatement();
311 rs = connection.executeQuery(s,
"SELECT * FROM accounts WHERE account_type_id = " + getAccountTypeId(accountType)
312 +
" AND account_unique_identifier = '" + normalizeAccountID(accountType, accountUniqueID) +
"'");
315 account =
new Account(rs.getInt(
"account_id"), accountType,
316 rs.getString(
"account_unique_identifier"));
318 }
catch (SQLException ex) {
319 throw new TskCoreException(
"Error getting account type id", ex);
356 if (relationshipType.isCreatableFrom(sourceArtifact) ==
false) {
357 throw new TskDataException(
"Can not make a " + relationshipType.getDisplayName()
358 +
" relationship from a" + sourceArtifact.getDisplayName());
367 List<Long> accountIDs =
new ArrayList<Long>();
369 if (null != sender) {
370 accountIDs.add(sender.getAccount().getAccountID());
371 if (sender.getDataSourceObjectID() != sourceArtifact.getDataSourceObjectID()) {
372 throw new TskDataException(
"Sender and relationship are from different data sources :"
373 +
"Sender source ID" + sender.getDataSourceObjectID() +
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
378 accountIDs.add(recipient.getAccount().getAccountID());
379 if (recipient.getDataSourceObjectID() != sourceArtifact.getDataSourceObjectID()) {
380 throw new TskDataException(
"Recipient and relationship are from different data sources :"
381 +
"Recipient source ID" + recipient.getDataSourceObjectID() +
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
385 for (
int i = 0; i < accountIDs.size(); i++) {
386 for (
int j = i + 1; j < accountIDs.size(); j++) {
388 addAccountsRelationship(accountIDs.get(i), accountIDs.get(j),
389 sourceArtifact, relationshipType, dateTime);
390 }
catch (TskCoreException ex) {
392 LOGGER.log(Level.WARNING,
"Error adding relationship", ex);
414 if (null == account) {
415 String query =
" INTO accounts (account_type_id, account_unique_identifier) "
416 +
"VALUES ( " + getAccountTypeId(accountType) +
", '"
417 + normalizeAccountID(accountType, accountUniqueID) +
"'" +
")";
420 query =
"INSERT " + query +
" ON CONFLICT DO NOTHING";
423 query =
"INSERT OR IGNORE " + query;
426 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
429 CaseDbConnection connection = db.getConnection();
434 connection.beginTransaction();
435 s = connection.createStatement();
439 connection.commitTransaction();
440 account =
getAccount(accountType, accountUniqueID);
441 }
catch (SQLException ex) {
442 connection.rollbackTransaction();
443 throw new TskCoreException(
"Error adding an account", ex);
472 private BlackboardArtifact getOrCreateAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile)
throws TskCoreException {
473 BlackboardArtifact accountArtifact = getAccountFileInstanceArtifact(accountType, accountUniqueID, sourceFile);
474 if (accountArtifact == null) {
475 accountArtifact = db.
newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT, sourceFile.getId());
476 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
477 attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, moduleName, accountType.getTypeName()));
478 attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID, moduleName, accountUniqueID));
482 }
catch (BlackboardException ex) {
483 LOGGER.log(Level.SEVERE, String.format(
"Error posting new account artifact to the blackboard (object ID = %d)", accountArtifact.getId()), ex);
486 return accountArtifact;
502 private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, Content sourceFile)
throws TskCoreException {
503 BlackboardArtifact accountArtifact = null;
504 CaseDbConnection connection = db.getConnection();
510 s = connection.createStatement();
511 String queryStr =
"SELECT artifacts.artifact_id AS artifact_id,"
512 +
" artifacts.obj_id AS obj_id,"
513 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
514 +
" artifacts.data_source_obj_id AS data_source_obj_id,"
515 +
" artifacts.artifact_type_id AS artifact_type_id,"
516 +
" artifacts.review_status_id AS review_status_id"
517 +
" FROM blackboard_artifacts AS artifacts"
518 +
" JOIN blackboard_attributes AS attr_account_type"
519 +
" ON artifacts.artifact_id = attr_account_type.artifact_id"
520 +
" JOIN blackboard_attributes AS attr_account_id"
521 +
" ON artifacts.artifact_id = attr_account_id.artifact_id"
522 +
" AND attr_account_id.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID()
523 +
" AND attr_account_id.value_text = '" + accountUniqueID +
"'"
524 +
" WHERE artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()
525 +
" AND attr_account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
526 +
" AND attr_account_type.value_text = '" + accountType.getTypeName() +
"'"
527 +
" AND artifacts.obj_id = " + sourceFile.getId();
529 rs = connection.executeQuery(s, queryStr);
531 BlackboardArtifact.Type bbartType = db.
getArtifactType(rs.getInt(
"artifact_type_id"));
533 accountArtifact =
new BlackboardArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"), rs.getLong(
"data_source_obj_id"),
534 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
535 BlackboardArtifact.ReviewStatus.withID(rs.getInt(
"review_status_id")));
537 }
catch (SQLException ex) {
538 throw new TskCoreException(
"Error getting account", ex);
546 return accountArtifact;
560 if (this.typeNameToAccountTypeMap.containsKey(accountTypeName)) {
561 return this.typeNameToAccountTypeMap.get(accountTypeName);
564 CaseDbConnection connection = db.getConnection();
570 s = connection.createStatement();
571 rs = connection.executeQuery(s,
"SELECT account_type_id, type_name, display_name FROM account_types WHERE type_name = '" + accountTypeName +
"'");
574 accountType =
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
575 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
576 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
579 }
catch (SQLException ex) {
580 throw new TskCoreException(
"Error getting account type id", ex);
602 private void addAccountsRelationship(
long account1_id,
long account2_id,
BlackboardArtifact relationshipaArtifact,
Relationship.
Type relationshipType,
long dateTime)
throws TskCoreException {
603 CaseDbConnection connection = db.getConnection();
609 String dateTimeValStr = (dateTime > 0) ? Long.toString(dateTime) :
"NULL";
611 connection.beginTransaction();
612 s = connection.createStatement();
613 String query =
"INTO account_relationships (account1_id, account2_id, relationship_source_obj_id, date_time, relationship_type, data_source_obj_id ) "
614 +
"VALUES ( " + account1_id +
", " + account2_id +
", " + relationshipaArtifact.getId() +
", " + dateTimeValStr +
", " + relationshipType.getTypeID() +
", " + relationshipaArtifact.getDataSourceObjectID() +
")";
617 query =
"INSERT " + query +
" ON CONFLICT DO NOTHING";
620 query =
"INSERT OR IGNORE " + query;
623 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
626 connection.commitTransaction();
627 }
catch (SQLException ex) {
628 connection.rollbackTransaction();
629 throw new TskCoreException(
"Error adding accounts relationship", ex);
653 CaseDbConnection connection = db.getConnection();
659 s = connection.createStatement();
662 Set<String> applicableInnerQueryFilters =
new HashSet<String>(Arrays.asList(
667 String relationshipFilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
669 String relationshipLimitSQL = getMostRecentFilterLimitSQL(filter);
671 String relTblfilterQuery
673 +
"FROM account_relationships as relationships"
674 + (relationshipFilterSQL.isEmpty() ?
"" :
" WHERE " + relationshipFilterSQL)
675 + (relationshipLimitSQL.isEmpty() ?
"" : relationshipLimitSQL);
677 String uniqueAccountQueryTemplate
678 =
" SELECT %1$1s as account_id,"
679 +
" data_source_obj_id"
680 +
" FROM ( " + relTblfilterQuery +
")AS %2$s";
682 String relationshipTableFilterQuery1 = String.format(uniqueAccountQueryTemplate,
"account1_id",
"union_query_1");
683 String relationshipTableFilterQuery2 = String.format(uniqueAccountQueryTemplate,
"account2_id",
"union_query_2");
686 String uniqueAccountQuery
687 =
"SELECT DISTINCT account_id, data_source_obj_id"
688 +
" FROM ( " + relationshipTableFilterQuery1 +
" UNION " + relationshipTableFilterQuery2 +
" ) AS inner_union"
689 +
" GROUP BY account_id, data_source_obj_id";
692 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
696 String accountTypeFilterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
700 " accounts.account_id AS account_id,"
701 +
" accounts.account_unique_identifier AS account_unique_identifier,"
703 +
" account_types.type_name AS type_name,"
705 +
" data_source_info.device_id AS device_id"
706 +
" FROM ( " + uniqueAccountQuery +
" ) AS account_device_instances"
707 +
" JOIN accounts AS accounts"
708 +
" ON accounts.account_id = account_device_instances.account_id"
709 +
" JOIN account_types AS account_types"
710 +
" ON accounts.account_type_id = account_types.account_type_id"
711 +
" JOIN data_source_info AS data_source_info"
712 +
" ON account_device_instances.data_source_obj_id = data_source_info.obj_id"
713 + (accountTypeFilterSQL.isEmpty() ?
"" :
" WHERE " + accountTypeFilterSQL);
717 queryStr =
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
720 queryStr =
"SELECT " + queryStr +
" GROUP BY accounts.account_id, data_source_info.device_id";
723 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
726 rs = connection.executeQuery(s, queryStr);
727 ArrayList<AccountDeviceInstance> accountDeviceInstances =
new ArrayList<AccountDeviceInstance>();
729 long account_id = rs.getLong(
"account_id");
730 String deviceID = rs.getString(
"device_id");
731 final String type_name = rs.getString(
"type_name");
732 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
734 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
735 Account account =
new Account(account_id, accountType, account_unique_identifier);
739 return accountDeviceInstances;
740 }
catch (SQLException ex) {
741 throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
771 Set<Long> accountIDs =
new HashSet<Long>();
772 Set<String> accountDeviceIDs =
new HashSet<String>();
774 accountIDs.add(adi.getAccount().getAccountID());
775 accountDeviceIDs.add(
"'" + adi.getDeviceId() +
"'");
778 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
784 String accountIDsCSL = StringUtils.buildCSVString(accountIDs);
785 String accountDeviceIDsCSL = StringUtils.buildCSVString(accountDeviceIDs);
786 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
788 final String queryString
789 =
" SELECT count(DISTINCT relationships.relationship_source_obj_id) AS count,"
790 +
" data_source_info.device_id AS device_id,"
792 +
" accounts1.account_id AS account1_id,"
793 +
" accounts1.account_unique_identifier AS account1_unique_identifier,"
794 +
" account_types1.type_name AS type_name1,"
795 +
" account_types1.display_name AS display_name1,"
797 +
" accounts2.account_id AS account2_id,"
798 +
" accounts2.account_unique_identifier AS account2_unique_identifier,"
799 +
" account_types2.type_name AS type_name2,"
800 +
" account_types2.display_name AS display_name2"
801 +
" FROM account_relationships AS relationships"
802 +
" JOIN data_source_info AS data_source_info"
803 +
" ON relationships.data_source_obj_id = data_source_info.obj_id "
805 +
" JOIN accounts AS accounts1 "
806 +
" ON accounts1.account_id = relationships.account1_id"
807 +
" JOIN account_types AS account_types1"
808 +
" ON accounts1.account_type_id = account_types1.account_type_id"
810 +
" JOIN accounts AS accounts2 "
811 +
" ON accounts2.account_id = relationships.account2_id"
812 +
" JOIN account_types AS account_types2"
813 +
" ON accounts2.account_type_id = account_types2.account_type_id"
814 +
" WHERE (( relationships.account1_id IN (" + accountIDsCSL +
")) "
815 +
" AND ( relationships.account2_id IN ( " + accountIDsCSL +
" ))"
816 +
" AND ( data_source_info.device_id IN (" + accountDeviceIDsCSL +
"))) "
817 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL)
818 +
" GROUP BY data_source_info.device_id, "
819 +
" accounts1.account_id, "
820 +
" account_types1.type_name, "
821 +
" account_types1.display_name, "
822 +
" accounts2.account_id, "
823 +
" account_types2.type_name, "
824 +
" account_types2.display_name";
825 CaseDbConnection connection = db.getConnection();
830 Map<AccountPair, Long> results =
new HashMap<AccountPair, Long>();
833 s = connection.createStatement();
834 rs = connection.executeQuery(s, queryString);
840 rs.getString(
"account1_unique_identifier")),
841 rs.getString(
"device_id"));
846 rs.getString(
"account2_unique_identifier")),
847 rs.getString(
"device_id"));
850 long count = rs.getLong(
"count");
853 Long oldCount = results.get(relationshipKey);
854 if (oldCount != null) {
857 results.put(relationshipKey, count);
860 }
catch (SQLException ex) {
861 throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
887 long account_id = accountDeviceInstance.getAccount().
getAccountID();
890 String datasourceObjIdsCSV = StringUtils.buildCSVString(
891 db.getDataSourceObjIds(accountDeviceInstance.getDeviceId()));
894 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
898 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
900 CaseDbConnection connection = db.getConnection();
906 s = connection.createStatement();
908 String innerQuery =
" account_relationships AS relationships";
909 String limitStr = getMostRecentFilterLimitSQL(filter);
911 if (!limitStr.isEmpty()) {
912 innerQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
916 =
"SELECT count(DISTINCT relationships.relationship_source_obj_id) as count "
917 +
" FROM" + innerQuery
918 +
" WHERE relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV +
" )"
919 +
" AND ( relationships.account1_id = " + account_id
920 +
" OR relationships.account2_id = " + account_id +
" )"
921 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL);
923 rs = connection.executeQuery(s, queryStr);
925 return (rs.getLong(
"count"));
926 }
catch (SQLException ex) {
927 throw new TskCoreException(
"Error getting relationships count for account device instance. " + ex.getMessage(), ex);
954 if (accountDeviceInstanceList.isEmpty()) {
956 return Collections.emptySet();
959 Map<Long, Set<Long>> accountIdToDatasourceObjIdMap =
new HashMap<Long, Set<Long>>();
961 long accountID = accountDeviceInstance.getAccount().
getAccountID();
962 List<Long> dataSourceObjIds = db.getDataSourceObjIds(accountDeviceInstance.getDeviceId());
964 if (accountIdToDatasourceObjIdMap.containsKey(accountID)) {
965 accountIdToDatasourceObjIdMap.get(accountID).addAll(dataSourceObjIds);
967 accountIdToDatasourceObjIdMap.put(accountID,
new HashSet<Long>(dataSourceObjIds));
971 List<String> adiSQLClauses =
new ArrayList<String>();
972 for (Map.Entry<Long, Set<Long>> entry : accountIdToDatasourceObjIdMap.entrySet()) {
973 final Long accountID = entry.getKey();
974 String datasourceObjIdsCSV = StringUtils.buildCSVString(entry.getValue());
977 "( ( relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV +
" ) )"
978 +
" AND ( relationships.account1_id = " + accountID
979 +
" OR relationships.account2_id = " + accountID +
" ) )"
982 String adiSQLClause = StringUtils.joinAsStrings(adiSQLClauses,
" OR ");
985 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
991 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
993 String limitQuery =
" account_relationships AS relationships";
994 String limitStr = getMostRecentFilterLimitSQL(filter);
995 if (!limitStr.isEmpty()) {
996 limitQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
999 CaseDbConnection connection = db.getConnection();
1002 ResultSet rs = null;
1005 s = connection.createStatement();
1007 =
"SELECT DISTINCT artifacts.artifact_id AS artifact_id,"
1008 +
" artifacts.obj_id AS obj_id,"
1009 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
1010 +
" artifacts.data_source_obj_id AS data_source_obj_id, "
1011 +
" artifacts.artifact_type_id AS artifact_type_id, "
1012 +
" artifacts.review_status_id AS review_status_id "
1013 +
" FROM blackboard_artifacts as artifacts"
1014 +
" JOIN " + limitQuery
1015 +
" ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id"
1017 +
" WHERE (" + adiSQLClause +
" )"
1019 + (filterSQL.isEmpty() ?
"" :
" AND (" + filterSQL +
" )");
1021 rs = connection.executeQuery(s, queryStr);
1022 Set<Content> relationshipSources =
new HashSet<Content>();
1026 rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"),
1027 rs.getLong(
"data_source_obj_id"), bbartType.getTypeID(),
1028 bbartType.getTypeName(), bbartType.getDisplayName(),
1032 return relationshipSources;
1033 }
catch (SQLException ex) {
1034 throw new TskCoreException(
"Error getting relationships for account. " + ex.getMessage(), ex);
1059 final List<Long> dataSourceObjIds
1060 = getSleuthkitCase().getDataSourceObjIds(accountDeviceInstance.getDeviceId());
1063 Set<String> applicableInnerQueryFilters =
new HashSet<String>(Arrays.asList(
1069 String innerQueryfilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
1071 String innerQueryTemplate
1072 =
" SELECT %1$1s as account_id,"
1073 +
" data_source_obj_id"
1074 +
" FROM account_relationships as relationships"
1075 +
" WHERE %2$1s = " + accountDeviceInstance.getAccount().getAccountID() +
""
1076 +
" AND data_source_obj_id IN (" + StringUtils.buildCSVString(dataSourceObjIds) +
")"
1077 + (innerQueryfilterSQL.isEmpty() ?
"" :
" AND " + innerQueryfilterSQL);
1079 String innerQuery1 = String.format(innerQueryTemplate,
"account1_id",
"account2_id");
1080 String innerQuery2 = String.format(innerQueryTemplate,
"account2_id",
"account1_id");
1083 String combinedInnerQuery
1084 =
"SELECT account_id, data_source_obj_id "
1085 +
" FROM ( " + innerQuery1 +
" UNION " + innerQuery2 +
" ) AS inner_union"
1086 +
" GROUP BY account_id, data_source_obj_id";
1089 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
1093 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
1097 " accounts.account_id AS account_id,"
1098 +
" accounts.account_unique_identifier AS account_unique_identifier,"
1100 +
" account_types.type_name AS type_name,"
1102 +
" data_source_info.device_id AS device_id"
1103 +
" FROM ( " + combinedInnerQuery +
" ) AS account_device_instances"
1104 +
" JOIN accounts AS accounts"
1105 +
" ON accounts.account_id = account_device_instances.account_id"
1106 +
" JOIN account_types AS account_types"
1107 +
" ON accounts.account_type_id = account_types.account_type_id"
1108 +
" JOIN data_source_info AS data_source_info"
1109 +
" ON account_device_instances.data_source_obj_id = data_source_info.obj_id"
1110 + (filterSQL.isEmpty() ?
"" :
" WHERE " + filterSQL);
1114 queryStr =
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
1117 queryStr =
"SELECT " + queryStr +
" GROUP BY accounts.account_id, data_source_info.device_id";
1120 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
1123 CaseDbConnection connection = db.getConnection();
1126 ResultSet rs = null;
1129 s = connection.createStatement();
1131 rs = connection.executeQuery(s, queryStr);
1132 ArrayList<AccountDeviceInstance> accountDeviceInstances =
new ArrayList<AccountDeviceInstance>();
1134 long account_id = rs.getLong(
"account_id");
1135 String deviceID = rs.getString(
"device_id");
1136 final String type_name = rs.getString(
"type_name");
1137 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
1139 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
1140 Account account =
new Account(account_id, accountType, account_unique_identifier);
1144 return accountDeviceInstances;
1145 }
catch (SQLException ex) {
1146 throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
1174 Set<String> applicableFilters =
new HashSet<String>(Arrays.asList(
1180 String limitQuery =
" account_relationships AS relationships";
1181 String limitStr = getMostRecentFilterLimitSQL(filter);
1182 if (!limitStr.isEmpty()) {
1183 limitQuery =
"(SELECT * FROM account_relationships as relationships " + limitStr +
") as relationships";
1186 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
1187 final String queryString =
"SELECT artifacts.artifact_id AS artifact_id,"
1188 +
" artifacts.obj_id AS obj_id,"
1189 +
" artifacts.artifact_obj_id AS artifact_obj_id,"
1190 +
" artifacts.data_source_obj_id AS data_source_obj_id,"
1191 +
" artifacts.artifact_type_id AS artifact_type_id,"
1192 +
" artifacts.review_status_id AS review_status_id"
1193 +
" FROM blackboard_artifacts AS artifacts"
1194 +
" JOIN " + limitQuery
1195 +
" ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id"
1196 +
" WHERE (( relationships.account1_id = " + account1.getAccount().getAccountID()
1197 +
" AND relationships.account2_id = " + account2.getAccount().getAccountID()
1198 +
" ) OR ( relationships.account2_id = " + account1.getAccount().getAccountID()
1199 +
" AND relationships.account1_id =" + account2.getAccount().getAccountID() +
" ))"
1200 + (filterSQL.isEmpty() ?
"" :
" AND " + filterSQL);
1201 CaseDbConnection connection = db.getConnection();
1204 ResultSet rs = null;
1206 s = connection.createStatement();
1207 rs = connection.executeQuery(s, queryString);
1209 ArrayList<Content> artifacts =
new ArrayList<Content>();
1212 artifacts.add(
new BlackboardArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"), rs.getLong(
"data_source_obj_id"),
1213 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
1218 }
catch (SQLException ex) {
1219 throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
1239 List<AccountFileInstance> accountFileInstanceList =
new ArrayList<>();
1243 if (artifactList != null && !artifactList.isEmpty()) {
1249 if (!accountFileInstanceList.isEmpty()) {
1250 return accountFileInstanceList;
1265 CaseDbConnection connection = db.getConnection();
1268 ResultSet rs = null;
1269 List<
Account.
Type> inUseAccounts =
new ArrayList<>();
1272 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";
1273 s = connection.createStatement();
1274 rs = connection.executeQuery(s, query);
1277 String accountTypeName = rs.getString(
"type_name");
1278 accountType = this.typeNameToAccountTypeMap.get(accountTypeName);
1280 if (accountType == null) {
1281 accountType =
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
1282 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
1285 inUseAccounts.add(accountType);
1287 return inUseAccounts;
1288 }
catch (SQLException ex) {
1289 throw new TskCoreException(
"Error getting account type id", ex);
1308 if (artifact == null) {
1309 throw new IllegalArgumentException(
"null arugment passed to getAccountsRelatedToArtifact");
1312 List<Account> accountList =
new ArrayList<>();
1313 try (CaseDbConnection connection = db.getConnection()) {
1320 String query = String.format(
"SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1322 +
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1324 +
" JOIN account_relationships ON account1_id = account_id"
1325 +
" WHERE relationship_source_obj_id = %d"
1327 +
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier"
1329 +
" JOIN account_relationships ON account2_id = account_id"
1330 +
" WHERE relationship_source_obj_id = %d) AS unionOfRelationships", artifact.getId(), artifact.getId());
1331 try (Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(query)) {
1334 int accountTypeId = rs.getInt(
"account_type_id");
1335 for (Map.Entry<
Account.
Type, Integer> entry : accountTypeToTypeIdMap.entrySet()) {
1336 if (entry.getValue() == accountTypeId) {
1337 accountType = entry.getKey();
1342 accountList.add(
new Account(rs.getInt(
"account_id"), accountType, rs.getString(
"account_unique_identifier")));
1344 }
catch (SQLException ex) {
1345 throw new TskCoreException(
"Unable to get account list for give artifact " + artifact.getId(), ex);
1364 if (accountTypeToTypeIdMap.containsKey(accountType)) {
1365 return accountTypeToTypeIdMap.get(accountType);
1382 private String normalizeAccountID(Account.Type accountType, String accountUniqueID)
throws InvalidAccountIDException {
1384 if (accountUniqueID == null || accountUniqueID.isEmpty()) {
1385 throw new InvalidAccountIDException(
"Account id is null or empty.");
1388 String normalizedAccountID;
1389 if (accountType.equals(Account.Type.PHONE)) {
1390 normalizedAccountID = CommunicationsUtils.normalizePhoneNum(accountUniqueID);
1391 }
else if (accountType.equals(Account.Type.EMAIL)) {
1392 normalizedAccountID = CommunicationsUtils.normalizeEmailAddress(accountUniqueID);
1394 normalizedAccountID = accountUniqueID.toLowerCase().trim();
1397 return normalizedAccountID;
1412 private String getCommunicationsFilterSQL(CommunicationsFilter commFilter, Set<String> applicableFilters) {
1413 if (null == commFilter || commFilter.getAndFilters().isEmpty()) {
1418 StringBuilder sqlSB =
new StringBuilder();
1419 boolean first =
true;
1420 for (CommunicationsFilter.SubFilter subFilter : commFilter.getAndFilters()) {
1423 if (applicableFilters.contains(subFilter.getClass().getName())) {
1424 String subfilterSQL = subFilter.getSQL(
this);
1425 if (!subfilterSQL.isEmpty()) {
1429 sqlSB.append(
" AND ");
1432 sqlSB.append(subfilterSQL);
1438 if (!sqlSB.toString().isEmpty()) {
1439 sqlStr =
"( " + sqlSB.toString() +
" )";
1452 private String getMostRecentFilterLimitSQL(CommunicationsFilter filter) {
1453 String limitStr =
"";
1455 if (filter != null && !filter.getAndFilters().isEmpty()) {
1457 for (CommunicationsFilter.SubFilter subFilter : filter.getAndFilters()) {
1458 if (subFilter.getClass().getName().equals(CommunicationsFilter.MostRecentFilter.class.getName())) {
1459 limitStr = subFilter.getSQL(
this);
Set< Content > getRelationshipSources(Set< AccountDeviceInstance > accountDeviceInstanceList, CommunicationsFilter filter)
void postArtifact(BlackboardArtifact artifact, String moduleName)
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)