1 /* 2 * Sleuth Kit Data Model 3 * 4 * Copyright 2018 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; 20 21 import com.google.common.net.InternetDomainName; 22 import java.text.MessageFormat; 23 import java.util.Optional; 24 import java.util.logging.Level; 25 import java.util.logging.Logger; 26 import org.apache.commons.lang3.StringUtils; 27 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN; 28 29 /** 30 * Version of TimelineEventType for events based on artifacts 31 */ 32 class TimelineEventArtifactTypeImpl extends TimelineEventTypeImpl { 33 34 private static final Logger logger = Logger.getLogger(TimelineEventArtifactTypeImpl.class.getName()); 35 36 static final int EMAIL_FULL_DESCRIPTION_LENGTH_MAX = 150; 37 static final int EMAIL_TO_FROM_LENGTH_MAX = 75; 38 39 private final BlackboardArtifact.Type artifactType; 40 private final BlackboardAttribute.Type dateTimeAttributeType; 41 private final TSKCoreCheckedFunction<BlackboardArtifact, String> fullExtractor; 42 private final TSKCoreCheckedFunction<BlackboardArtifact, String> medExtractor; 43 private final TSKCoreCheckedFunction<BlackboardArtifact, String> shortExtractor; 44 private final TSKCoreCheckedFunction<BlackboardArtifact, TimelineEventDescriptionWithTime> artifactParsingFunction; 45 46 private static final int MAX_SHORT_DESCRIPTION_LENGTH = 500; 47 private static final int MAX_MED_DESCRIPTION_LENGTH = 500; 48 private static final int MAX_FULL_DESCRIPTION_LENGTH = 1024; 49 TimelineEventArtifactTypeImpl(int typeID, String displayName, TimelineEventType superType, BlackboardArtifact.Type artifactType, BlackboardAttribute.Type dateTimeAttributeType, TSKCoreCheckedFunction<BlackboardArtifact, String> shortExtractor, TSKCoreCheckedFunction<BlackboardArtifact, String> medExtractor, TSKCoreCheckedFunction<BlackboardArtifact, String> fullExtractor)50 TimelineEventArtifactTypeImpl(int typeID, String displayName, 51 TimelineEventType superType, 52 BlackboardArtifact.Type artifactType, 53 BlackboardAttribute.Type dateTimeAttributeType, 54 TSKCoreCheckedFunction<BlackboardArtifact, String> shortExtractor, 55 TSKCoreCheckedFunction<BlackboardArtifact, String> medExtractor, 56 TSKCoreCheckedFunction<BlackboardArtifact, String> fullExtractor) { 57 this(typeID, displayName, superType, artifactType, dateTimeAttributeType, shortExtractor, medExtractor, fullExtractor, null); 58 } 59 TimelineEventArtifactTypeImpl(int typeID, String displayName, TimelineEventType superType, BlackboardArtifact.Type artifactType, BlackboardAttribute.Type dateTimeAttributeType, TSKCoreCheckedFunction<BlackboardArtifact, String> shortExtractor, TSKCoreCheckedFunction<BlackboardArtifact, String> medExtractor, TSKCoreCheckedFunction<BlackboardArtifact, String> fullExtractor, TSKCoreCheckedFunction<BlackboardArtifact, TimelineEventDescriptionWithTime> eventPayloadFunction)60 TimelineEventArtifactTypeImpl(int typeID, String displayName, 61 TimelineEventType superType, 62 BlackboardArtifact.Type artifactType, 63 BlackboardAttribute.Type dateTimeAttributeType, 64 TSKCoreCheckedFunction<BlackboardArtifact, String> shortExtractor, 65 TSKCoreCheckedFunction<BlackboardArtifact, String> medExtractor, 66 TSKCoreCheckedFunction<BlackboardArtifact, String> fullExtractor, 67 TSKCoreCheckedFunction<BlackboardArtifact, TimelineEventDescriptionWithTime> eventPayloadFunction) { 68 69 super(typeID, displayName, TimelineEventType.HierarchyLevel.EVENT, superType); 70 this.artifactType = artifactType; 71 this.dateTimeAttributeType = dateTimeAttributeType; 72 this.shortExtractor = shortExtractor; 73 this.medExtractor = medExtractor; 74 this.fullExtractor = fullExtractor; 75 this.artifactParsingFunction = eventPayloadFunction; 76 } 77 getArtifactTypeID()78 int getArtifactTypeID() { 79 return getArtifactType().getTypeID(); 80 } 81 82 /** 83 * The attribute type this event type is associated with. 84 * 85 * @return The attribute type this event type is derived from. 86 */ getDateTimeAttributeType()87 BlackboardAttribute.Type getDateTimeAttributeType() { 88 return dateTimeAttributeType; 89 } 90 extractFullDescription(BlackboardArtifact artf)91 String extractFullDescription(BlackboardArtifact artf) throws TskCoreException { 92 return fullExtractor.apply(artf); 93 } 94 extractMedDescription(BlackboardArtifact artf)95 String extractMedDescription(BlackboardArtifact artf) throws TskCoreException { 96 return medExtractor.apply(artf); 97 } 98 extractShortDescription(BlackboardArtifact artf)99 String extractShortDescription(BlackboardArtifact artf) throws TskCoreException { 100 return shortExtractor.apply(artf); 101 } 102 103 /** 104 * Get the artifact type this event type is derived from. 105 * 106 * @return The artifact type this event type is derived from. 107 */ getArtifactType()108 BlackboardArtifact.Type getArtifactType() { 109 return artifactType; 110 } 111 112 /** 113 * Parses the artifact to create a triple description with a time. 114 * 115 * @param artifact 116 * 117 * @return 118 * 119 * @throws TskCoreException 120 */ makeEventDescription(BlackboardArtifact artifact)121 TimelineEventDescriptionWithTime makeEventDescription(BlackboardArtifact artifact) throws TskCoreException { 122 //if we got passed an artifact that doesn't correspond to this event type, 123 //something went very wrong. throw an exception. 124 if (this.getArtifactTypeID() != artifact.getArtifactTypeID()) { 125 throw new IllegalArgumentException(); 126 } 127 BlackboardAttribute timeAttribute = artifact.getAttribute(getDateTimeAttributeType()); 128 if (timeAttribute == null) { 129 logger.log(Level.WARNING, "Artifact {0} has no date/time attribute, skipping it.", artifact.toString()); // NON-NLS 130 return null; 131 } 132 133 /* 134 * Use the type-specific method 135 */ 136 if (this.artifactParsingFunction != null) { 137 //use the hook provided by this subtype implementation to build the descriptions. 138 return this.artifactParsingFunction.apply(artifact); 139 } 140 141 //combine descriptions in standard way 142 String shortDescription = extractShortDescription(artifact); 143 if (shortDescription.length() > MAX_SHORT_DESCRIPTION_LENGTH) { 144 shortDescription = shortDescription.substring(0, MAX_SHORT_DESCRIPTION_LENGTH); 145 } 146 147 String medDescription = shortDescription + " : " + extractMedDescription(artifact); 148 if (medDescription.length() > MAX_MED_DESCRIPTION_LENGTH) { 149 medDescription = medDescription.substring(0, MAX_MED_DESCRIPTION_LENGTH); 150 } 151 152 String fullDescription = medDescription + " : " + extractFullDescription(artifact); 153 if (fullDescription.length() > MAX_FULL_DESCRIPTION_LENGTH) { 154 fullDescription = fullDescription.substring(0, MAX_FULL_DESCRIPTION_LENGTH); 155 } 156 157 return new TimelineEventDescriptionWithTime(timeAttribute.getValueLong(), shortDescription, medDescription, fullDescription); 158 } 159 getAttributeSafe(BlackboardArtifact artf, BlackboardAttribute.Type attrType)160 static BlackboardAttribute getAttributeSafe(BlackboardArtifact artf, BlackboardAttribute.Type attrType) { 161 try { 162 return artf.getAttribute(attrType); 163 } catch (TskCoreException ex) { 164 logger.log(Level.SEVERE, MessageFormat.format("Error getting attribute from artifact {0}.", artf.getArtifactID()), ex); // NON-NLS 165 return null; 166 } 167 } 168 169 /** 170 * Function that extracts a string representation of the given attribute 171 * from the artifact it is applied to. 172 */ 173 static class AttributeExtractor implements TSKCoreCheckedFunction<BlackboardArtifact, String> { 174 175 private final BlackboardAttribute.Type attributeType; 176 AttributeExtractor(BlackboardAttribute.Type attribute)177 AttributeExtractor(BlackboardAttribute.Type attribute) { 178 this.attributeType = attribute; 179 } 180 181 @Override apply(BlackboardArtifact artf)182 public String apply(BlackboardArtifact artf) throws TskCoreException { 183 return Optional.ofNullable(getAttributeSafe(artf, attributeType)) 184 .map(BlackboardAttribute::getDisplayString) 185 .orElse(""); 186 } 187 } 188 189 /** 190 * Specialization of AttributeExtractor that extract the domain attribute 191 * and then further processes it to obtain the top private domain using 192 * InternetDomainName. 193 */ 194 final static class TopPrivateDomainExtractor extends AttributeExtractor { 195 196 final private static TopPrivateDomainExtractor instance = new TopPrivateDomainExtractor(); 197 getInstance()198 static TopPrivateDomainExtractor getInstance() { 199 return instance; 200 } 201 TopPrivateDomainExtractor()202 TopPrivateDomainExtractor() { 203 super(new BlackboardAttribute.Type(TSK_DOMAIN)); 204 } 205 206 @Override apply(BlackboardArtifact artf)207 public String apply(BlackboardArtifact artf) throws TskCoreException { 208 String domainString = StringUtils.substringBefore(super.apply(artf), "/"); 209 if (InternetDomainName.isValid(domainString)) { 210 InternetDomainName domain = InternetDomainName.from(domainString); 211 return (domain.isUnderPublicSuffix()) 212 ? domain.topPrivateDomain().toString() 213 : domain.toString(); 214 } else { 215 return domainString; 216 } 217 } 218 } 219 220 /** 221 * Functinal interface for a function from I to O that throws 222 * TskCoreException. 223 * 224 * @param <I> Input type. 225 * @param <O> Output type. 226 */ 227 @FunctionalInterface 228 interface TSKCoreCheckedFunction<I, O> { 229 apply(I input)230 O apply(I input) throws TskCoreException; 231 } 232 } 233