Sleuth Kit Java Bindings (JNI)  4.6
Java bindings for using The Sleuth Kit
MessageAttachments.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
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.datamodel.blackboardutils.attributes;
20 
21 import com.google.common.collect.ImmutableList;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.List;
32 
39 public final class MessageAttachments {
40 
45  public interface Attachment {
46 
52  String getLocation();
53 
54  /*
55  * Returns object id of the attachment file.
56  *
57  * @return Object id of attachment, may be null if not available or not
58  * applicable.
59  */
60  Long getObjId();
61 
62  }
63 
69  public static class URLAttachment implements Attachment {
70 
71  private final String url;
72 
78  public URLAttachment(String url) {
79  this.url = url;
80  }
81 
87  public String getURL() {
88  return url;
89  }
90 
91  @Override
92  public String getLocation() {
93  return this.url;
94  }
95 
96  @Override
97  public Long getObjId() {
98  // no real object available.
99  return null;
100  }
101 
102  }
103 
114  public static final class FileAttachment implements Attachment {
115 
116  private final String path;
117  private final long objectID;
118 
119  // Mobile phones often create mount points to refer to SD Cards or other
120  // fixed/removable storage media.
121  //
122  // Applications use these mount points when referring files. But they may
123  // not exist physically in the data source.
124  //
125  // Common, wellknown mount points are stripped from the file paths to
126  // accurately search for the file in the image.
127  transient private static final List<String> KNOWN_MOUNTPOINTS
128  = ImmutableList.of(
129  "/data/", // NON-NLS
130  "/storage/emulated/"); //NON-NLS
131 
146  public FileAttachment(SleuthkitCase caseDb, Content dataSource, String pathName) throws TskCoreException {
147 
148  //normalize the slashes.
149  this.path = normalizePath(pathName);
150 
151  String fileName = path.substring(path.lastIndexOf('/') + 1);
152  if (fileName.isEmpty()) {
153  throw new TskCoreException(String.format("No file name specified for attachment file: %s, on data source = %d", path, dataSource.getId()));
154  }
155 
156  String parentPathSubString = (path.lastIndexOf('/') < 0) ? "" : path.substring(0, path.lastIndexOf('/'));
157 
158  // find the attachment file
159  objectID = findAttachmentFile(caseDb, fileName, parentPathSubString, dataSource);
160  }
161 
172  public FileAttachment(DerivedFile derivedFile) {
173  objectID = derivedFile.getId();
174  path = derivedFile.getLocalAbsPath() + "/" + derivedFile.getName();
175  }
176 
182  public FileAttachment(AbstractFile abstractFile) {
183  objectID = abstractFile.getId();
184  path = abstractFile.getParentPath() + "/" + abstractFile.getName();
185  }
186 
192  public String getPathName() {
193  return path;
194  }
195 
202  public long getObjectId() {
203  return objectID;
204  }
205 
214  private String normalizePath(String path) {
215  //normalize the slashes, replace encoded space
216  String adjustedPath = path.replace("\\", "/").replace("%20", " ");
217 
218  // Strip common known mountpoints.
219  for (String mountPoint : KNOWN_MOUNTPOINTS) {
220  if (adjustedPath.toLowerCase().startsWith(mountPoint)) {
221  adjustedPath = ("/").concat(adjustedPath.substring(mountPoint.length()));
222  break;
223  }
224  }
225 
226  return adjustedPath;
227  }
228 
244  private long findAttachmentFile(SleuthkitCase caseDb, String fileName, String parentPathSubstring, Content dataSource) throws TskCoreException {
245 
246  // Find all files with matching name and parent path substring
247  String whereClause = String.format("LOWER(name) = LOWER('%s') AND LOWER(parent_path) LIKE LOWER('%%%s%%')", fileName, parentPathSubstring);
248  List<AbstractFile> matchedFiles = caseDb.findAllFilesWhere(whereClause);
249 
250  // separate the matching files into allocated files on same datsource,
251  // allocated files on other data sources, and unallocated files.
252  List<Long> allocFileMatchesOnSameDatasource = new ArrayList<>();
253  List<Long> allocFileMatchesOnOtherDatasources = new ArrayList<>();
254  List<Long> unallocFileMatches = new ArrayList<>();
255 
256  for (AbstractFile file : matchedFiles) {
257  if (file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
258  if (dataSource.getId() == file.getDataSource().getId()) {
259  allocFileMatchesOnSameDatasource.add(file.getId());
260  } else {
261  allocFileMatchesOnOtherDatasources.add(file.getId());
262  }
263  } else { // unallocated file
264  unallocFileMatches.add(file.getId());
265  }
266  }
267 
268  // pick the best match from the 3 lists.
269  return pickBestMatchFile(allocFileMatchesOnSameDatasource, allocFileMatchesOnOtherDatasources, unallocFileMatches);
270  }
271 
300  private long pickBestMatchFile(List<Long> allocFileMatchesOnSameDatasource,
301  List<Long> allocFileMatchesOnOtherDatasources,
302  List<Long> unallocFileMatches) {
303 
304  // check if there's an allocated file match on the same data source
305  if (!allocFileMatchesOnSameDatasource.isEmpty() && allocFileMatchesOnSameDatasource.size() == 1) {
306  return allocFileMatchesOnSameDatasource.get(0);
307  }
308  // if no match found yet,check if there's an allocated file match on other data sources.
309  if (!allocFileMatchesOnOtherDatasources.isEmpty()
310  && allocFileMatchesOnOtherDatasources.size() == 1) {
311  return allocFileMatchesOnOtherDatasources.get(0);
312  }
313  // if no match found yet, check if there is an unallocated file that matches.
314  if (!unallocFileMatches.isEmpty()
315  && unallocFileMatches.size() == 1) {
316  return unallocFileMatches.get(0);
317  }
318  // no single suitable match found
319  return -1;
320 
321  }
322 
323  @Override
324  public String getLocation() {
325  return this.path;
326  }
327 
328  @Override
329  public Long getObjId() {
330  return this.objectID;
331  }
332  }
333 
334 
335  private final Collection<FileAttachment> fileAttachments;
336  private final Collection<URLAttachment> urlAttachments;
337 
345  public MessageAttachments(Collection<FileAttachment> fileAttachments, Collection<URLAttachment> urlAttachments) {
346  this.fileAttachments = fileAttachments;
347  this.urlAttachments = urlAttachments;
348  }
349 
355  public Collection<FileAttachment> getFileAttachments() {
356  return Collections.unmodifiableCollection(fileAttachments);
357  }
358 
364  public Collection<URLAttachment> getUrlAttachments() {
365  return Collections.unmodifiableCollection(urlAttachments);
366  }
367 
373  public int getAttachmentsCount() {
374  return (fileAttachments.size() + urlAttachments.size());
375  }
376 }
FileAttachment(SleuthkitCase caseDb, Content dataSource, String pathName)
ALLOC
Metadata structure is currently in an allocated state.
Definition: TskData.java:206
MessageAttachments(Collection< FileAttachment > fileAttachments, Collection< URLAttachment > urlAttachments)

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