Sleuth Kit Java Bindings (JNI)  4.11.1
Java bindings for using The Sleuth Kit
CommunicationArtifactsHelper.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2019-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.datamodel.blackboardutils;
20 
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;
49 
69 public final class CommunicationArtifactsHelper extends ArtifactHelperBase {
70 
71  private static final Logger LOGGER = Logger.getLogger(CommunicationArtifactsHelper.class.getName());
72 
73  private static final BlackboardArtifact.Type CONTACT_TYPE = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_CONTACT);
74  private static final BlackboardArtifact.Type MESSAGE_TYPE = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_MESSAGE);
75  private static final BlackboardArtifact.Type CALLOG_TYPE = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_CALLLOG);
76  private static final BlackboardArtifact.Type ASSOCIATED_OBJ_TYPE = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
77 
81  public enum MessageReadStatus {
82 
83  UNKNOWN("Unknown"),
84  UNREAD("Unread"),
85  READ("Read");
86 
87  private final String msgReadStr;
88 
89  MessageReadStatus(String readStatus) {
90  this.msgReadStr = readStatus;
91  }
92 
93  public String getDisplayName() {
94  return msgReadStr;
95  }
96  }
97 
102  UNKNOWN("Unknown"),
103  INCOMING("Incoming"),
104  OUTGOING("Outgoing");
105 
106  private final String dirStr;
107 
109  this.dirStr = dir;
110  }
111 
112  public String getDisplayName() {
113  return dirStr;
114  }
115  }
116 
120  public enum CallMediaType {
121  UNKNOWN("Unknown"),
122  AUDIO("Audio"), // Audio only call
123  VIDEO("Video"); // Video/multimedia call
124 
125  private final String typeStr;
126 
127  CallMediaType(String type) {
128  this.typeStr = type;
129  }
130 
131  public String getDisplayName() {
132  return typeStr;
133  }
134  }
135 
136  private static final BlackboardAttribute.Type ATTACHMENTS_ATTR_TYPE = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS);
137 
138  // 'self' account for the application being processed by the module.
139  private final Account.Type selfAccountType;
140  private final String selfAccountId;
141 
142  private AccountFileInstance selfAccountInstance = null;
143 
144  // Type of accounts to be created for the module using this helper.
145  private final Account.Type moduleAccountsType;
146 
165  public CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType, Long ingestJobId) throws TskCoreException {
166  super(caseDb, moduleName, srcContent, ingestJobId);
167  this.moduleAccountsType = accountsType;
168  this.selfAccountType = Account.Type.DEVICE;
169  this.selfAccountId = ((DataSource) getContent().getDataSource()).getDeviceId();
170  }
171 
194  public CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType, Account.Type selfAccountType, String selfAccountId, Long ingestJobId) throws TskCoreException {
195  super(caseDb, moduleName, srcContent, ingestJobId);
196  this.moduleAccountsType = accountsType;
197  this.selfAccountType = selfAccountType;
198  this.selfAccountId = selfAccountId;
199  }
200 
220  @Deprecated
221  public CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType) throws TskCoreException {
222  this(caseDb, moduleName, srcContent, accountsType, null);
223  }
224 
247  @Deprecated
248  public CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType, Account.Type selfAccountType, String selfAccountId) throws TskCoreException {
249  this(caseDb, moduleName, srcContent, accountsType, selfAccountType, selfAccountId, null);
250  }
251 
273  public BlackboardArtifact addContact(String contactName,
274  String phoneNumber, String homePhoneNumber,
275  String mobilePhoneNumber, String emailAddr) throws TskCoreException, BlackboardException {
276  return addContact(contactName, phoneNumber,
277  homePhoneNumber, mobilePhoneNumber, emailAddr,
278  Collections.emptyList());
279  }
280 
306  public BlackboardArtifact addContact(String contactName,
307  String phoneNumber, String homePhoneNumber,
308  String mobilePhoneNumber, String emailAddr,
309  Collection<BlackboardAttribute> additionalAttributes) throws TskCoreException, BlackboardException {
310 
311  // check if the caller has included any phone/email/id in addtional attributes
312  boolean hasAnyIdAttribute = false;
313  if (additionalAttributes != null) {
314  for (BlackboardAttribute attr : additionalAttributes) {
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;
319  break;
320  }
321  }
322  }
323 
324  // At least one phone number or email address
325  // or an optional attribute with phone/email/id must be provided
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.");
330  }
331 
332  BlackboardArtifact contactArtifact;
333  Collection<BlackboardAttribute> attributes = new ArrayList<>();
334 
335  // create TSK_CONTACT artifact and construct attributes
336  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_NAME, contactName, attributes);
337 
338  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, phoneNumber, attributes);
339  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME, homePhoneNumber, attributes);
340  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE, mobilePhoneNumber, attributes);
341  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_EMAIL, emailAddr, attributes);
342 
343  // add attributes
344  attributes.addAll(additionalAttributes);
345  Content content = getContent();
346 
347  contactArtifact = content.newDataArtifact(CONTACT_TYPE, attributes);
348 
349  // create an account for each specified contact method, and a relationship with self account
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);
354 
355  // if the additional attribute list has any phone/email/id attributes, create accounts & relationships for those.
356  if ((additionalAttributes != null) && hasAnyIdAttribute) {
357  for (BlackboardAttribute bba : additionalAttributes) {
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);
364  }
365  }
366  }
367 
368  // post artifact
369  Optional<Long> ingestJobId = getIngestJobId();
370  getSleuthkitCase().getBlackboard().postArtifact(contactArtifact, getModuleName(), ingestJobId.orElse(null));
371 
372  return contactArtifact;
373  }
374 
383  private void createContactMethodAccountAndRelationship(Account.Type accountType,
384  String accountUniqueID, BlackboardArtifact sourceArtifact,
385  long dateTime) throws TskCoreException {
386 
387  // Find/Create an account instance for each of the contact method
388  // Create a relationship between selfAccount and contactAccount
389  if (StringUtils.isNotBlank(accountUniqueID)) {
390  try {
391  AccountFileInstance contactAccountInstance = createAccountInstance(accountType, accountUniqueID);
392 
393  // Create a relationship between self account and the contact account
394  try {
395  getSleuthkitCase().getCommunicationsManager().addRelationships(getSelfAccountInstance(),
396  Collections.singletonList(contactAccountInstance), sourceArtifact, Relationship.Type.CONTACT, dateTime);
397  } catch (TskDataException ex) {
398  throw new TskCoreException(String.format("Failed to create relationship between account = %s and account = %s.",
399  getSelfAccountInstance().getAccount(), contactAccountInstance.getAccount()), ex);
400  }
401  } catch (InvalidAccountIDException ex) {
402  LOGGER.log(Level.WARNING, String.format("Failed to create account with id %s", accountUniqueID));
403  }
404  }
405  }
406 
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));
422  }
423 
446  String messageType,
447  CommunicationDirection direction,
448  String senderId,
449  String recipientId,
450  long dateTime, MessageReadStatus readStatus,
451  String subject, String messageText, String threadId) throws TskCoreException, BlackboardException {
452  return addMessage(messageType, direction,
453  senderId, recipientId, dateTime, readStatus,
454  subject, messageText, threadId,
455  Collections.emptyList());
456  }
457 
480  public BlackboardArtifact addMessage(String messageType,
481  CommunicationDirection direction,
482  String senderId,
483  String recipientId,
484  long dateTime, MessageReadStatus readStatus, String subject,
485  String messageText, String threadId,
486  Collection<BlackboardAttribute> otherAttributesList) throws TskCoreException, BlackboardException {
487 
488  return addMessage(messageType, direction,
489  senderId,
490  Arrays.asList(recipientId),
491  dateTime, readStatus,
492  subject, messageText, threadId,
493  otherAttributesList);
494  }
495 
518  public BlackboardArtifact addMessage(String messageType,
519  CommunicationDirection direction,
520  String senderId,
521  List<String> recipientIdsList,
522  long dateTime, MessageReadStatus readStatus,
523  String subject, String messageText, String threadId) throws TskCoreException, BlackboardException {
524  return addMessage(messageType, direction,
525  senderId, recipientIdsList,
526  dateTime, readStatus,
527  subject, messageText, threadId,
528  Collections.emptyList());
529  }
530 
553  public BlackboardArtifact addMessage(String messageType,
554  CommunicationDirection direction,
555  String senderId,
556  List<String> recipientIdsList,
557  long dateTime, MessageReadStatus readStatus,
558  String subject, String messageText,
559  String threadId,
560  Collection<BlackboardAttribute> otherAttributesList) throws TskCoreException, BlackboardException {
561 
562  // Created message artifact.
563  Collection<BlackboardAttribute> attributes = new ArrayList<>();
564 
565  // construct attributes
566  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, getModuleName(), messageType));
567  addAttributeIfNotZero(ATTRIBUTE_TYPE.TSK_DATETIME, dateTime, attributes);
568 
569  addMessageReadStatusIfKnown(readStatus, attributes);
570  addCommDirectionIfKnown(direction, attributes);
571 
572  // Get the self account instance
573  AccountFileInstance selfAccountInstanceLocal = null;
574  try {
575  selfAccountInstanceLocal = getSelfAccountInstance();
576  } catch (InvalidAccountIDException ex) {
577  LOGGER.log(Level.WARNING, String.format("Failed to get/create self account with id %s", selfAccountId), ex);
578  }
579 
580  // set sender attribute and create sender account
581  AccountFileInstance senderAccountInstance = null;
582  if (StringUtils.isNotBlank(senderId)) {
583  try {
584  senderAccountInstance = createAccountInstance(moduleAccountsType, senderId);
585  } catch (InvalidAccountIDException ex) {
586  LOGGER.log(Level.WARNING, String.format("Invalid account identifier %s", senderId));
587  }
588  }
589 
590  // set recipient attribute and create recipient accounts
591  List<AccountFileInstance> recipientAccountsList = new ArrayList<>();
592  String recipientsStr = "";
593  if (!isEffectivelyEmpty(recipientIdsList)) {
594  for (String recipient : recipientIdsList) {
595  if (StringUtils.isNotBlank(recipient)) {
596  try {
597  recipientAccountsList.add(createAccountInstance(moduleAccountsType, recipient));
598  } catch (InvalidAccountIDException ex) {
599  LOGGER.log(Level.WARNING, String.format("Invalid account identifier %s", recipient));
600  }
601  }
602  }
603  // Create a comma separated string of recipients
604  recipientsStr = addressListToString(recipientIdsList);
605  }
606 
607  switch (direction) {
608  case OUTGOING:
609  // if no sender, selfAccount substitutes caller.
610  if (StringUtils.isEmpty(senderId) && selfAccountInstanceLocal != null) {
611  senderAccountInstance = selfAccountInstanceLocal;
612  }
613  // sender becomes PHONE_FROM
614  if (senderAccountInstance != null) {
615  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, senderAccountInstance.getAccount().getTypeSpecificID(), attributes);
616  }
617  // recipient becomes PHONE_TO
618  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, recipientsStr, attributes);
619  break;
620 
621  case INCOMING:
622  // if no recipeint specified, selfAccount substitutes recipient
623  if (isEffectivelyEmpty(recipientIdsList) && selfAccountInstanceLocal != null) {
624  recipientsStr = selfAccountInstanceLocal.getAccount().getTypeSpecificID();
625  recipientAccountsList.add(selfAccountInstanceLocal);
626  }
627  // caller becomes PHONE_FROM
628  if (senderAccountInstance != null) {
629  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, senderAccountInstance.getAccount().getTypeSpecificID(), attributes);
630  }
631  // callee becomes PHONE_TO
632  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, recipientsStr, attributes);
633  break;
634  default: // direction UNKNOWN
635  if (StringUtils.isEmpty(senderId) && selfAccountInstanceLocal != null) {
636  // if no sender, selfAccount substitutes caller.
637  senderAccountInstance = selfAccountInstanceLocal;
638  } else if (isEffectivelyEmpty(recipientIdsList) && selfAccountInstanceLocal != null) {
639  // else if no recipient specified, selfAccount substitutes recipient
640  recipientsStr = selfAccountInstanceLocal.getAccount().getTypeSpecificID();
641  recipientAccountsList.add(selfAccountInstanceLocal);
642  }
643 
644  // save phone numbers in direction agnostic attributes
645  if (senderAccountInstance != null) {
646  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, senderAccountInstance.getAccount().getTypeSpecificID(), attributes);
647  } // callee becomes PHONE_TO
648  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, recipientsStr, attributes);
649  break;
650  }
651 
652  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_SUBJECT, subject, attributes);
653  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_TEXT, messageText, attributes);
654  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_THREAD_ID, threadId, attributes);
655 
656  // add attributes to artifact
657  attributes.addAll(otherAttributesList);
658 
659  // create TSK_MESSAGE artifact
660  Content content = getContent();
661  BlackboardArtifact msgArtifact = content.newDataArtifact(MESSAGE_TYPE, attributes);
662 
663  // create sender/recipient relationships
664  try {
665  getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance,
666  recipientAccountsList, msgArtifact, Relationship.Type.MESSAGE, dateTime);
667  } catch (TskDataException ex) {
668  throw new TskCoreException(String.format("Failed to create Message relationships between sender account = %s and recipients = %s.",
669  (senderAccountInstance != null) ? senderAccountInstance.getAccount().getTypeSpecificID() : "Unknown", recipientsStr), ex);
670  }
671 
672  // post artifact
673  Optional<Long> ingestJobId = getIngestJobId();
674  getSleuthkitCase().getBlackboard().postArtifact(msgArtifact, getModuleName(), ingestJobId.orElse(null));
675 
676  // return the artifact
677  return msgArtifact;
678  }
679 
703  String callerId, String calleeId,
704  long startDateTime, long endDateTime, CallMediaType mediaType) throws TskCoreException, BlackboardException {
705  return addCalllog(direction, callerId, calleeId,
706  startDateTime, endDateTime, mediaType,
707  Collections.emptyList());
708  }
709 
734  String callerId,
735  String calleeId,
736  long startDateTime, long endDateTime,
737  CallMediaType mediaType,
738  Collection<BlackboardAttribute> otherAttributesList) throws TskCoreException, BlackboardException {
739  return addCalllog(direction,
740  callerId,
741  Arrays.asList(calleeId),
742  startDateTime, endDateTime,
743  mediaType,
744  otherAttributesList);
745  }
746 
770  String callerId,
771  Collection<String> calleeIdsList,
772  long startDateTime, long endDateTime,
773  CallMediaType mediaType) throws TskCoreException, BlackboardException {
774 
775  return addCalllog(direction, callerId, calleeIdsList,
776  startDateTime, endDateTime,
777  mediaType,
778  Collections.emptyList());
779  }
780 
805  String callerId,
806  Collection<String> calleeIdsList,
807  long startDateTime, long endDateTime,
808  CallMediaType mediaType,
809  Collection<BlackboardAttribute> otherAttributesList) throws TskCoreException, BlackboardException {
810 
811  // Either caller id or a callee id must be provided.
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.");
814  }
815 
816  AccountFileInstance selfAccountInstanceLocal = null;
817  try {
818  selfAccountInstanceLocal = getSelfAccountInstance();
819  } catch (InvalidAccountIDException ex) {
820  LOGGER.log(Level.WARNING, String.format("Failed to get/create self account with id %s", selfAccountId), ex);
821  }
822 
823  Collection<BlackboardAttribute> attributes = new ArrayList<>();
824 
825  // Add basic attributes
826  addAttributeIfNotZero(ATTRIBUTE_TYPE.TSK_DATETIME_START, startDateTime, attributes);
827  addAttributeIfNotZero(ATTRIBUTE_TYPE.TSK_DATETIME_END, endDateTime, attributes);
828  addCommDirectionIfKnown(direction, attributes);
829 
830  AccountFileInstance callerAccountInstance = null;
831  if (StringUtils.isNotBlank(callerId)) {
832  try {
833  callerAccountInstance = createAccountInstance(moduleAccountsType, callerId);
834  } catch (InvalidAccountIDException ex) {
835  LOGGER.log(Level.WARNING, String.format("Failed to create account with id %s", callerId));
836  }
837  }
838 
839  // Create a comma separated string of callee
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)) {
846  try {
847  recipientAccountsList.add(createAccountInstance(moduleAccountsType, callee));
848  } catch (InvalidAccountIDException ex) {
849  LOGGER.log(Level.WARNING, String.format("Failed to create account with id %s", callee));
850  }
851  }
852  }
853  }
854 
855  switch (direction) {
856  case OUTGOING:
857  // if no callee throw IllegalArg
858  if (isEffectivelyEmpty(calleeIdsList)) {
859  throw new IllegalArgumentException("Callee not provided for an outgoing call.");
860  }
861  // if no caller, selfAccount substitutes caller.
862  if (StringUtils.isEmpty(callerId) && selfAccountInstanceLocal != null) {
863  callerAccountInstance = selfAccountInstanceLocal;
864  }
865  // caller becomes PHONE_FROM
866  if (callerAccountInstance != null) {
867  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, callerAccountInstance.getAccount().getTypeSpecificID(), attributes);
868  }
869  // callee becomes PHONE_TO
870  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, calleesStr, attributes);
871  break;
872 
873  case INCOMING:
874  // if no caller throw IllegalArg
875  if (StringUtils.isEmpty(callerId)) {
876  throw new IllegalArgumentException("Caller Id not provided for incoming call.");
877  }
878  // if no callee specified, selfAccount substitutes callee
879  if (isEffectivelyEmpty(calleeIdsList) && selfAccountInstanceLocal != null) {
880  calleesStr = selfAccountInstanceLocal.getAccount().getTypeSpecificID();
881  recipientAccountsList.add(selfAccountInstanceLocal);
882  }
883  // caller becomes PHONE_FROM
884  if (callerAccountInstance != null) {
885  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, callerAccountInstance.getAccount().getTypeSpecificID(), attributes);
886  }
887  // callee becomes PHONE_TO
888  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, calleesStr, attributes);
889  break;
890  default: // direction UNKNOWN
891 
892  // save phone numbers in direction agnostic attributes
893  if (callerAccountInstance != null) {
894  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, callerAccountInstance.getAccount().getTypeSpecificID(), attributes);
895  } // callee becomes PHONE_TO
896  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, calleesStr, attributes);
897  break;
898  }
899 
900  // add attributes to artifact
901  attributes.addAll(otherAttributesList);
902  // Create TSK_CALLLOG artifact
903  Content content = getContent();
904  BlackboardArtifact callLogArtifact = content.newDataArtifact(CALLOG_TYPE, attributes);
905 
906  callLogArtifact.addAttributes(attributes);
907 
908  // create relationships between caller/callees
909  try {
910  getSleuthkitCase().getCommunicationsManager().addRelationships(callerAccountInstance,
911  recipientAccountsList, callLogArtifact, Relationship.Type.CALL_LOG, startDateTime);
912  } catch (TskDataException ex) {
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);
915  }
916 
917  // post artifact
918  Optional<Long> ingestJobId = getIngestJobId();
919  getSleuthkitCase().getBlackboard().postArtifact(callLogArtifact, getModuleName(), ingestJobId.orElse(null));
920 
921  // return the artifact
922  return callLogArtifact;
923  }
924 
933  public void addAttachments(BlackboardArtifact message, MessageAttachments attachments) throws TskCoreException {
934  // Create attribute
935  BlackboardAttribute blackboardAttribute = BlackboardJsonAttrUtil.toAttribute(ATTACHMENTS_ATTR_TYPE, getModuleName(), attachments);
936  message.addAttribute(blackboardAttribute);
937 
938  // Associate each attachment file with the message.
939  List<BlackboardArtifact> assocObjectArtifacts = new ArrayList<>();
940  Collection<FileAttachment> fileAttachments = attachments.getFileAttachments();
941  for (FileAttachment fileAttachment : fileAttachments) {
942  long attachedFileObjId = fileAttachment.getObjectId();
943  if (attachedFileObjId >= 0) {
944  AbstractFile attachedFile = message.getSleuthkitCase().getAbstractFileById(attachedFileObjId);
945  DataArtifact artifact = associateAttachmentWithMessage(message, attachedFile);
946  assocObjectArtifacts.add(artifact);
947  }
948  }
949 
950  try {
951  Optional<Long> ingestJobId = getIngestJobId();
952  getSleuthkitCase().getBlackboard().postArtifacts(assocObjectArtifacts, getModuleName(), ingestJobId.orElse(null));
953  } catch (BlackboardException ex) {
954  throw new TskCoreException("Error posting TSK_ASSOCIATED_ARTIFACT artifacts for attachments", ex);
955  }
956  }
957 
970  private DataArtifact associateAttachmentWithMessage(BlackboardArtifact message, AbstractFile attachedFile) throws TskCoreException {
971  Collection<BlackboardAttribute> attributes = new ArrayList<>();
972  attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, this.getModuleName(), message.getArtifactID()));
973  return attachedFile.newDataArtifact(ASSOCIATED_OBJ_TYPE, attributes);
974  }
975 
979  private String addressListToString(Collection<String> addressList) {
980 
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);
987  }
988  }
989  toAddresses = toAddressesSb.toString();
990  }
991 
992  return toAddresses;
993  }
994 
1004  private boolean isEffectivelyEmpty(Collection<String> idList) {
1005 
1006  if (idList == null || idList.isEmpty()) {
1007  return true;
1008  }
1009 
1010  for (String id : idList) {
1011  if (!StringUtils.isEmpty(id)) {
1012  return false;
1013  }
1014  }
1015 
1016  return true;
1017 
1018  }
1019 
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()));
1026  }
1027  }
1028 
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));
1035  }
1036  }
1037 
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));
1050  }
1051  return selfAccountInstance;
1052  }
1053 }
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)
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)
static final Account.Type PHONE
Definition: Account.java:49
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)
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
Definition: Account.java:48
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)
void addAttachments(BlackboardArtifact message, MessageAttachments attachments)
static final Account.Type EMAIL
Definition: Account.java:50

Copyright © 2011-2021 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.