Autopsy  4.15.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
CallLogArtifactViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 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.contentviewers.artifactviewers;
20 
21 import java.awt.Component;
22 import java.awt.GridBagConstraints;
23 import java.awt.GridBagLayout;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.logging.Level;
32 import javax.swing.JScrollPane;
33 import org.apache.commons.lang3.ObjectUtils;
34 import org.apache.commons.lang3.StringUtils;
35 import org.openide.util.NbBundle;
36 import org.openide.util.lookup.ServiceProvider;
39 import org.sleuthkit.datamodel.BlackboardArtifact;
40 import org.sleuthkit.datamodel.BlackboardAttribute;
41 import org.sleuthkit.datamodel.Content;
42 import org.sleuthkit.datamodel.DataSource;
43 import org.sleuthkit.datamodel.TskCoreException;
44 
50 @ServiceProvider(service = ArtifactContentViewer.class)
51 public class CallLogArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer {
52 
53  private final static Logger logger = Logger.getLogger(CallLogArtifactViewer.class.getName());
54  private static final long serialVersionUID = 1L;
55 
56  private static final Set<Integer> HANDLED_ATTRIBUTE_TYPES = new HashSet<Integer>(Arrays.asList(
57  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(),
58  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO.getTypeID(),
59  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM.getTypeID(),
60  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID(),
61  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID(),
62  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(),
63  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID(),
64  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()
65  ));
66 
67  private GridBagLayout m_gridBagLayout = new GridBagLayout();
68  private GridBagConstraints m_constraints = new GridBagConstraints();
69 
70  private PersonaAccountFetcher currentAccountFetcher = null;
71 
76  initComponents();
77  }
78 
84  @SuppressWarnings("unchecked")
85  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
86  private void initComponents() {
87 
88  setLayout(new java.awt.GridBagLayout());
89  }// </editor-fold>//GEN-END:initComponents
90 
91  @Override
92  public void setArtifact(BlackboardArtifact artifact) {
93  resetComponent();
94 
95  if (artifact == null) {
96  return;
97  }
98 
99  CallLogViewData callLogViewData = null;
100  try {
101  callLogViewData = getCallLogViewData(artifact);
102  } catch (TskCoreException ex) {
103  logger.log(Level.SEVERE, String.format("Error getting attributes for Calllog artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
104  }
105 
106  // update the view with the call log data
107  if (callLogViewData != null) {
108  List<AccountPersonaSearcherData> personaSearchDataList = updateView(callLogViewData);
109  if(!personaSearchDataList.isEmpty()) {
110  currentAccountFetcher = new PersonaAccountFetcher(artifact, personaSearchDataList, this);
111  currentAccountFetcher.execute();
112  } else {
113  currentAccountFetcher = null;
114  }
115  }
116  // repaint
117  this.revalidate();
118  }
119 
129  private CallLogViewData getCallLogViewData(BlackboardArtifact artifact) throws TskCoreException {
130 
131  if (artifact == null) {
132  return null;
133  }
134 
135  BlackboardAttribute directionAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION));
136  BlackboardAttribute toAccountAttr = null;
137  BlackboardAttribute fromAccountAttr = null;
138  BlackboardAttribute localAccountAttr = null;
139 
140  CallLogViewData callLogViewData = null;
141 
142  String direction = null;
143  String fromAccountIdentifier = null;
144  String toAccountIdentifier = null;
145  List<String> otherParties = null;
146 
147  Content dataSource = artifact.getDataSource();
148  String deviceId = ((DataSource) dataSource).getDeviceId();
149 
150  if (directionAttr != null) {
151  direction = directionAttr.getValueString();
152  if (direction.equalsIgnoreCase("Incoming")) {
153  fromAccountAttr = ObjectUtils.firstNonNull(
154  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)),
155  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)),
156  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID))
157  );
158 
159  toAccountAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO));
160  localAccountAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO));
161  } else if (direction.equalsIgnoreCase("Outgoing")) {
162  toAccountAttr = ObjectUtils.firstNonNull(
163  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)),
164  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)),
165  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID))
166  );
167 
168  fromAccountAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM));
169  localAccountAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM));
170  }
171  }
172 
173  // if direction isn't known, check all the usual attributes that may have the number/address
174  // in the absence of sufficent data, any number available will be displayed as a From address.
175  if (fromAccountAttr == null) {
176  fromAccountAttr = ObjectUtils.firstNonNull(
177  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)),
178  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)),
179  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)),
180  artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID))
181  );
182  }
183 
184  // get the from account address
185  if (fromAccountAttr != null) {
186  String fromAccountAttrValue = fromAccountAttr.getValueString();
187  if (fromAccountAttrValue.equalsIgnoreCase(deviceId) == false) {
188  fromAccountIdentifier = fromAccountAttrValue;
189  }
190  }
191 
192  if (toAccountAttr != null) {
193  // TO may be a list of comma separated values.
194  String[] numbers = toAccountAttr.getValueString().split(",");
195  String toAccountAttrValue = StringUtils.trim(numbers[0]);
196  if (toAccountAttrValue.equalsIgnoreCase(deviceId) == false) {
197  toAccountIdentifier = toAccountAttrValue;
198  }
199 
200  // if more than one To address, then stick the rest of them in the
201  // "Other parties" list.
202  if (numbers.length > 1) {
203  otherParties = new ArrayList<>();
204  for (int i = 1; i < numbers.length; i++) {
205  otherParties.add(StringUtils.trim(numbers[i]));
206  }
207  }
208  }
209 
210  // if we have at least one address attribute
211  if (null != fromAccountAttr || null != toAccountAttr) {
212  callLogViewData = new CallLogViewData(fromAccountIdentifier, toAccountIdentifier);
213  callLogViewData.setDirection(direction);
214 
215  callLogViewData.setOtherParties(otherParties);
216 
217  extractTimeAndDuration(artifact, callLogViewData);
218 
219  callLogViewData.setDataSourceName(dataSource.getName());
220 
221  // set local account, if it can be deduced.
222  if (localAccountAttr != null) {
223  String attrValue = localAccountAttr.getValueString();
224  // value must be a singular address and not a deviceId to be the local account id
225  if (attrValue.equalsIgnoreCase(deviceId) == false && attrValue.contains(",") == false) {
226  callLogViewData.setLocalAccountId(attrValue);
227  }
228  }
229 
230  callLogViewData.setOtherAttributes(extractOtherAttributes(artifact));
231  }
232 
233  return callLogViewData;
234  }
235 
246  private void extractTimeAndDuration(BlackboardArtifact artifact, CallLogViewData callLogViewData) throws TskCoreException {
247 
248  BlackboardAttribute startTimeAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START));
249  if (startTimeAttr == null) {
250  startTimeAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME));
251  }
252  if (startTimeAttr != null) {
253  long startTime = startTimeAttr.getValueLong();
254  callLogViewData.setDateTimeStr(startTimeAttr.getDisplayString());
255 
256  BlackboardAttribute endTimeAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END));
257  if (endTimeAttr != null) {
258  long endTime = endTimeAttr.getValueLong();
259  if (endTime > 0 && (endTime - startTime) > 0) {
260  callLogViewData.setDuration(String.format("%d seconds", (endTime - startTime)));
261  }
262  }
263  }
264  }
265 
276  private Map<String, String> extractOtherAttributes(BlackboardArtifact artifact) throws TskCoreException {
277  List<BlackboardAttribute> attributes = artifact.getAttributes();
278  Map<String, String> otherAttributes = new HashMap<>();
279 
280  for (BlackboardAttribute attr : attributes) {
281  if (HANDLED_ATTRIBUTE_TYPES.contains(attr.getAttributeType().getTypeID()) == false) {
282  otherAttributes.put(attr.getAttributeType().getDisplayName(), attr.getDisplayString());
283  }
284  }
285 
286  return otherAttributes;
287  }
288 
296  @NbBundle.Messages({
297  "CallLogArtifactViewer_heading_parties=Parties",
298  "CallLogArtifactViewer_value_unknown=Unknown",
299  "CallLogArtifactViewer_label_from=From",
300  "CallLogArtifactViewer_label_to=To"
301  })
302  private List<AccountPersonaSearcherData> updateView(CallLogViewData callLogViewData) {
303 
304  CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_parties());
305 
306  List<AccountPersonaSearcherData> dataList = new ArrayList<>();
307  // Display From address
308  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_from());
309 
310  if (callLogViewData.getFromAccount() != null) {
311  // check if this is local account
312  String accountDisplayString = getAccountDisplayString(callLogViewData.getFromAccount(), callLogViewData);
313  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, accountDisplayString);
314 
315  // show persona
316  dataList.addAll( CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, callLogViewData.getFromAccount()));
317  } else {
318  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_value_unknown());
319  }
320 
321  // Display To:
322  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_to());
323  if (callLogViewData.getToAccount() != null) {
324  String accountDisplayString = getAccountDisplayString(callLogViewData.getToAccount(), callLogViewData);
325  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, accountDisplayString);
326 
327  dataList.addAll( CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, callLogViewData.getToAccount()));
328 
329  } else {
330  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_value_unknown());
331  }
332 
333  // Display other parties
334  for (String otherParty : callLogViewData.getOtherParties()) {
335  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_to());
336  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, otherParty);
337 
338  dataList.addAll( CommunicationArtifactViewerHelper.addPersonaRow(this, m_gridBagLayout, this.m_constraints, otherParty));
339  }
340 
341  updateMetadataView(callLogViewData);
342 
343  updateOtherAttributesView(callLogViewData);
344 
345  updateSourceView(callLogViewData);
346 
347  if (CentralRepository.isEnabled() == false) {
348  showCRDisabledMessage();
349  }
350 
351  CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
352 
353  this.setLayout(m_gridBagLayout);
354  this.revalidate();
355  this.repaint();
356 
357  return dataList;
358  }
359 
365  @NbBundle.Messages({
366  "CallLogArtifactViewer_heading_metadata=Metadata",
367  "CallLogArtifactViewer_label_direction=Direction",
368  "CallLogArtifactViewer_label_date=Date",
369  "CallLogArtifactViewer_label_duration=Duration"
370  })
371  private void updateMetadataView(CallLogViewData callLogViewData) {
372 
373  CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_metadata());
374 
375  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_direction());
376  if (callLogViewData.getDirection() != null) {
377  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDirection());
378  } else {
379  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_value_unknown());
380  }
381 
382  if (callLogViewData.getDateTimeStr() != null) {
383  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_date());
384  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDateTimeStr());
385  }
386 
387  if (callLogViewData.getDuration() != null) {
388  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_duration());
389  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDuration());
390  }
391 
392  }
393 
399  @NbBundle.Messages({
400  "CallLogArtifactViewer_heading_Source=Source",
401  "CallLogArtifactViewer_label_datasource=Data Source",})
402  private void updateSourceView(CallLogViewData callLogViewData) {
403  CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_Source());
404  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_datasource());
405  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDataSourceName());
406  }
407 
413  @NbBundle.Messages({
414  "CallLogArtifactViewer_heading_others=Other Attributes"
415  })
416  private void updateOtherAttributesView(CallLogViewData callLogViewData) {
417 
418  if (callLogViewData.getOtherAttributes().isEmpty()) {
419  return;
420  }
421  CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_others());
422 
423  for (Map.Entry<String, String> entry : callLogViewData.getOtherAttributes().entrySet()) {
424  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, entry.getKey());
425  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, entry.getValue());
426  }
427  }
428 
429  @NbBundle.Messages({
430  "CalllogArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas."
431  })
432  private void showCRDisabledMessage() {
433  CommunicationArtifactViewerHelper.addBlankLine(this, m_gridBagLayout, m_constraints);
434  m_constraints.gridy++;
435  CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
436  m_constraints.gridy++;
437  }
438 
449  @NbBundle.Messages({
450  "CallLogArtifactViewer_suffix_local=(Local)",})
451  private String getAccountDisplayString(String accountIdentifier, CallLogViewData callLogViewDataNew) {
452  String accountDisplayValue = accountIdentifier;
453  if (callLogViewDataNew.getLocalAccountId() != null && callLogViewDataNew.getLocalAccountId().equalsIgnoreCase(accountIdentifier)) {
454  accountDisplayValue += " " + Bundle.CallLogArtifactViewer_suffix_local();
455  }
456  return accountDisplayValue;
457  }
458 
459  @Override
460  public Component getComponent() {
461  return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
462  }
463 
464  @Override
465  public boolean isSupported(BlackboardArtifact artifact) {
466 
467  return (artifact != null)
468  && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID());
469  }
470 
474  private void resetComponent() {
475 
476  // cancel any outstanding persona searching threads.
477  if(currentAccountFetcher != null && !currentAccountFetcher.isDone()) {
478  currentAccountFetcher.cancel(true);
479  currentAccountFetcher = null;
480  }
481 
482  // clear the panel
483  this.removeAll();
484  this.setLayout(null);
485 
486  m_gridBagLayout = new GridBagLayout();
487  m_constraints = new GridBagConstraints();
488 
489  m_constraints.anchor = GridBagConstraints.FIRST_LINE_START;
490  m_constraints.gridy = 0;
491  m_constraints.gridx = 0;
492  m_constraints.weighty = 0.0;
493  m_constraints.weightx = 0.0; // keep components fixed horizontally.
494  m_constraints.insets = new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
495  m_constraints.fill = GridBagConstraints.NONE;
496 
497  }
498 
499 
500  // Variables declaration - do not modify//GEN-BEGIN:variables
501  // End of variables declaration//GEN-END:variables
502 }
void extractTimeAndDuration(BlackboardArtifact artifact, CallLogViewData callLogViewData)
List< AccountPersonaSearcherData > updateView(CallLogViewData callLogViewData)
String getAccountDisplayString(String accountIdentifier, CallLogViewData callLogViewDataNew)
Map< String, String > extractOtherAttributes(BlackboardArtifact artifact)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

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