19 package org.sleuthkit.datamodel.blackboardutils;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Optional;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29 import org.apache.commons.lang3.StringUtils;
87 private final String msgReadStr;
90 this.msgReadStr = readStatus;
106 private final String dirStr;
125 private final String typeStr;
140 private final String selfAccountId;
166 super(caseDb, moduleName, srcContent, ingestJobId);
167 this.moduleAccountsType = accountsType;
169 this.selfAccountId = ((
DataSource) getContent().getDataSource()).getDeviceId();
195 super(caseDb, moduleName, srcContent, ingestJobId);
196 this.moduleAccountsType = accountsType;
197 this.selfAccountType = selfAccountType;
198 this.selfAccountId = selfAccountId;
222 this(caseDb, moduleName, srcContent, accountsType, null);
249 this(caseDb, moduleName, srcContent, accountsType, selfAccountType, selfAccountId, null);
274 String phoneNumber, String homePhoneNumber,
277 homePhoneNumber, mobilePhoneNumber, emailAddr,
278 Collections.emptyList());
307 String phoneNumber, String homePhoneNumber,
308 String mobilePhoneNumber, String emailAddr,
309 Collection<BlackboardAttribute> additionalAttributes)
throws TskCoreException,
BlackboardException {
312 boolean hasAnyIdAttribute =
false;
313 if (additionalAttributes != null) {
315 if ((attr.getAttributeType().getTypeName().startsWith(
"TSK_PHONE"))
316 || (attr.getAttributeType().getTypeName().startsWith(
"TSK_EMAIL"))
317 || (attr.getAttributeType().getTypeName().startsWith(
"TSK_ID"))) {
318 hasAnyIdAttribute =
true;
326 if (StringUtils.isEmpty(phoneNumber) && StringUtils.isEmpty(homePhoneNumber)
327 && StringUtils.isEmpty(mobilePhoneNumber) && StringUtils.isEmpty(emailAddr)
328 && (!hasAnyIdAttribute)) {
329 throw new IllegalArgumentException(
"At least one phone number or email address or an id must be provided.");
333 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
344 attributes.addAll(additionalAttributes);
345 Content content = getContent();
350 createContactMethodAccountAndRelationship(
Account.
Type.
PHONE, phoneNumber, contactArtifact, 0);
351 createContactMethodAccountAndRelationship(
Account.
Type.
PHONE, homePhoneNumber, contactArtifact, 0);
352 createContactMethodAccountAndRelationship(
Account.
Type.
PHONE, mobilePhoneNumber, contactArtifact, 0);
353 createContactMethodAccountAndRelationship(
Account.
Type.
EMAIL, emailAddr, contactArtifact, 0);
356 if ((additionalAttributes != null) && hasAnyIdAttribute) {
358 if (bba.getAttributeType().getTypeName().startsWith(
"TSK_PHONE")) {
359 createContactMethodAccountAndRelationship(
Account.
Type.
PHONE, bba.getValueString(), contactArtifact, 0);
360 }
else if (bba.getAttributeType().getTypeName().startsWith(
"TSK_EMAIL")) {
361 createContactMethodAccountAndRelationship(
Account.
Type.
EMAIL, bba.getValueString(), contactArtifact, 0);
362 }
else if (bba.getAttributeType().getTypeName().startsWith(
"TSK_ID")) {
363 createContactMethodAccountAndRelationship(this.moduleAccountsType, bba.getValueString(), contactArtifact, 0);
369 Optional<Long> ingestJobId = getIngestJobId();
370 getSleuthkitCase().getBlackboard().postArtifact(contactArtifact, getModuleName(), ingestJobId.orElse(null));
372 return contactArtifact;
383 private void createContactMethodAccountAndRelationship(
Account.
Type accountType,
385 long dateTime)
throws TskCoreException {
389 if (StringUtils.isNotBlank(accountUniqueID)) {
391 AccountFileInstance contactAccountInstance = createAccountInstance(accountType, accountUniqueID);
395 getSleuthkitCase().getCommunicationsManager().addRelationships(getSelfAccountInstance(),
398 throw new TskCoreException(String.format(
"Failed to create relationship between account = %s and account = %s.",
399 getSelfAccountInstance().getAccount(), contactAccountInstance.
getAccount()), ex);
401 }
catch (InvalidAccountIDException ex) {
402 LOGGER.log(Level.WARNING, String.format(
"Failed to create account with id %s", accountUniqueID));
419 private AccountFileInstance createAccountInstance(Account.Type accountType, String accountUniqueID)
throws TskCoreException, InvalidAccountIDException {
420 Optional<Long> ingestJobId = getIngestJobId();
421 return getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(accountType, accountUniqueID, getModuleName(), getContent(), null, ingestJobId.orElse(null));
451 String subject, String messageText, String threadId)
throws TskCoreException,
BlackboardException {
453 senderId, recipientId, dateTime, readStatus,
454 subject, messageText, threadId,
455 Collections.emptyList());
485 String messageText, String threadId,
486 Collection<BlackboardAttribute> otherAttributesList)
throws TskCoreException,
BlackboardException {
490 Arrays.asList(recipientId),
491 dateTime, readStatus,
492 subject, messageText, threadId,
493 otherAttributesList);
521 List<String> recipientIdsList,
523 String subject, String messageText, String threadId)
throws TskCoreException,
BlackboardException {
525 senderId, recipientIdsList,
526 dateTime, readStatus,
527 subject, messageText, threadId,
528 Collections.emptyList());
556 List<String> recipientIdsList,
558 String subject, String messageText,
560 Collection<BlackboardAttribute> otherAttributesList)
throws TskCoreException,
BlackboardException {
563 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
569 addMessageReadStatusIfKnown(readStatus, attributes);
570 addCommDirectionIfKnown(direction, attributes);
575 selfAccountInstanceLocal = getSelfAccountInstance();
577 LOGGER.log(Level.WARNING, String.format(
"Failed to get/create self account with id %s", selfAccountId), ex);
582 if (StringUtils.isNotBlank(senderId)) {
584 senderAccountInstance = createAccountInstance(moduleAccountsType, senderId);
586 LOGGER.log(Level.WARNING, String.format(
"Invalid account identifier %s", senderId));
591 List<AccountFileInstance> recipientAccountsList =
new ArrayList<>();
592 String recipientsStr =
"";
593 if (!isEffectivelyEmpty(recipientIdsList)) {
594 for (String recipient : recipientIdsList) {
595 if (StringUtils.isNotBlank(recipient)) {
597 recipientAccountsList.add(createAccountInstance(moduleAccountsType, recipient));
599 LOGGER.log(Level.WARNING, String.format(
"Invalid account identifier %s", recipient));
604 recipientsStr = addressListToString(recipientIdsList);
610 if (StringUtils.isEmpty(senderId) && selfAccountInstanceLocal != null) {
611 senderAccountInstance = selfAccountInstanceLocal;
614 if (senderAccountInstance != null) {
623 if (isEffectivelyEmpty(recipientIdsList) && selfAccountInstanceLocal != null) {
625 recipientAccountsList.add(selfAccountInstanceLocal);
628 if (senderAccountInstance != null) {
635 if (StringUtils.isEmpty(senderId) && selfAccountInstanceLocal != null) {
637 senderAccountInstance = selfAccountInstanceLocal;
638 }
else if (isEffectivelyEmpty(recipientIdsList) && selfAccountInstanceLocal != null) {
641 recipientAccountsList.add(selfAccountInstanceLocal);
645 if (senderAccountInstance != null) {
657 attributes.addAll(otherAttributesList);
660 Content content = getContent();
665 getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance,
668 throw new TskCoreException(String.format(
"Failed to create Message relationships between sender account = %s and recipients = %s.",
673 Optional<Long> ingestJobId = getIngestJobId();
674 getSleuthkitCase().getBlackboard().postArtifact(msgArtifact, getModuleName(), ingestJobId.orElse(null));
703 String callerId, String calleeId,
705 return addCalllog(direction, callerId, calleeId,
706 startDateTime, endDateTime, mediaType,
707 Collections.emptyList());
736 long startDateTime,
long endDateTime,
738 Collection<BlackboardAttribute> otherAttributesList)
throws TskCoreException,
BlackboardException {
741 Arrays.asList(calleeId),
742 startDateTime, endDateTime,
744 otherAttributesList);
771 Collection<String> calleeIdsList,
772 long startDateTime,
long endDateTime,
775 return addCalllog(direction, callerId, calleeIdsList,
776 startDateTime, endDateTime,
778 Collections.emptyList());
806 Collection<String> calleeIdsList,
807 long startDateTime,
long endDateTime,
809 Collection<BlackboardAttribute> otherAttributesList)
throws TskCoreException,
BlackboardException {
812 if (StringUtils.isEmpty(callerId) && (isEffectivelyEmpty(calleeIdsList))) {
813 throw new IllegalArgumentException(
"Either a caller id, or at least one callee id must be provided for a call log.");
818 selfAccountInstanceLocal = getSelfAccountInstance();
820 LOGGER.log(Level.WARNING, String.format(
"Failed to get/create self account with id %s", selfAccountId), ex);
823 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
828 addCommDirectionIfKnown(direction, attributes);
831 if (StringUtils.isNotBlank(callerId)) {
833 callerAccountInstance = createAccountInstance(moduleAccountsType, callerId);
835 LOGGER.log(Level.WARNING, String.format(
"Failed to create account with id %s", callerId));
840 List<AccountFileInstance> recipientAccountsList =
new ArrayList<>();
841 String calleesStr =
"";
842 if (!isEffectivelyEmpty(calleeIdsList)) {
843 calleesStr = addressListToString(calleeIdsList);
844 for (String callee : calleeIdsList) {
845 if (StringUtils.isNotBlank(callee)) {
847 recipientAccountsList.add(createAccountInstance(moduleAccountsType, callee));
849 LOGGER.log(Level.WARNING, String.format(
"Failed to create account with id %s", callee));
858 if (isEffectivelyEmpty(calleeIdsList)) {
859 throw new IllegalArgumentException(
"Callee not provided for an outgoing call.");
862 if (StringUtils.isEmpty(callerId) && selfAccountInstanceLocal != null) {
863 callerAccountInstance = selfAccountInstanceLocal;
866 if (callerAccountInstance != null) {
875 if (StringUtils.isEmpty(callerId)) {
876 throw new IllegalArgumentException(
"Caller Id not provided for incoming call.");
879 if (isEffectivelyEmpty(calleeIdsList) && selfAccountInstanceLocal != null) {
881 recipientAccountsList.add(selfAccountInstanceLocal);
884 if (callerAccountInstance != null) {
893 if (callerAccountInstance != null) {
901 attributes.addAll(otherAttributesList);
903 Content content = getContent();
910 getSleuthkitCase().getCommunicationsManager().addRelationships(callerAccountInstance,
913 throw new TskCoreException(String.format(
"Failed to create Call log relationships between caller account = %s and callees = %s.",
914 (callerAccountInstance != null) ? callerAccountInstance.
getAccount() :
"", calleesStr), ex);
918 Optional<Long> ingestJobId = getIngestJobId();
919 getSleuthkitCase().getBlackboard().postArtifact(callLogArtifact, getModuleName(), ingestJobId.orElse(null));
922 return callLogArtifact;
936 message.addAttribute(blackboardAttribute);
939 List<BlackboardArtifact> assocObjectArtifacts =
new ArrayList<>();
940 Collection<FileAttachment> fileAttachments = attachments.getFileAttachments();
942 long attachedFileObjId = fileAttachment.getObjectId();
943 if (attachedFileObjId >= 0) {
945 DataArtifact artifact = associateAttachmentWithMessage(message, attachedFile);
946 assocObjectArtifacts.add(artifact);
951 Optional<Long> ingestJobId = getIngestJobId();
952 getSleuthkitCase().getBlackboard().postArtifacts(assocObjectArtifacts, getModuleName(), ingestJobId.orElse(null));
954 throw new TskCoreException(
"Error posting TSK_ASSOCIATED_ARTIFACT artifacts for attachments", ex);
971 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
979 private String addressListToString(Collection<String> addressList) {
981 String toAddresses =
"";
982 if (addressList != null && (!addressList.isEmpty())) {
983 StringBuilder toAddressesSb =
new StringBuilder();
984 for (String address : addressList) {
985 if (!StringUtils.isEmpty(address)) {
986 toAddressesSb = toAddressesSb.length() > 0 ? toAddressesSb.append(
", ").append(address) : toAddressesSb.append(address);
989 toAddresses = toAddressesSb.toString();
1004 private boolean isEffectivelyEmpty(Collection<String> idList) {
1006 if (idList == null || idList.isEmpty()) {
1010 for (String
id : idList) {
1011 if (!StringUtils.isEmpty(
id)) {
1023 private void addCommDirectionIfKnown(CommunicationDirection direction, Collection<BlackboardAttribute> attributes) {
1024 if (direction != CommunicationDirection.UNKNOWN) {
1025 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, getModuleName(), direction.getDisplayName()));
1032 private void addMessageReadStatusIfKnown(MessageReadStatus readStatus, Collection<BlackboardAttribute> attributes) {
1033 if (readStatus != MessageReadStatus.UNKNOWN) {
1034 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_READ_STATUS, getModuleName(), (readStatus == MessageReadStatus.READ) ? 1 : 0));
1046 private synchronized AccountFileInstance getSelfAccountInstance() throws TskCoreException, InvalidAccountIDException {
1047 if (selfAccountInstance == null) {
1048 Optional<Long> ingestJobId = getIngestJobId();
1049 selfAccountInstance = getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(selfAccountType, selfAccountId, this.getModuleName(), getContent(), null, ingestJobId.orElse(null));
1051 return selfAccountInstance;
READ
message has not been read
CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType, Long ingestJobId)
CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType, Account.Type selfAccountType, String selfAccountId, Long ingestJobId)
static< T > BlackboardAttribute toAttribute(BlackboardAttribute.Type attrType, String moduleName, T attrValue)
BlackboardArtifact addMessage(String messageType, CommunicationDirection direction, String senderId, List< String > recipientIdsList, long dateTime, MessageReadStatus readStatus, String subject, String messageText, String threadId, Collection< BlackboardAttribute > otherAttributesList)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList, Long osAccountId)
CommunicationDirection(String dir)
BlackboardArtifact addContact(String contactName, String phoneNumber, String homePhoneNumber, String mobilePhoneNumber, String emailAddr)
void addAttributes(Collection< BlackboardAttribute > attributes)
CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList)
BlackboardArtifact addContact(String contactName, String phoneNumber, String homePhoneNumber, String mobilePhoneNumber, String emailAddr, Collection< BlackboardAttribute > additionalAttributes)
UNREAD
read status is unknown
String getTypeSpecificID()
static final Account.Type PHONE
AbstractFile getAbstractFileById(long id)
BlackboardArtifact addMessage(String messageType, CommunicationDirection direction, String senderId, String recipientId, long dateTime, MessageReadStatus readStatus, String subject, String messageText, String threadId)
BlackboardArtifact addMessage(String messageType, CommunicationDirection direction, String senderId, String recipientId, long dateTime, MessageReadStatus readStatus, String subject, String messageText, String threadId, Collection< BlackboardAttribute > otherAttributesList)
SleuthkitCase getSleuthkitCase()
static final Relationship.Type CALL_LOG
BlackboardArtifact addCalllog(CommunicationDirection direction, String callerId, Collection< String > calleeIdsList, long startDateTime, long endDateTime, CallMediaType mediaType, Collection< BlackboardAttribute > otherAttributesList)
BlackboardArtifact addCalllog(CommunicationDirection direction, String callerId, Collection< String > calleeIdsList, long startDateTime, long endDateTime, CallMediaType mediaType)
CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType, Account.Type selfAccountType, String selfAccountId)
BlackboardArtifact addCalllog(CommunicationDirection direction, String callerId, String calleeId, long startDateTime, long endDateTime, CallMediaType mediaType, Collection< BlackboardAttribute > otherAttributesList)
static final Account.Type DEVICE
static final Relationship.Type MESSAGE
BlackboardArtifact addMessage(String messageType, CommunicationDirection direction, String senderId, List< String > recipientIdsList, long dateTime, MessageReadStatus readStatus, String subject, String messageText, String threadId)
static final Relationship.Type CONTACT
BlackboardArtifact addCalllog(CommunicationDirection direction, String callerId, String calleeId, long startDateTime, long endDateTime, CallMediaType mediaType)
MessageReadStatus(String readStatus)
void addAttachments(BlackboardArtifact message, MessageAttachments attachments)
static final Account.Type EMAIL