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 = StringUtils.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) {
 
  262                 Account account = getOrCreateAccount(accountType, normalizeAccountID(accountType, accountUniqueID));
 
  270                 BlackboardArtifact accountArtifact = getOrCreateAccountFileInstanceArtifact(accountType, normalizeAccountID(accountType, accountUniqueID), moduleName, sourceFile);
 
  298                 try (CaseDbConnection connection = db.getConnection();
 
  299                         Statement s = connection.createStatement();
 
  300                         ResultSet rs = connection.executeQuery(s, 
"SELECT * FROM accounts WHERE account_type_id = " + getAccountTypeId(accountType)
 
  301                                         + 
" AND account_unique_identifier = '" + normalizeAccountID(accountType, accountUniqueID) + 
"'");) { 
 
  304                                 account = 
new Account(rs.getInt(
"account_id"), accountType,
 
  305                                                 rs.getString(
"account_unique_identifier"));
 
  307                 } 
catch (SQLException ex) {
 
  308                         throw new TskCoreException(
"Error getting account type id", ex);
 
  342                 if (sourceArtifact.getDataSourceObjectID() == null) {
 
  343                         throw new TskDataException(
"Source Artifact does not have a valid data source.");
 
  346                 if (relationshipType.isCreatableFrom(sourceArtifact) == 
false) {
 
  347                         throw new TskDataException(
"Can not make a " + relationshipType.getDisplayName()
 
  348                                         + 
" relationship from a" + sourceArtifact.getDisplayName());
 
  357                 List<Long> accountIDs = 
new ArrayList<>();
 
  359                 if (null != sender) {
 
  360                         accountIDs.add(sender.getAccount().getAccountID());
 
  361                         if (!sender.getDataSourceObjectID().equals(sourceArtifact.getDataSourceObjectID())) {
 
  362                                 throw new TskDataException(
"Sender and relationship are from different data sources :" 
  363                                                 + 
"Sender source ID" + sender.getDataSourceObjectID() + 
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
 
  368                         accountIDs.add(recipient.getAccount().getAccountID());
 
  369                         if (!recipient.getDataSourceObjectID().equals(sourceArtifact.getDataSourceObjectID())) {
 
  370                                 throw new TskDataException(
"Recipient and relationship are from different data sources :" 
  371                                                 + 
"Recipient source ID" + recipient.getDataSourceObjectID() + 
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
 
  376                 String query = 
"INTO account_relationships (account1_id, account2_id, relationship_source_obj_id, date_time, relationship_type, data_source_obj_id  ) " 
  377                                 + 
"VALUES (?,?,?,?,?,?)";
 
  380                                 query = 
"INSERT " + query + 
" ON CONFLICT DO NOTHING";
 
  383                                 query = 
"INSERT OR IGNORE " + query;
 
  386                                 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  392                         PreparedStatement preparedStatement = connection.getPreparedStatement(query, Statement.NO_GENERATED_KEYS);
 
  394                         for (
int i = 0; i < accountIDs.size(); i++) {
 
  395                                 for (
int j = i + 1; j < accountIDs.size(); j++) {
 
  396                                         long account1_id = accountIDs.get(i);
 
  397                                         long account2_id = accountIDs.get(j);
 
  399                                         preparedStatement.clearParameters();
 
  400                                         preparedStatement.setLong(1, account1_id);
 
  401                                         preparedStatement.setLong(2, account2_id);
 
  402                                         preparedStatement.setLong(3, sourceArtifact.getId());
 
  404                                                 preparedStatement.setLong(4, dateTime);
 
  406                                                 preparedStatement.setNull(4, java.sql.Types.BIGINT);
 
  408                                         preparedStatement.setInt(5, relationshipType.getTypeID());
 
  409                                         preparedStatement.setLong(6, sourceArtifact.getDataSourceObjectID());
 
  411                                         connection.executeUpdate(preparedStatement);
 
  415                 } 
catch (SQLException ex) {
 
  417                         throw new TskCoreException(
"Error adding accounts relationship", ex);
 
  437                 if (null == account) {
 
  438                         String query = 
" INTO accounts (account_type_id, account_unique_identifier) " 
  439                                         + 
"VALUES ( " + getAccountTypeId(accountType) + 
", '" 
  440                                         + normalizeAccountID(accountType, accountUniqueID) + 
"'" + 
")";
 
  443                                         query = 
"INSERT " + query + 
" ON CONFLICT DO NOTHING"; 
 
  446                                         query = 
"INSERT OR IGNORE " + query;
 
  449                                         throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  456                                 s = trans.getConnection().createStatement();
 
  461                                 account = 
getAccount(accountType, accountUniqueID);
 
  462                         } 
catch (SQLException ex) {
 
  464                                 throw new TskCoreException(
"Error adding an account", ex);
 
  491         private BlackboardArtifact getOrCreateAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile) 
throws TskCoreException {
 
  492                 if (sourceFile == null) {
 
  493                         throw new TskCoreException(
"Source file not provided.");
 
  496                 BlackboardArtifact accountArtifact = getAccountFileInstanceArtifact(accountType, accountUniqueID, sourceFile);
 
  497                 if (accountArtifact == null) {
 
  498                         List<BlackboardAttribute> attributes = Arrays.asList(
 
  499                                         new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, moduleName, accountType.getTypeName()),
 
  500                                         new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID, moduleName, accountUniqueID)
 
  503                         accountArtifact = sourceFile.newDataArtifact(ACCOUNT_TYPE, attributes);
 
  507                         } 
catch (BlackboardException ex) {
 
  508                                 LOGGER.log(Level.SEVERE, String.format(
"Error posting new account artifact to the blackboard (object ID = %d)", accountArtifact.getId()), ex);
 
  511                 return accountArtifact;
 
  527         private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, Content sourceFile) 
throws TskCoreException {
 
  528                 BlackboardArtifact accountArtifact = null;
 
  530                 String queryStr = 
"SELECT artifacts.artifact_id AS artifact_id," 
  531                         + 
" artifacts.obj_id AS obj_id," 
  532                         + 
" artifacts.artifact_obj_id AS artifact_obj_id," 
  533                         + 
" artifacts.data_source_obj_id AS data_source_obj_id," 
  534                         + 
" artifacts.artifact_type_id AS artifact_type_id," 
  535                         + 
" artifacts.review_status_id AS review_status_id," 
  536                         + 
" tsk_data_artifacts.os_account_obj_id AS os_account_obj_id" 
  537                         + 
" FROM blackboard_artifacts AS artifacts" 
  538                         + 
"     JOIN blackboard_attributes AS attr_account_type" 
  539                         + 
"             ON artifacts.artifact_id = attr_account_type.artifact_id" 
  540                         + 
" JOIN blackboard_attributes AS attr_account_id" 
  541                         + 
"             ON artifacts.artifact_id = attr_account_id.artifact_id" 
  542                         + 
"             AND attr_account_id.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID()
 
  543                         + 
"         AND attr_account_id.value_text = '" + accountUniqueID + 
"'" 
  544                         + 
" LEFT JOIN tsk_data_artifacts ON tsk_data_artifacts.artifact_obj_id = artifacts.artifact_obj_id" 
  545                         + 
" WHERE artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()
 
  546                         + 
" AND attr_account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
 
  547                         + 
" AND attr_account_type.value_text = '" + accountType.getTypeName() + 
"'" 
  548                         + 
" AND artifacts.obj_id = " + sourceFile.getId(); 
 
  551                 try (CaseDbConnection connection = db.getConnection();
 
  552                         Statement s = connection.createStatement();
 
  553                         ResultSet rs = connection.executeQuery(s, queryStr);) { 
 
  555                                 BlackboardArtifact.Type bbartType = db.
getArtifactType(rs.getInt(
"artifact_type_id"));
 
  557                                 accountArtifact = 
new DataArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"),
 
  558                                                 rs.getObject(
"data_source_obj_id") != null ? rs.getLong(
"data_source_obj_id") : null,
 
  559                                                 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
 
  560                                                 BlackboardArtifact.ReviewStatus.withID(rs.getInt(
"review_status_id")), rs.getLong(
"os_account_obj_id"), 
false);
 
  562                 } 
catch (SQLException ex) {
 
  563                         throw new TskCoreException(
"Error getting account", ex);
 
  568                 return accountArtifact;
 
  582                 if (this.typeNameToAccountTypeMap.containsKey(accountTypeName)) {
 
  583                         return this.typeNameToAccountTypeMap.get(accountTypeName);
 
  587                 try (CaseDbConnection connection = db.getConnection();
 
  588                         Statement s = connection.createStatement();
 
  589                         ResultSet rs = connection.executeQuery(s, 
"SELECT account_type_id, type_name, display_name FROM account_types WHERE type_name = '" + accountTypeName + 
"'");) { 
 
  592                                 accountType = 
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
 
  593                                 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
 
  594                                 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
 
  597                 } 
catch (SQLException ex) {
 
  598                         throw new TskCoreException(
"Error getting account type id", ex);
 
  621                 Set<String> applicableInnerQueryFilters = 
new HashSet<String>(Arrays.asList(
 
  626                 String relationshipFilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
 
  628                 String relationshipLimitSQL = getMostRecentFilterLimitSQL(filter);
 
  630                 String relTblfilterQuery
 
  632                                 + 
"FROM account_relationships as relationships" 
  633                                 + (relationshipFilterSQL.isEmpty() ? 
"" : 
" WHERE " + relationshipFilterSQL)
 
  634                                 + (relationshipLimitSQL.isEmpty() ? 
"" : relationshipLimitSQL);
 
  636                 String uniqueAccountQueryTemplate
 
  637                                 = 
" SELECT %1$1s as account_id," 
  638                                 + 
" data_source_obj_id" 
  639                                 + 
" FROM ( " + relTblfilterQuery + 
")AS %2$s";
 
  641                 String relationshipTableFilterQuery1 = String.format(uniqueAccountQueryTemplate, 
"account1_id", 
"union_query_1");
 
  642                 String relationshipTableFilterQuery2 = String.format(uniqueAccountQueryTemplate, 
"account2_id", 
"union_query_2");
 
  645                 String uniqueAccountQuery
 
  646                                 = 
"SELECT DISTINCT account_id, data_source_obj_id" 
  647                                 + 
" FROM ( " + relationshipTableFilterQuery1 + 
" UNION " + relationshipTableFilterQuery2 + 
" ) AS inner_union" 
  648                                 + 
" GROUP BY account_id, data_source_obj_id";
 
  651                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  655                 String accountTypeFilterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  659                                 " accounts.account_id AS account_id," 
  660                                 + 
" accounts.account_unique_identifier AS account_unique_identifier," 
  662                                 + 
" account_types.type_name AS type_name," 
  664                                 + 
" data_source_info.device_id AS device_id" 
  665                                 + 
" FROM ( " + uniqueAccountQuery + 
" ) AS account_device_instances" 
  666                                 + 
" JOIN accounts AS accounts" 
  667                                 + 
"             ON accounts.account_id = account_device_instances.account_id" 
  668                                 + 
" JOIN account_types AS account_types" 
  669                                 + 
"             ON accounts.account_type_id = account_types.account_type_id" 
  670                                 + 
" JOIN data_source_info AS data_source_info" 
  671                                 + 
"             ON account_device_instances.data_source_obj_id = data_source_info.obj_id" 
  672                                 + (accountTypeFilterSQL.isEmpty() ? 
"" : 
" WHERE " + accountTypeFilterSQL);
 
  676                                 queryStr = 
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
 
  679                                 queryStr = 
"SELECT " + queryStr + 
" GROUP BY accounts.account_id, data_source_info.device_id";
 
  682                                 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  686                 try (CaseDbConnection connection = db.getConnection();
 
  687                                 Statement s = connection.createStatement();
 
  688                                 ResultSet rs = connection.executeQuery(s, queryStr);) { 
 
  689                         ArrayList<AccountDeviceInstance> accountDeviceInstances = 
new ArrayList<AccountDeviceInstance>();
 
  691                                 long account_id = rs.getLong(
"account_id");
 
  692                                 String deviceID = rs.getString(
"device_id");
 
  693                                 final String type_name = rs.getString(
"type_name");
 
  694                                 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
 
  696                                 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
 
  697                                 Account account = 
new Account(account_id, accountType, account_unique_identifier);
 
  701                         return accountDeviceInstances;
 
  702                 } 
catch (SQLException ex) {
 
  703                         throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
 
  730                 Set<Long> accountIDs = 
new HashSet<Long>();
 
  731                 Set<String> accountDeviceIDs = 
new HashSet<String>();
 
  733                         accountIDs.add(adi.getAccount().getAccountID());
 
  734                         accountDeviceIDs.add(
"'" + adi.getDeviceId() + 
"'");
 
  737                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  743                 String accountIDsCSL = StringUtils.buildCSVString(accountIDs);
 
  744                 String accountDeviceIDsCSL = StringUtils.buildCSVString(accountDeviceIDs);
 
  745                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  747                 final String queryString
 
  748                                 = 
" SELECT  count(DISTINCT relationships.relationship_source_obj_id) AS count,"  
  749                                 + 
"             data_source_info.device_id AS device_id," 
  751                                 + 
"             accounts1.account_id AS account1_id," 
  752                                 + 
"             accounts1.account_unique_identifier AS account1_unique_identifier," 
  753                                 + 
"             account_types1.type_name AS type_name1," 
  754                                 + 
"             account_types1.display_name AS display_name1," 
  756                                 + 
"             accounts2.account_id AS account2_id," 
  757                                 + 
"             accounts2.account_unique_identifier AS account2_unique_identifier," 
  758                                 + 
"             account_types2.type_name AS type_name2," 
  759                                 + 
"             account_types2.display_name AS display_name2" 
  760                                 + 
" FROM account_relationships AS relationships" 
  761                                 + 
"     JOIN data_source_info AS data_source_info" 
  762                                 + 
"             ON relationships.data_source_obj_id = data_source_info.obj_id " 
  764                                 + 
"     JOIN accounts AS accounts1       " 
  765                                 + 
"             ON accounts1.account_id = relationships.account1_id" 
  766                                 + 
"     JOIN account_types AS account_types1" 
  767                                 + 
"             ON accounts1.account_type_id = account_types1.account_type_id" 
  769                                 + 
"     JOIN accounts AS accounts2       " 
  770                                 + 
"             ON accounts2.account_id = relationships.account2_id" 
  771                                 + 
"     JOIN account_types AS account_types2" 
  772                                 + 
"             ON accounts2.account_type_id = account_types2.account_type_id" 
  773                                 + 
" WHERE (( relationships.account1_id IN (" + accountIDsCSL + 
")) " 
  774                                 + 
"             AND ( relationships.account2_id IN ( " + accountIDsCSL + 
" ))" 
  775                                 + 
"             AND ( data_source_info.device_id IN (" + accountDeviceIDsCSL + 
"))) " 
  776                                 + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL)
 
  777                                 + 
"  GROUP BY data_source_info.device_id, " 
  778                                 + 
"             accounts1.account_id, " 
  779                                 + 
"             account_types1.type_name, " 
  780                                 + 
"             account_types1.display_name, " 
  781                                 + 
"             accounts2.account_id, " 
  782                                 + 
"             account_types2.type_name, " 
  783                                 + 
"             account_types2.display_name";
 
  785                 Map<AccountPair, Long> results = 
new HashMap<AccountPair, Long>();
 
  788                 try (CaseDbConnection connection = db.getConnection();
 
  789                         Statement s = connection.createStatement();
 
  790                         ResultSet rs = connection.executeQuery(s, queryString);) { 
 
  796                                                 rs.getString(
"account1_unique_identifier")),
 
  797                                                 rs.getString(
"device_id"));
 
  802                                                 rs.getString(
"account2_unique_identifier")),
 
  803                                                 rs.getString(
"device_id"));
 
  806                                 long count = rs.getLong(
"count");
 
  809                                 Long oldCount = results.get(relationshipKey);
 
  810                                 if (oldCount != null) {
 
  813                                 results.put(relationshipKey, count);
 
  816                 } 
catch (SQLException ex) {
 
  817                         throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
 
  840                 long account_id = accountDeviceInstance.getAccount().
getAccountID();
 
  843                 String datasourceObjIdsCSV = StringUtils.buildCSVString(
 
  844                                 db.getDataSourceObjIds(accountDeviceInstance.getDeviceId()));
 
  847                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  851                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  853                 String innerQuery = 
" account_relationships AS relationships";
 
  854                 String limitStr = getMostRecentFilterLimitSQL(filter);
 
  856                 if (!limitStr.isEmpty()) {
 
  857                         innerQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
  861                         = 
"SELECT count(DISTINCT relationships.relationship_source_obj_id) as count " 
  862                         + 
"     FROM" + innerQuery
 
  863                         + 
" WHERE relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV + 
" )" 
  864                         + 
" AND ( relationships.account1_id = " + account_id
 
  865                         + 
"      OR  relationships.account2_id = " + account_id + 
" )" 
  866                         + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL);
 
  869                 try (CaseDbConnection connection = db.getConnection();
 
  870                                 Statement s = connection.createStatement();
 
  871                                 ResultSet rs = connection.executeQuery(s, queryStr);) { 
 
  873                         return (rs.getLong(
"count"));
 
  874                 } 
catch (SQLException ex) {
 
  875                         throw new TskCoreException(
"Error getting relationships count for account device instance. " + ex.getMessage(), ex);
 
  899                 if (accountDeviceInstanceList.isEmpty()) {
 
  901                         return Collections.emptySet();
 
  904                 Map<Long, Set<Long>> accountIdToDatasourceObjIdMap = 
new HashMap<>();
 
  906                         long accountID = accountDeviceInstance.getAccount().
getAccountID();
 
  907                         List<Long> dataSourceObjIds = db.getDataSourceObjIds(accountDeviceInstance.getDeviceId());
 
  909                         if (accountIdToDatasourceObjIdMap.containsKey(accountID)) {
 
  910                                 accountIdToDatasourceObjIdMap.get(accountID).addAll(dataSourceObjIds);
 
  912                                 accountIdToDatasourceObjIdMap.put(accountID, 
new HashSet<>(dataSourceObjIds));
 
  916                 List<String> adiSQLClauses = 
new ArrayList<>();
 
  917                 for (Map.Entry<Long, Set<Long>> entry : accountIdToDatasourceObjIdMap.entrySet()) {
 
  918                         final Long accountID = entry.getKey();
 
  919                         String datasourceObjIdsCSV = StringUtils.buildCSVString(entry.getValue());
 
  922                                         "( ( relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV + 
" ) )" 
  923                                         + 
" AND ( relationships.account1_id = " + accountID
 
  924                                         + 
" OR relationships.account2_id = " + accountID + 
" ) )" 
  927                 String adiSQLClause = StringUtils.joinAsStrings(adiSQLClauses, 
" OR ");
 
  930                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  936                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  938                 String limitQuery = 
" account_relationships AS relationships";
 
  939                 String limitStr = getMostRecentFilterLimitSQL(filter);
 
  940                 if (!limitStr.isEmpty()) {
 
  941                         limitQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
  945                         = 
"SELECT DISTINCT artifacts.artifact_id AS artifact_id," 
  946                         + 
" artifacts.obj_id AS obj_id," 
  947                         + 
" artifacts.artifact_obj_id AS artifact_obj_id," 
  948                         + 
" artifacts.data_source_obj_id AS data_source_obj_id, " 
  949                         + 
" artifacts.artifact_type_id AS artifact_type_id, " 
  950                         + 
" artifacts.review_status_id AS review_status_id," 
  951                         + 
" tsk_data_artifacts.os_account_obj_id as os_account_obj_id" 
  952                         + 
" FROM blackboard_artifacts as artifacts" 
  953                         + 
" JOIN " + limitQuery
 
  954                         + 
"     ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id" 
  955                         + 
" LEFT JOIN tsk_data_artifacts ON artifacts.artifact_obj_id = tsk_data_artifacts.artifact_obj_id" 
  957                         + 
" WHERE (" + adiSQLClause + 
" )" 
  959                         + (filterSQL.isEmpty() ? 
"" : 
" AND (" + filterSQL + 
" )");
 
  962                 try (CaseDbConnection connection = db.getConnection();
 
  963                                 Statement s = connection.createStatement();
 
  964                                 ResultSet rs = connection.executeQuery(s, queryStr);) { 
 
  965                         Set<Content> relationshipSources = 
new HashSet<>();
 
  966                         relationshipSources.addAll(getDataArtifactsFromResult(rs));
 
  967                         return relationshipSources;
 
  968                 } 
catch (SQLException ex) {
 
  969                         throw new TskCoreException(
"Error getting relationships for account. " + ex.getMessage(), ex);
 
  991                 final List<Long> dataSourceObjIds
 
  992                                 = getSleuthkitCase().getDataSourceObjIds(accountDeviceInstance.getDeviceId());
 
  995                 Set<String> applicableInnerQueryFilters = 
new HashSet<String>(Arrays.asList(
 
 1001                 String innerQueryfilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
 
 1003                 String innerQueryTemplate
 
 1004                                 = 
" SELECT %1$1s as account_id," 
 1005                                 + 
"               data_source_obj_id" 
 1006                                 + 
" FROM account_relationships as relationships" 
 1007                                 + 
" WHERE %2$1s = " + accountDeviceInstance.getAccount().getAccountID() + 
"" 
 1008                                 + 
" AND data_source_obj_id IN (" + StringUtils.buildCSVString(dataSourceObjIds) + 
")" 
 1009                                 + (innerQueryfilterSQL.isEmpty() ? 
"" : 
" AND " + innerQueryfilterSQL);
 
 1011                 String innerQuery1 = String.format(innerQueryTemplate, 
"account1_id", 
"account2_id");
 
 1012                 String innerQuery2 = String.format(innerQueryTemplate, 
"account2_id", 
"account1_id");
 
 1015                 String combinedInnerQuery
 
 1016                                 = 
"SELECT account_id, data_source_obj_id " 
 1017                                 + 
" FROM ( " + innerQuery1 + 
" UNION " + innerQuery2 + 
" ) AS  inner_union" 
 1018                                 + 
" GROUP BY account_id, data_source_obj_id";
 
 1021                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
 1025                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
 1029                                 " accounts.account_id AS account_id," 
 1030                                 + 
" accounts.account_unique_identifier AS account_unique_identifier," 
 1032                                 + 
" account_types.type_name AS type_name," 
 1034                                 + 
" data_source_info.device_id AS device_id" 
 1035                                 + 
" FROM ( " + combinedInnerQuery + 
" ) AS account_device_instances" 
 1036                                 + 
" JOIN accounts AS accounts" 
 1037                                 + 
"             ON accounts.account_id = account_device_instances.account_id" 
 1038                                 + 
" JOIN account_types AS account_types" 
 1039                                 + 
"             ON accounts.account_type_id = account_types.account_type_id" 
 1040                                 + 
" JOIN data_source_info AS data_source_info" 
 1041                                 + 
"             ON account_device_instances.data_source_obj_id = data_source_info.obj_id" 
 1042                                 + (filterSQL.isEmpty() ? 
"" : 
" WHERE " + filterSQL);
 
 1046                                 queryStr = 
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
 
 1049                                 queryStr = 
"SELECT " + queryStr + 
" GROUP BY accounts.account_id, data_source_info.device_id";
 
 1052                                 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
 1056                 try (CaseDbConnection connection = db.getConnection();
 
 1057                                 Statement s = connection.createStatement();
 
 1058                                 ResultSet rs = connection.executeQuery(s, queryStr);) {
 
 1059                         ArrayList<AccountDeviceInstance> accountDeviceInstances = 
new ArrayList<AccountDeviceInstance>();
 
 1061                                 long account_id = rs.getLong(
"account_id");
 
 1062                                 String deviceID = rs.getString(
"device_id");
 
 1063                                 final String type_name = rs.getString(
"type_name");
 
 1064                                 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
 
 1066                                 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
 
 1067                                 Account account = 
new Account(account_id, accountType, account_unique_identifier);
 
 1071                         return accountDeviceInstances;
 
 1072                 } 
catch (SQLException ex) {
 
 1073                         throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
 
 1098                 Set<String> applicableFilters = 
new HashSet<>(Arrays.asList(
 
 1104                 String limitQuery = 
" account_relationships AS relationships";
 
 1105                 String limitStr = getMostRecentFilterLimitSQL(filter);
 
 1106                 if (!limitStr.isEmpty()) {
 
 1107                         limitQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
 1110                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
 1111                 final String queryString = 
"SELECT artifacts.artifact_id AS artifact_id," 
 1112                                 + 
"             artifacts.obj_id AS obj_id," 
 1113                                 + 
"             artifacts.artifact_obj_id AS artifact_obj_id," 
 1114                                 + 
"             artifacts.data_source_obj_id AS data_source_obj_id," 
 1115                                 + 
"             artifacts.artifact_type_id AS artifact_type_id," 
 1116                                 + 
"             artifacts.review_status_id AS review_status_id," 
 1117                                 + 
"     tsk_data_artifacts.os_account_obj_id AS os_account_obj_id" 
 1118                                 + 
" FROM blackboard_artifacts AS artifacts" 
 1119                                 + 
"     JOIN " + limitQuery
 
 1120                                 + 
"             ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id" 
 1121                                 + 
" LEFT JOIN tsk_data_artifacts ON artifacts.artifact_obj_id = tsk_data_artifacts.artifact_obj_id" 
 1122                                 + 
" WHERE (( relationships.account1_id = " + account1.getAccount().getAccountID()
 
 1123                                 + 
" AND relationships.account2_id  = " + account2.getAccount().getAccountID()
 
 1124                                 + 
" ) OR (        relationships.account2_id = " + account1.getAccount().getAccountID()
 
 1125                                 + 
" AND relationships.account1_id =" + account2.getAccount().getAccountID() + 
" ))" 
 1126                                 + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL);
 
 1129                 try (CaseDbConnection connection = db.getConnection();
 
 1130                                 Statement s = connection.createStatement();
 
 1131                                 ResultSet rs = connection.executeQuery(s, queryString);) {
 
 1133                         ArrayList<Content> artifacts = 
new ArrayList<>();
 
 1134                         artifacts.addAll(getDataArtifactsFromResult(rs));               
 
 1136                 } 
catch (SQLException ex) {
 
 1137                         throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
 
 1155                 List<AccountFileInstance> accountFileInstanceList = 
new ArrayList<>();
 
 1156                 @SuppressWarnings(
"deprecation")
 
 1159                 if (artifactList != null && !artifactList.isEmpty()) {
 
 1165                 if (!accountFileInstanceList.isEmpty()) {
 
 1166                         return accountFileInstanceList;
 
 1182                 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";
 
 1183                 List<
Account.
Type> inUseAccounts = 
new ArrayList<>();
 
 1186                 try (CaseDbConnection connection = db.getConnection();
 
 1187                                 Statement s = connection.createStatement();
 
 1188                                 ResultSet rs = connection.executeQuery(s, query);) {
 
 1191                                 String accountTypeName = rs.getString(
"type_name");
 
 1192                                 accountType = this.typeNameToAccountTypeMap.get(accountTypeName);
 
 1194                                 if (accountType == null) {
 
 1195                                         accountType = 
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
 
 1196                                         this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
 
 1199                                 inUseAccounts.add(accountType);
 
 1201                         return inUseAccounts;
 
 1202                 } 
catch (SQLException ex) {
 
 1203                         throw new TskCoreException(
"Error getting account type id", ex);
 
 1219                 if (artifact == null) {
 
 1220                         throw new IllegalArgumentException(
"null arugment passed to getAccountsRelatedToArtifact");
 
 1223                 List<Account> accountList = 
new ArrayList<>();
 
 1225                 try (CaseDbConnection connection = db.getConnection()) {
 
 1231                                 String query = String.format(
"SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1233                                                 + 
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1235                                                 + 
" JOIN account_relationships ON account1_id = account_id" 
 1236                                                 + 
" WHERE relationship_source_obj_id = %d" 
 1238                                                 + 
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1240                                                 + 
" JOIN account_relationships ON account2_id = account_id" 
 1241                                                 + 
" WHERE relationship_source_obj_id = %d) AS unionOfRelationships", artifact.getId(), artifact.getId());
 
 1242                                 try (Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(query)) {
 
 1245                                                 int accountTypeId = rs.getInt(
"account_type_id");
 
 1246                                                 for (Map.Entry<
Account.
Type, Integer> entry : accountTypeToTypeIdMap.entrySet()) {
 
 1247                                                         if (entry.getValue() == accountTypeId) {
 
 1248                                                                 accountType = entry.getKey();
 
 1253                                                 accountList.add(
new Account(rs.getInt(
"account_id"), accountType, rs.getString(
"account_unique_identifier")));
 
 1255                                 } 
catch (SQLException ex) {
 
 1256                                         throw new TskCoreException(
"Unable to get account list for give artifact " + artifact.getId(), ex);
 
 1275                 if (accountTypeToTypeIdMap.containsKey(accountType)) {
 
 1276                         return accountTypeToTypeIdMap.get(accountType);
 
 1293         private String normalizeAccountID(Account.Type accountType, String accountUniqueID) 
throws InvalidAccountIDException {
 
 1295                 if (accountUniqueID == null || accountUniqueID.isEmpty()) {
 
 1296                         throw new InvalidAccountIDException(
"Account id is null or empty.");
 
 1299                 String normalizedAccountID;
 
 1300                 if (accountType.equals(Account.Type.PHONE)) {
 
 1301                         normalizedAccountID = CommunicationsUtils.normalizePhoneNum(accountUniqueID);
 
 1302                 } 
else if (accountType.equals(Account.Type.EMAIL)) {
 
 1303                         normalizedAccountID = CommunicationsUtils.normalizeEmailAddress(accountUniqueID);
 
 1305                         normalizedAccountID = accountUniqueID.toLowerCase().trim();
 
 1308                 return normalizedAccountID;
 
 1323         private String getCommunicationsFilterSQL(CommunicationsFilter commFilter, Set<String> applicableFilters) {
 
 1324                 if (null == commFilter || commFilter.getAndFilters().isEmpty()) {
 
 1329                 StringBuilder sqlSB = 
new StringBuilder();
 
 1330                 boolean first = 
true;
 
 1331                 for (CommunicationsFilter.SubFilter subFilter : commFilter.getAndFilters()) {
 
 1334                         if (applicableFilters.contains(subFilter.getClass().getName())) {
 
 1335                                 String subfilterSQL = subFilter.getSQL(
this);
 
 1336                                 if (!subfilterSQL.isEmpty()) {
 
 1340                                                 sqlSB.append(
" AND ");
 
 1343                                         sqlSB.append(subfilterSQL);
 
 1349                 if (!sqlSB.toString().isEmpty()) {
 
 1350                         sqlStr = 
"( " + sqlSB.toString() + 
" )";
 
 1363         private String getMostRecentFilterLimitSQL(CommunicationsFilter filter) {
 
 1364                 String limitStr = 
"";
 
 1366                 if (filter != null && !filter.getAndFilters().isEmpty()) {
 
 1368                         for (CommunicationsFilter.SubFilter subFilter : filter.getAndFilters()) {
 
 1369                                 if (subFilter.getClass().getName().equals(CommunicationsFilter.MostRecentFilter.class.getName())) {
 
 1370                                         limitStr = subFilter.getSQL(
this);
 
 1390         private List<BlackboardArtifact> getDataArtifactsFromResult(ResultSet resultSet) 
throws SQLException, TskCoreException {
 
 1391                 List<BlackboardArtifact> artifacts = 
new ArrayList<>();
 
 1392                 while (resultSet.next()) {
 
 1393                         BlackboardArtifact.
Type bbartType = db.
getArtifactType(resultSet.getInt(
"artifact_type_id"));
 
 1394                         artifacts.add(
new DataArtifact(db, resultSet.getLong(
"artifact_id"),
 
 1395                                         resultSet.getLong(
"obj_id"), resultSet.getLong(
"artifact_obj_id"),
 
 1396                                         resultSet.getObject(
"data_source_obj_id") != null ? resultSet.getLong(
"data_source_obj_id") : null,
 
 1397                                         bbartType.getTypeID(),
 
 1398                                         bbartType.getTypeName(), bbartType.getDisplayName(),
 
 1399                                         BlackboardArtifact.ReviewStatus.withID(resultSet.getInt(
"review_status_id")),
 
 1400                                         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
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)
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)