Autopsy  4.14.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
XRYCallsFileParser.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019-2020 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.autopsy.datasourceprocessors.xry;
20 
21 import java.time.format.DateTimeParseException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.logging.Level;
27 import org.sleuthkit.datamodel.Account;
28 import org.sleuthkit.datamodel.Blackboard.BlackboardException;
29 import org.sleuthkit.datamodel.BlackboardArtifact;
30 import org.sleuthkit.datamodel.BlackboardAttribute;
31 import org.sleuthkit.datamodel.Content;
32 import org.sleuthkit.datamodel.SleuthkitCase;
33 import org.sleuthkit.datamodel.TskCoreException;
34 import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper;
35 import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CallMediaType;
36 import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CommunicationDirection;
37 
41 final class XRYCallsFileParser extends AbstractSingleEntityParser {
42 
43  private static final Logger logger = Logger.getLogger(XRYCallsFileParser.class.getName());
44 
49  private enum XryKey {
50  NAME_MATCHED("name (matched)", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME),
51  TIME("time", null),
52  DIRECTION("direction", null),
53  CALL_TYPE("call type", null),
54  NUMBER("number", null),
55  TEL("tel", null),
56  TO("to", null),
57  FROM("from", null),
58  DELETED("deleted", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ISDELETED),
59  DURATION("duration", null),
60  STORAGE("storage", null),
61  INDEX("index", null),
62  TYPE("type", null),
63  NAME("name", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
64 
65  private final String name;
66  private final BlackboardAttribute.ATTRIBUTE_TYPE type;
67 
68  XryKey(String name, BlackboardAttribute.ATTRIBUTE_TYPE type) {
69  this.name = name;
70  this.type = type;
71  }
72 
73  public BlackboardAttribute.ATTRIBUTE_TYPE getType() {
74  return type;
75  }
76 
80  public static boolean contains(String key) {
81  try {
83  return true;
84  } catch (IllegalArgumentException ex) {
85  return false;
86  }
87  }
88 
96  public static XryKey fromDisplayName(String key) {
97  String normalizedKey = key.trim().toLowerCase();
98  for (XryKey keyChoice : XryKey.values()) {
99  if (normalizedKey.equals(keyChoice.name)) {
100  return keyChoice;
101  }
102  }
103 
104  throw new IllegalArgumentException(String.format("Key [%s] was not found."
105  + " All keys should be tested with contains.", key));
106  }
107  }
108 
112  private enum XryNamespace {
113  TO("to"),
114  FROM("from"),
115  NONE(null);
116 
117  private final String name;
118 
119  XryNamespace(String name) {
120  this.name = name;
121  }
122 
127  public static boolean contains(String xryNamespace) {
128  try {
129  XryNamespace.fromDisplayName(xryNamespace);
130  return true;
131  } catch (IllegalArgumentException ex) {
132  return false;
133  }
134  }
135 
144  public static XryNamespace fromDisplayName(String xryNamespace) {
145  String normalizedNamespace = xryNamespace.trim().toLowerCase();
146  for (XryNamespace keyChoice : XryNamespace.values()) {
147  if (normalizedNamespace.equals(keyChoice.name)) {
148  return keyChoice;
149  }
150  }
151 
152  throw new IllegalArgumentException(String.format("Key [%s] was not found."
153  + " All keys should be tested with contains.", xryNamespace));
154  }
155  }
156 
157  @Override
158  boolean canProcess(XRYKeyValuePair pair) {
159  return XryKey.contains(pair.getKey());
160  }
161 
162  @Override
163  boolean isNamespace(String nameSpace) {
164  return XryNamespace.contains(nameSpace);
165  }
166 
167  @Override
168  void makeArtifact(List<XRYKeyValuePair> keyValuePairs, Content parent, SleuthkitCase currentCase) throws TskCoreException, BlackboardException {
169  // Transform all the data from XRY land into the appropriate CommHelper
170  // data types.
171  String callerId = null;
172  final Collection<String> calleeList = new ArrayList<>();
173  CommunicationDirection direction = CommunicationDirection.UNKNOWN;
174  long startTime = 0L;
175  final long endTime = 0L;
176  final CallMediaType callType = CallMediaType.UNKNOWN;
177  final Collection<BlackboardAttribute> otherAttributes = new ArrayList<>();
178 
179  for (XRYKeyValuePair pair : keyValuePairs) {
180  XryKey xryKey = XryKey.fromDisplayName(pair.getKey());
181  XryNamespace xryNamespace = XryNamespace.NONE;
182  if (XryNamespace.contains(pair.getNamespace())) {
183  xryNamespace = XryNamespace.fromDisplayName(pair.getNamespace());
184  }
185 
186  switch (xryKey) {
187  case TEL:
188  case NUMBER:
189  if(!XRYUtils.isPhoneValid(pair.getValue())) {
190  continue;
191  }
192 
193  // Apply namespace or direction
194  if (xryNamespace == XryNamespace.FROM || direction == CommunicationDirection.INCOMING) {
195  callerId = pair.getValue();
196  } else if (xryNamespace == XryNamespace.TO || direction == CommunicationDirection.OUTGOING) {
197  calleeList.add(pair.getValue());
198  } else {
199  otherAttributes.add(new BlackboardAttribute(
200  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
201  PARSER_NAME, pair.getValue()));
202  }
203  break;
204  // Although confusing, as these are also 'name spaces', it appears
205  // later versions of XRY just made these standardized lines.
206  case TO:
207  if(!XRYUtils.isPhoneValid(pair.getValue())) {
208  continue;
209  }
210 
211  calleeList.add(pair.getValue());
212  break;
213  case FROM:
214  if(!XRYUtils.isPhoneValid(pair.getValue())) {
215  continue;
216  }
217 
218  callerId = pair.getValue();
219  break;
220  case TIME:
221  try {
222  //Tranform value to seconds since epoch
223  long dateTimeSinceEpoch = XRYUtils.calculateSecondsSinceEpoch(pair.getValue());
224  startTime = dateTimeSinceEpoch;
225  } catch (DateTimeParseException ex) {
226  logger.log(Level.WARNING, String.format("[XRY DSP] Assumption"
227  + " about the date time formatting of call logs is "
228  + "not right. Here is the value [ %s ]", pair.getValue()), ex);
229  }
230  break;
231  case DIRECTION:
232  String directionString = pair.getValue().toLowerCase();
233  if (directionString.equals("incoming")) {
234  direction = CommunicationDirection.INCOMING;
235  } else {
236  direction = CommunicationDirection.OUTGOING;
237  }
238  break;
239  case TYPE:
240  String typeString = pair.getValue();
241  if (typeString.equalsIgnoreCase("received")) {
242  direction = CommunicationDirection.INCOMING;
243  } else if (typeString.equalsIgnoreCase("dialed")) {
244  direction = CommunicationDirection.OUTGOING;
245  }
246  break;
247  default:
248  //Otherwise, the XryKey enum contains the correct BlackboardAttribute
249  //type.
250  if (xryKey.getType() != null) {
251  otherAttributes.add(new BlackboardAttribute(xryKey.getType(),
252  PARSER_NAME, pair.getValue()));
253  }
254 
255  logger.log(Level.INFO, String.format("[XRY DSP] Key value pair "
256  + "(in brackets) [ %s ] was recognized but "
257  + "more data or time is needed to finish implementation. Discarding... ",
258  pair));
259  }
260  }
261 
262  // Make sure we have the required fields, otherwise the CommHelper will
263  // complain about illegal arguments.
264 
265  // These are all the invalid combinations.
266  if (callerId == null && calleeList.isEmpty()
267  || direction == CommunicationDirection.INCOMING && callerId == null
268  || direction == CommunicationDirection.OUTGOING && calleeList.isEmpty()) {
269 
270  // If the combo is invalid, just make an artifact with what we've got.
271  if (direction != CommunicationDirection.UNKNOWN) {
272  otherAttributes.add(new BlackboardAttribute(
273  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION,
274  PARSER_NAME, direction.getDisplayName()));
275  }
276 
277  if (startTime > 0L) {
278  otherAttributes.add(new BlackboardAttribute(
279  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START,
280  PARSER_NAME, startTime));
281  }
282 
283  // If the DIRECTION check failed, just manually create accounts
284  // for these phones. Note, there is no need to create relationships.
285  // If both callerId and calleeList were non-null/non-empty, then
286  // it would have been a valid combination.
287  if (callerId != null) {
288  currentCase.getCommunicationsManager().createAccountFileInstance(
289  Account.Type.PHONE, callerId, PARSER_NAME, parent);
290 
291  otherAttributes.add(new BlackboardAttribute(
292  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
293  PARSER_NAME, callerId));
294  }
295 
296  for (String phone : calleeList) {
297  currentCase.getCommunicationsManager().createAccountFileInstance(
298  Account.Type.PHONE, phone, PARSER_NAME, parent);
299 
300  otherAttributes.add(new BlackboardAttribute(
301  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
302  PARSER_NAME, phone));
303  }
304 
305  if (!otherAttributes.isEmpty()) {
306  BlackboardArtifact artifact = parent.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG);
307  artifact.addAttributes(otherAttributes);
308 
309  currentCase.getBlackboard().postArtifact(artifact, PARSER_NAME);
310  }
311  } else {
312 
313  // Otherwise we can safely use the helper.
314  CommunicationArtifactsHelper helper = new CommunicationArtifactsHelper(
315  currentCase, PARSER_NAME, parent, Account.Type.PHONE);
316 
317  helper.addCalllog(direction, callerId, calleeList, startTime,
318  endTime, callType, otherAttributes);
319  }
320  }
321 }
XryKey(String name, BlackboardAttribute.ATTRIBUTE_TYPE type)

Copyright © 2012-2020 Basis Technology. Generated on: Wed Apr 8 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.