diff --git a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java index 0b36732ebc431b944da960470fb1707a5a8fe3c9..4fefb10606bb1f8cb59694f35222527d843212a3 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java @@ -259,11 +259,12 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam * * @return AccountFileInstance * - * @throws TskCoreException exception thrown if a critical error occurs - * within TSK core + * @throws TskCoreException If a critical error occurs within TSK + * core + * @throws InvalidAccountIDException If the account identifier is not valid. */ // NOTE: Full name given for Type for doxygen linking - public AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile) throws TskCoreException { + public AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile) throws TskCoreException, InvalidAccountIDException { // make or get the Account (unique at the case-level) Account account = getOrCreateAccount(accountType, normalizeAccountID(accountType, accountUniqueID)); @@ -294,11 +295,12 @@ public AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Acc * * @return Account, returns NULL is no matching account found * - * @throws TskCoreException exception thrown if a critical error occurs - * within TSK core + * @throws TskCoreException If a critical error occurs within TSK + * core. + * @throws InvalidAccountIDException If the account identifier is not valid. */ // NOTE: Full name given for Type for doxygen linking - public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID) throws TskCoreException { + public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID) throws TskCoreException, InvalidAccountIDException { Account account = null; CaseDbConnection connection = db.getConnection(); db.acquireSingleUserCaseReadLock(); @@ -330,12 +332,12 @@ public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, Stri * instances and between all recipient account instances. All account * instances must be from the same data source. * - * @param sender sender account - * @param recipients list of recipients - * @param sourceArtifact Artifact that relationships were derived from - * @param relationshipType The type of relationships to be created + * @param sender Sender account, may be null. + * @param recipients List of recipients, may be empty. + * @param sourceArtifact Artifact that relationships were derived from. + * @param relationshipType The type of relationships to be created. * @param dateTime Date of communications/relationship, as epoch - * seconds + * seconds. * * * @throws org.sleuthkit.datamodel.TskCoreException @@ -402,10 +404,12 @@ public void addRelationships(AccountFileInstance sender, List<AccountFileInstanc * * @return A matching account, either existing or newly created. * - * @throws TskCoreException exception thrown if a critical error occurs - * within TSK core + * @throws TskCoreException exception thrown if a critical error + * occurs within TSK core + * @throws InvalidAccountIDException If the account identifier is not valid. + * */ - private Account getOrCreateAccount(Account.Type accountType, String accountUniqueID) throws TskCoreException { + private Account getOrCreateAccount(Account.Type accountType, String accountUniqueID) throws TskCoreException, InvalidAccountIDException { Account account = getAccount(accountType, accountUniqueID); if (null == account) { String query = " INTO accounts (account_type_id, account_unique_identifier) " @@ -1372,17 +1376,25 @@ int getAccountTypeId(Account.Type accountType) { * @param accountUniqueID The account id to normalize * * @return The normalized account id. + * + * @throws InvalidAccountIDException If the account identifier is not valid. */ - private String normalizeAccountID(Account.Type accountType, String accountUniqueID) throws TskCoreException { - String normailzeAccountID = accountUniqueID; + private String normalizeAccountID(Account.Type accountType, String accountUniqueID) throws InvalidAccountIDException { + if (accountUniqueID == null || accountUniqueID.isEmpty()) { + throw new InvalidAccountIDException("Account id is null or empty."); + } + + String normalizedAccountID; if (accountType.equals(Account.Type.PHONE)) { - normailzeAccountID = CommunicationsUtils.normalizePhoneNum(accountUniqueID); + normalizedAccountID = CommunicationsUtils.normalizePhoneNum(accountUniqueID); } else if (accountType.equals(Account.Type.EMAIL)) { - normailzeAccountID = CommunicationsUtils.normalizeEmailAddress(accountUniqueID); + normalizedAccountID = CommunicationsUtils.normalizeEmailAddress(accountUniqueID); + } else { + normalizedAccountID = accountUniqueID.toLowerCase().trim(); } - return normailzeAccountID; + return normalizedAccountID; } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsUtils.java b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsUtils.java index f8ebf2ad7f98d3d06ee2c857168aaa1d1c131d04..2484b1e16babe1bd61b1b0fe5fcb450b45855555 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsUtils.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsUtils.java @@ -18,65 +18,100 @@ */ package org.sleuthkit.datamodel; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.validator.routines.EmailValidator; /** * Provides general utility methods related to communications artifacts. - * + * */ public final class CommunicationsUtils { - + + // These symbols are allowed in dialed or written forms of phone numbers. + // A '+' is allowed only as a leading digit and hence not inlcuded here. + private static final Set<String> TELEPHONY_CHARS = new HashSet<>(Arrays.asList( + "-", "(", ")", "#", "*", "," + )); + + private static final int MIN_PHONENUMBER_LEN = 3; + /** - * Empty private constructor. - */ - private CommunicationsUtils() { - } - + * Empty private constructor. + */ + private CommunicationsUtils() { + } + /** - * Normalize the given phone number by removing all non numeric characters, - * except for a leading +. + * Normalize the given phone number by removing all non numeric characters, + * except: a leading + # or * or , * - * @param phoneNum The string to normalize. + * Note: this method intentionally performs a rather lenient validation of + * the phone number in order to not drop any collected data. + * + * @param phoneNumber The string to normalize. * * @return The normalized phone number. - * - * @throws TskCoreException If the given string is not a valid phone number. - * + * + * @throws InvalidAccountIDException If the given string is not a valid + * phone number. + * */ - public static String normalizePhoneNum(String phoneNum) throws TskCoreException { - if (isValidPhoneNumber(phoneNum)) { - return phoneNum.replaceAll("[^0-9\\+]", ""); - } else { - throw new TskCoreException(String.format("Input string is not a valid phone number: %s", phoneNum)); - } + public static String normalizePhoneNum(String phoneNumber) throws InvalidAccountIDException { + + if (StringUtils.isEmpty(phoneNumber)) { + throw new InvalidAccountIDException(String.format("Input phone number is empty or null.")); + } + + if (isValidPhoneNumber(phoneNumber) == false) { + throw new InvalidAccountIDException(String.format("Input string is not a valid phone number: %s", phoneNumber)); + } + + String normalizedNumber = phoneNumber.trim(); + normalizedNumber = normalizedNumber.replaceAll("\\s+", ""); // remove spaces. + normalizedNumber = normalizedNumber.replaceAll("[\\-()]", ""); // remove parens & dashes. + + // ensure a min length + if (normalizedNumber.length() < MIN_PHONENUMBER_LEN) { + throw new InvalidAccountIDException("Invalid phone number string " + phoneNumber); + + } + return normalizedNumber; } /** - * Normalizes the given email address by converting it to lowercase. + * Normalizes the given email address. * * @param emailAddress The email address string to be normalized. * * @return The normalized email address. - * @throws TskCoreException If the given string is not a valid email address. + * + * @throws InvalidAccountIDException If the given string is not a valid + * email address. */ - public static String normalizeEmailAddress(String emailAddress) throws TskCoreException { - - if (isValidEmailAddress(emailAddress)) { - return emailAddress.toLowerCase(); - } else { - throw new TskCoreException(String.format("Input string is not a valid email address: %s", emailAddress)); - } + public static String normalizeEmailAddress(String emailAddress) throws InvalidAccountIDException { + + if (StringUtils.isEmpty(emailAddress)) { + throw new InvalidAccountIDException(String.format("Input email address is empty or null.")); + } + + if (isValidEmailAddress(emailAddress) == false) { + throw new InvalidAccountIDException(String.format("Input string is not a valid email address: %s", emailAddress)); + } + + return emailAddress.toLowerCase().trim(); } - + /** - * Checks if the given accountId is a valid id for - * the specified account type. - * - * @param accountType Account type. + * Checks if the given accountId is a valid id for the specified account + * type. + * + * @param accountType Account type. * @param accountUniqueID Id to check. - * - * @return True, if the id is a valid id for the given account type, False otherwise. + * + * @return True, if the id is a valid id for the given account type, False + * otherwise. */ public static boolean isValidAccountId(Account.Type accountType, String accountUniqueID) { if (accountType == Account.Type.PHONE) { @@ -85,37 +120,92 @@ public static boolean isValidAccountId(Account.Type accountType, String accountU if (accountType == Account.Type.EMAIL) { return isValidEmailAddress(accountUniqueID); } - + return !StringUtils.isEmpty(accountUniqueID); } - + /** * Checks if the given string is a valid phone number. * + * NOTE: this method intentionally performs a rather lenient validation of + * the phone number in order to not drop any collected data. + * * @param phoneNum Phone number string to check. * - * @return True if the given string is a valid phone number, false otherwise. + * @return True if the given string is a valid phone number, false + * otherwise. */ public static boolean isValidPhoneNumber(String phoneNum) { - if (!StringUtils.isEmpty(phoneNum)) { - return phoneNum.matches("\\+?[0-9()\\-\\s]+"); + if (StringUtils.isEmpty(phoneNum)) { + return false; + } + + String trimmedPhoneNum = phoneNum.trim(); + + // A phone number may have a leading '+', special telephony chars, or digits. + // Anything else implies an invalid phone number. + for (int i = 0; i < trimmedPhoneNum.length(); i++) { + if (!((trimmedPhoneNum.charAt(i) == '+' && i == 0) // a '+' is allowed only at the beginning + || isValidPhoneChar(trimmedPhoneNum.charAt(i)))) { + return false; + } } - return false; + + return true; + } + + /** + * Checks if the given character is a valid character for a phone number. + * + * @param ch Character to check. + * + * @return True, if its a valid phone number character, false, otherwise. + */ + private static boolean isValidPhoneChar(char ch) { + return Character.isSpaceChar(ch) + || Character.isDigit(ch) + || TELEPHONY_CHARS.contains(String.valueOf(ch)); } - + /** * Checks if the given string is a valid email address. * + * Note: this method intentionally performs a rather lenient validation in + * order to not drop any collected data. + * + * Note: We are requiring that an email address have a "." on the right-hand + * side to allow us to differentiate between app-specific identifiers and + * email addresses. We realize that some emails can be sent within + * enterprises without a ".', but that this is less common than encountering + * app-specific identifiers of the form a@b. + * * @param emailAddress String to check. * - * @return True if the given string is a valid email address, false otherwise. + * @return True if the given string is a valid email address, false + * otherwise. */ public static boolean isValidEmailAddress(String emailAddress) { - if (!StringUtils.isEmpty(emailAddress)) { - EmailValidator validator = EmailValidator.getInstance(true, true); - return validator.isValid(emailAddress); + if (StringUtils.isEmpty(emailAddress)) { + return false; + } + + if (emailAddress.contains("@") == false + || emailAddress.contains(".") == false ) { + return false; + } + + // emsure there's a username and domain + String[] tokens = emailAddress.split("@"); + if (tokens.length < 2 + || StringUtils.isEmpty(tokens[0]) + || StringUtils.isEmpty(tokens[1])) { + return false; } - return false; + // ensure domain has name and suffix + String[] tokens2 = tokens[1].split("\\."); + return !(tokens2.length < 2 + || StringUtils.isEmpty(tokens2[0]) + || StringUtils.isEmpty(tokens2[1])); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/InvalidAccountIDException.java b/bindings/java/src/org/sleuthkit/datamodel/InvalidAccountIDException.java new file mode 100644 index 0000000000000000000000000000000000000000..4da90aac913c19bc2bdf0e41f54e9e68b10b005b --- /dev/null +++ b/bindings/java/src/org/sleuthkit/datamodel/InvalidAccountIDException.java @@ -0,0 +1,54 @@ +/* + * Sleuth Kit Data Model + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier <at> sleuthkit <dot> org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.datamodel; + +/** + * Exception thrown when an account identifier is not valid. + * + */ +public class InvalidAccountIDException extends TskCoreException { + + private static final long serialVersionUID = 1L; + + /** + * Default constructor when error message is not available + */ + public InvalidAccountIDException() { + super("No error message available."); + } + + /** + * Create exception containing the error message. + * + * @param msg Message. + */ + public InvalidAccountIDException(String msg) { + super(msg); + } + + /** + * Create exception containing the error message and cause exception. + * + * @param msg Message. + * @param ex Underlying exception. + */ + public InvalidAccountIDException(String msg, Exception ex) { + super(msg, ex); + } +} diff --git a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java index f6db50b6dd347037e3374dba6683da3d20358843..1ec6227ecbf10788d652845edb0a32e41a7b0886 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java +++ b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java @@ -23,6 +23,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -32,9 +34,9 @@ import org.sleuthkit.datamodel.Blackboard.BlackboardException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.CommunicationsUtils; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.InvalidAccountIDException; import org.sleuthkit.datamodel.Relationship; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -65,6 +67,7 @@ */ public final class CommunicationArtifactsHelper extends ArtifactHelperBase { + private static final Logger LOGGER = Logger.getLogger(CommunicationArtifactsHelper.class.getName()); /** * Enum for message read status */ @@ -326,16 +329,21 @@ private void createContactMethodAccountAndRelationship(Account.Type accountType, // Find/Create an account instance for each of the contact method // Create a relationship between selfAccount and contactAccount - if (CommunicationsUtils.isValidAccountId(accountType, accountUniqueID)) { - AccountFileInstance contactAccountInstance = createAccountInstance(accountType, accountUniqueID); - - // Create a relationship between self account and the contact account + if (StringUtils.isNotBlank(accountUniqueID)) { try { - getSleuthkitCase().getCommunicationsManager().addRelationships(getSelfAccountInstance(), - Collections.singletonList(contactAccountInstance), sourceArtifact, Relationship.Type.CONTACT, dateTime); - } catch (TskDataException ex) { - throw new TskCoreException(String.format("Failed to create relationship between account = %s and account = %s.", - getSelfAccountInstance().getAccount(), contactAccountInstance.getAccount()), ex); + AccountFileInstance contactAccountInstance = createAccountInstance(accountType, accountUniqueID); + + // Create a relationship between self account and the contact account + try { + getSleuthkitCase().getCommunicationsManager().addRelationships(getSelfAccountInstance(), + Collections.singletonList(contactAccountInstance), sourceArtifact, Relationship.Type.CONTACT, dateTime); + } catch (TskDataException ex) { + throw new TskCoreException(String.format("Failed to create relationship between account = %s and account = %s.", + getSelfAccountInstance().getAccount(), contactAccountInstance.getAccount()), ex); + } + } + catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Failed to create account with id %s", accountUniqueID), ex); } } } @@ -352,7 +360,7 @@ private void createContactMethodAccountAndRelationship(Account.Type accountType, * @throws TskCoreException If there is an error creating the account * instance. */ - private AccountFileInstance createAccountInstance(Account.Type accountType, String accountUniqueID) throws TskCoreException { + private AccountFileInstance createAccountInstance(Account.Type accountType, String accountUniqueID) throws TskCoreException, InvalidAccountIDException { return getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(accountType, accountUniqueID, getModuleName(), getContent()); } @@ -508,19 +516,36 @@ public BlackboardArtifact addMessage(String messageType, addMessageReadStatusIfKnown(readStatus, attributes); addCommDirectionIfKnown(direction, attributes); + // Get the self account instance + AccountFileInstance selfAccountInstanceLocal = null; + try { + selfAccountInstanceLocal = getSelfAccountInstance(); + } catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Failed to get/create self account with id %s", selfAccountId), ex); + } + // set sender attribute and create sender account AccountFileInstance senderAccountInstance = null; - if (CommunicationsUtils.isValidAccountId(moduleAccountsType, senderId)) { - senderAccountInstance = createAccountInstance(moduleAccountsType, senderId); - } + if (StringUtils.isNotBlank(senderId)) { + try { + senderAccountInstance = createAccountInstance(moduleAccountsType, senderId); + } catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Invalid account identifier %s", senderId), ex); + } + } + // set recipient attribute and create recipient accounts List<AccountFileInstance> recipientAccountsList = new ArrayList<>(); String recipientsStr = ""; if (!isEffectivelyEmpty(recipientIdsList)) { for (String recipient : recipientIdsList) { - if (CommunicationsUtils.isValidAccountId(moduleAccountsType, recipient)) { - recipientAccountsList.add(createAccountInstance(moduleAccountsType, recipient)); + if (StringUtils.isNotBlank(recipient)) { + try { + recipientAccountsList.add(createAccountInstance(moduleAccountsType, recipient)); + } catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Invalid account identifier %s", senderId), ex); + } } } // Create a comma separated string of recipients @@ -530,8 +555,8 @@ public BlackboardArtifact addMessage(String messageType, switch (direction) { case OUTGOING: // if no sender, selfAccount substitutes caller. - if (StringUtils.isEmpty(senderId)) { - senderAccountInstance = getSelfAccountInstance(); + if (StringUtils.isEmpty(senderId) && selfAccountInstanceLocal != null) { + senderAccountInstance = selfAccountInstanceLocal; } // sender becomes PHONE_FROM if (senderAccountInstance != null) { @@ -543,9 +568,9 @@ public BlackboardArtifact addMessage(String messageType, case INCOMING: // if no recipeint specified, selfAccount substitutes recipient - if (isEffectivelyEmpty(recipientIdsList)) { - recipientsStr = getSelfAccountInstance().getAccount().getTypeSpecificID(); - recipientAccountsList.add(getSelfAccountInstance()); + if (isEffectivelyEmpty(recipientIdsList) && selfAccountInstanceLocal != null ) { + recipientsStr = selfAccountInstanceLocal.getAccount().getTypeSpecificID(); + recipientAccountsList.add(selfAccountInstanceLocal); } // caller becomes PHONE_FROM if (senderAccountInstance != null) { @@ -555,14 +580,14 @@ public BlackboardArtifact addMessage(String messageType, addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, recipientsStr, attributes); break; default: // direction UNKNOWN - if (StringUtils.isEmpty(senderId)) { + if (StringUtils.isEmpty(senderId) && selfAccountInstanceLocal != null ) { // if no sender, selfAccount substitutes caller. - senderAccountInstance = getSelfAccountInstance(); + senderAccountInstance = selfAccountInstanceLocal; } - else if (isEffectivelyEmpty(recipientIdsList)) { + else if (isEffectivelyEmpty(recipientIdsList) && selfAccountInstanceLocal != null) { // else if no recipient specified, selfAccount substitutes recipient - recipientsStr = getSelfAccountInstance().getAccount().getTypeSpecificID(); - recipientAccountsList.add(getSelfAccountInstance()); + recipientsStr = selfAccountInstanceLocal.getAccount().getTypeSpecificID(); + recipientAccountsList.add(selfAccountInstanceLocal); } // save phone numbers in direction agnostic attributes @@ -733,6 +758,13 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction, throw new IllegalArgumentException("Either a caller id, or at least one callee id must be provided for a call log."); } + AccountFileInstance selfAccountInstanceLocal = null; + try { + selfAccountInstanceLocal = getSelfAccountInstance(); + } catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Failed to get/create self account with id %s", selfAccountId), ex); + } + BlackboardArtifact callLogArtifact; Collection<BlackboardAttribute> attributes = new ArrayList<>(); @@ -745,8 +777,12 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction, addCommDirectionIfKnown(direction, attributes); AccountFileInstance callerAccountInstance = null; - if (CommunicationsUtils.isValidAccountId(moduleAccountsType, callerId)) { - callerAccountInstance = createAccountInstance(moduleAccountsType, callerId); + if (StringUtils.isNotBlank(callerId)) { + try { + callerAccountInstance = createAccountInstance(moduleAccountsType, callerId); + } catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Failed to create account with id %s", callerId), ex); + } } // Create a comma separated string of callee @@ -755,8 +791,13 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction, if (!isEffectivelyEmpty(calleeIdsList)) { calleesStr = addressListToString(calleeIdsList); for (String callee : calleeIdsList) { - if (CommunicationsUtils.isValidAccountId(moduleAccountsType, callee)) { - recipientAccountsList.add(createAccountInstance(moduleAccountsType, callee)); + if (StringUtils.isNotBlank(callee)) { + try{ + recipientAccountsList.add(createAccountInstance(moduleAccountsType, callee)); + } + catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Failed to create account with id %s", callerId), ex); + } } } } @@ -768,8 +809,8 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction, throw new IllegalArgumentException("Callee not provided for an outgoing call."); } // if no caller, selfAccount substitutes caller. - if (StringUtils.isEmpty(callerId)) { - callerAccountInstance = getSelfAccountInstance(); + if (StringUtils.isEmpty(callerId) && selfAccountInstanceLocal != null ) { + callerAccountInstance = selfAccountInstanceLocal; } // caller becomes PHONE_FROM if (callerAccountInstance != null) { @@ -785,9 +826,9 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction, throw new IllegalArgumentException("Caller Id not provided for incoming call."); } // if no callee specified, selfAccount substitutes callee - if (isEffectivelyEmpty(calleeIdsList)) { - calleesStr = getSelfAccountInstance().getAccount().getTypeSpecificID(); - recipientAccountsList.add(getSelfAccountInstance()); + if (isEffectivelyEmpty(calleeIdsList) && selfAccountInstanceLocal != null) { + calleesStr = selfAccountInstanceLocal.getAccount().getTypeSpecificID(); + recipientAccountsList.add(selfAccountInstanceLocal); } // caller becomes PHONE_FROM if (callerAccountInstance != null) { @@ -816,7 +857,7 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction, recipientAccountsList, callLogArtifact, Relationship.Type.CALL_LOG, startDateTime); } catch (TskDataException ex) { throw new TskCoreException(String.format("Failed to create Call log relationships between caller account = %s and callees = %s.", - callerAccountInstance.getAccount(), calleesStr), ex); + (callerAccountInstance!= null) ? callerAccountInstance.getAccount() : "", calleesStr), ex); } // post artifact @@ -940,7 +981,7 @@ private void addMessageReadStatusIfKnown(MessageReadStatus readStatus, Collectio * @return Self account instance. * @throws TskCoreException */ - private synchronized AccountFileInstance getSelfAccountInstance() throws TskCoreException { + private synchronized AccountFileInstance getSelfAccountInstance() throws TskCoreException, InvalidAccountIDException { if (selfAccountInstance == null) { selfAccountInstance = getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(selfAccountType, selfAccountId, this.getModuleName(), getContent()); } diff --git a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/WebBrowserArtifactsHelper.java b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/WebBrowserArtifactsHelper.java index f3b7814666bf318c24a74dfe37b2650c7388a49a..3cc193a40acd95a9cb1848a1f635b4e8c1767872 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/WebBrowserArtifactsHelper.java +++ b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/WebBrowserArtifactsHelper.java @@ -24,14 +24,16 @@ import java.util.Collection; import java.util.Collections; import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.Blackboard.BlackboardException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.CommunicationsManager; -import org.sleuthkit.datamodel.CommunicationsUtils; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.InvalidAccountIDException; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -44,6 +46,8 @@ */ public final class WebBrowserArtifactsHelper extends ArtifactHelperBase { + private static final Logger LOGGER = Logger.getLogger(WebBrowserArtifactsHelper.class.getName()); + /** * Creates a WebBrowserArtifactsHelper. * @@ -300,12 +304,21 @@ public BlackboardArtifact addWebFormAddress(String personName, String email, Collection<BlackboardAttribute> attributes = new ArrayList<>(); CommunicationsManager commManager = this.getSleuthkitCase().getCommunicationsManager(); - if (CommunicationsUtils.isValidEmailAddress(email)) { + + if (StringUtils.isNotEmpty(email)) { + try { commManager.createAccountFileInstance(Account.Type.EMAIL, email, this.getModuleName(), this.getContent()); + } catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Invalid account identifier %s", email), ex); + } } - if(CommunicationsUtils.isValidPhoneNumber(phoneNumber)) { + if(StringUtils.isNotEmpty(phoneNumber)) { + try { commManager.createAccountFileInstance(Account.Type.PHONE, phoneNumber, this.getModuleName(), this.getContent()); + } catch (InvalidAccountIDException ex) { + LOGGER.log(Level.WARNING, String.format("Invalid account identifier %s", phoneNumber), ex); + } } // create artifact