Sleuth Kit Java Bindings (JNI)  4.12.1
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 
174  public FileAttachment(DerivedFile derivedFile) throws TskCoreException {
175  objectID = derivedFile.getId();
176  path = derivedFile.getUniquePath();
177  }
178 
184  public FileAttachment(AbstractFile abstractFile) {
185  objectID = abstractFile.getId();
186  path = abstractFile.getParentPath() + "/" + abstractFile.getName();
187  }
188 
194  public String getPathName() {
195  return path;
196  }
197 
204  public long getObjectId() {
205  return objectID;
206  }
207 
216  private String normalizePath(String path) {
217  //normalize the slashes, replace encoded space
218  String adjustedPath = path.replace("\\", "/").replace("%20", " ");
219 
220  // Strip common known mountpoints.
221  for (String mountPoint : KNOWN_MOUNTPOINTS) {
222  if (adjustedPath.toLowerCase().startsWith(mountPoint)) {
223  adjustedPath = ("/").concat(adjustedPath.substring(mountPoint.length()));
224  break;
225  }
226  }
227 
228  return adjustedPath;
229  }
230 
246  private long findAttachmentFile(SleuthkitCase caseDb, String fileName, String parentPathSubstring, Content dataSource) throws TskCoreException {
247 
248  // Find all files with matching name and parent path substring
249  String whereClause = String.format("LOWER(name) = LOWER('%s') AND LOWER(parent_path) LIKE LOWER('%%%s%%')", fileName, parentPathSubstring);
250  List<AbstractFile> matchedFiles = caseDb.findAllFilesWhere(whereClause);
251 
252  // separate the matching files into allocated files on same datsource,
253  // allocated files on other data sources, and unallocated files.
254  List<Long> allocFileMatchesOnSameDatasource = new ArrayList<>();
255  List<Long> allocFileMatchesOnOtherDatasources = new ArrayList<>();
256  List<Long> unallocFileMatches = new ArrayList<>();
257 
258  for (AbstractFile file : matchedFiles) {
259  if (file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
260  if (dataSource.getId() == file.getDataSource().getId()) {
261  allocFileMatchesOnSameDatasource.add(file.getId());
262  } else {
263  allocFileMatchesOnOtherDatasources.add(file.getId());
264  }
265  } else { // unallocated file
266  unallocFileMatches.add(file.getId());
267  }
268  }
269 
270  // pick the best match from the 3 lists.
271  return pickBestMatchFile(allocFileMatchesOnSameDatasource, allocFileMatchesOnOtherDatasources, unallocFileMatches);
272  }
273 
302  private long pickBestMatchFile(List<Long> allocFileMatchesOnSameDatasource,
303  List<Long> allocFileMatchesOnOtherDatasources,
304  List<Long> unallocFileMatches) {
305 
306  // check if there's an allocated file match on the same data source
307  if (!allocFileMatchesOnSameDatasource.isEmpty() && allocFileMatchesOnSameDatasource.size() == 1) {
308  return allocFileMatchesOnSameDatasource.get(0);
309  }
310  // if no match found yet,check if there's an allocated file match on other data sources.
311  if (!allocFileMatchesOnOtherDatasources.isEmpty()
312  && allocFileMatchesOnOtherDatasources.size() == 1) {
313  return allocFileMatchesOnOtherDatasources.get(0);
314  }
315  // if no match found yet, check if there is an unallocated file that matches.
316  if (!unallocFileMatches.isEmpty()
317  && unallocFileMatches.size() == 1) {
318  return unallocFileMatches.get(0);
319  }
320  // no single suitable match found
321  return -1;
322 
323  }
324 
325  @Override
326  public String getLocation() {
327  return this.path;
328  }
329 
330  @Override
331  public Long getObjId() {
332  return this.objectID;
333  }
334  }
335 
336  private final Collection<FileAttachment> fileAttachments;
337  private final Collection<URLAttachment> urlAttachments;
338 
346  public MessageAttachments(Collection<FileAttachment> fileAttachments, Collection<URLAttachment> urlAttachments) {
347  this.fileAttachments = fileAttachments;
348  this.urlAttachments = urlAttachments;
349  }
350 
356  public Collection<FileAttachment> getFileAttachments() {
357  return Collections.unmodifiableCollection(fileAttachments);
358  }
359 
365  public Collection<URLAttachment> getUrlAttachments() {
366  return Collections.unmodifiableCollection(urlAttachments);
367  }
368 
374  public int getAttachmentsCount() {
375  return (fileAttachments.size() + urlAttachments.size());
376  }
377 }
FileAttachment(SleuthkitCase caseDb, Content dataSource, String pathName)
ALLOC
Metadata structure is currently in an allocated state.
Definition: TskData.java:208
MessageAttachments(Collection< FileAttachment > fileAttachments, Collection< URLAttachment > urlAttachments)

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