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