Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
XRYDataSourceProcessor.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 com.google.common.collect.Lists;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.UncheckedIOException;
25 import java.nio.file.Files;
26 import java.nio.file.LinkOption;
27 import java.nio.file.Path;
28 import java.nio.file.attribute.BasicFileAttributes;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.UUID;
32 import java.util.concurrent.ExecutionException;
33 import java.util.logging.Level;
34 import java.util.stream.Collectors;
35 import java.util.stream.Stream;
36 import javax.swing.JPanel;
37 import javax.swing.SwingWorker;
38 import org.openide.util.NbBundle;
39 import org.openide.util.lookup.ServiceProvider;
40 import org.openide.util.lookup.ServiceProviders;
50 import org.sleuthkit.datamodel.AbstractFile;
51 import org.sleuthkit.datamodel.Blackboard.BlackboardException;
52 import org.sleuthkit.datamodel.Host;
53 import org.sleuthkit.datamodel.LocalFilesDataSource;
54 import org.sleuthkit.datamodel.TskCoreException;
55 import org.sleuthkit.datamodel.TskDataException;
56 
60 @ServiceProviders(value = {
61  @ServiceProvider(service = DataSourceProcessor.class),
62  @ServiceProvider(service = AutoIngestDataSourceProcessor.class)
63 })
65 
66  private final XRYDataSourceProcessorConfigPanel configPanel;
67 
68  private static final int XRY_FILES_DEPTH = 1;
69 
70  //Background processor to relieve the EDT from adding files to the case
71  //database and parsing the report files.
73 
74  private static final Logger logger = Logger.getLogger(XRYDataSourceProcessor.class.getName());
75 
77  configPanel = XRYDataSourceProcessorConfigPanel.getInstance();
78  }
79 
80  @Override
81  @NbBundle.Messages({
82  "XRYDataSourceProcessor.dataSourceType=XRY Text Export"
83  })
84  public String getDataSourceType() {
85  return Bundle.XRYDataSourceProcessor_dataSourceType();
86  }
87 
88  @Override
89  public JPanel getPanel() {
90  return configPanel;
91  }
92 
99  @Override
100  @NbBundle.Messages({
101  "XRYDataSourceProcessor.noPathSelected=Please select a folder containing exported XRY text files",
102  "XRYDataSourceProcessor.notReadable=Selected path is not readable",
103  "XRYDataSourceProcessor.notXRYFolder=Selected folder did not contain any XRY text files",
104  "XRYDataSourceProcessor.ioError=I/O error occured trying to test the selected folder",
105  "XRYDataSourceProcessor.childNotReadable=Top level path [ %s ] is not readable",
106  "XRYDataSourceProcessor.notAFolder=The selected path is not a folder"
107  })
108  public boolean isPanelValid() {
109  configPanel.clearErrorText();
110  String selectedFilePath = configPanel.getSelectedFilePath();
111  if (selectedFilePath.isEmpty()) {
112  configPanel.setErrorText(Bundle.XRYDataSourceProcessor_noPathSelected());
113  return false;
114  }
115 
116  File selectedFile = new File(selectedFilePath);
117  Path selectedPath = selectedFile.toPath();
118 
119  //Test permissions
120  if (!Files.isReadable(selectedPath)) {
121  configPanel.setErrorText(Bundle.XRYDataSourceProcessor_notReadable());
122  return false;
123  }
124 
125  try {
126  BasicFileAttributes attr = Files.readAttributes(selectedPath,
127  BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
128 
129  if (!attr.isDirectory()) {
130  configPanel.setErrorText(Bundle.XRYDataSourceProcessor_notAFolder());
131  return false;
132  }
133 
134  //Ensure all of the XRY_FILES_DEPTH paths are readable.
135  try (Stream<Path> allFiles = Files.walk(selectedPath, XRY_FILES_DEPTH)) {
136  Iterator<Path> allFilesIterator = allFiles.iterator();
137  while (allFilesIterator.hasNext()) {
138  Path currentPath = allFilesIterator.next();
139  if (!Files.isReadable(currentPath)) {
140  Path fileName = currentPath.subpath(currentPath.getNameCount() - 2,
141  currentPath.getNameCount());
142  configPanel.setErrorText(String.format(
143  Bundle.XRYDataSourceProcessor_childNotReadable(),
144  fileName.toString()));
145  return false;
146  }
147  }
148  }
149 
150  //Validate the folder.
151  if (!XRYFolder.isXRYFolder(selectedPath)) {
152  configPanel.setErrorText(Bundle.XRYDataSourceProcessor_notXRYFolder());
153  return false;
154  }
155  } catch (IOException | UncheckedIOException ex) {
156  configPanel.setErrorText(Bundle.XRYDataSourceProcessor_ioError());
157  logger.log(Level.WARNING, "[XRY DSP] I/O exception encountered trying to test the XRY folder.", ex);
158  return false;
159  }
160 
161  return true;
162  }
163 
175  @Override
176  public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
177  try {
178  if (XRYFolder.isXRYFolder(dataSourcePath)) {
179  return 100;
180  }
181  } catch (IOException ex) {
182  throw new AutoIngestDataSourceProcessorException("[XRY DSP] encountered I/O error " + ex.getMessage(), ex);
183  }
184  return 0;
185  }
186 
196  @Override
197  public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
198  run(null, progressMonitor, callback);
199  }
200 
216  @Override
217  @NbBundle.Messages({
218  "XRYDataSourceProcessor.noCurrentCase=No case is open."
219  })
220  public void run(Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
221  progressMonitor.setIndeterminate(true);
222  String selectedFilePath = configPanel.getSelectedFilePath();
223  File selectedFile = new File(selectedFilePath);
224  Path selectedPath = selectedFile.toPath();
225 
226  try {
227  XRYFolder xryFolder = new XRYFolder(selectedPath);
228  Case currentCase = Case.getCurrentCaseThrows();
229  String uniqueUUID = UUID.randomUUID().toString();
230  //Move heavy lifting to a background task.
231  swingWorker = new XRYReportProcessorSwingWorker(xryFolder, progressMonitor,
232  callback, currentCase, uniqueUUID, host);
233  swingWorker.execute();
234  } catch (NoCurrentCaseException ex) {
235  logger.log(Level.WARNING, "[XRY DSP] No case is currently open.", ex);
237  Lists.newArrayList(Bundle.XRYDataSourceProcessor_noCurrentCase(),
238  ex.getMessage()), Lists.newArrayList());
239  }
240  }
241 
242  @Override
243  public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
244  process(deviceId, dataSourcePath, null, progressMonitor, callBack);
245  }
246 
261  @Override
262  public void process(String deviceId, Path dataSourcePath, Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
263  progressMonitor.setIndeterminate(true);
264 
265  try {
266  XRYFolder xryFolder = new XRYFolder(dataSourcePath);
267  Case currentCase = Case.getCurrentCaseThrows();
268  //Move heavy lifting to a background task.
269  swingWorker = new XRYReportProcessorSwingWorker(xryFolder, progressMonitor,
270  callBack, currentCase, deviceId, host);
271  swingWorker.execute();
272  } catch (NoCurrentCaseException ex) {
273  logger.log(Level.WARNING, "[XRY DSP] No case is currently open.", ex);
275  Lists.newArrayList(Bundle.XRYDataSourceProcessor_noCurrentCase(),
276  ex.getMessage()), Lists.newArrayList());
277  }
278  }
279 
280  @Override
281  public void cancel() {
282  if (swingWorker != null) {
283  swingWorker.cancel(true);
284  }
285  }
286 
287  @Override
288  public void reset() {
289  //Clear the current selected file path.
290  configPanel.clearSelectedFilePath();
291  }
292 
297  private class XRYReportProcessorSwingWorker extends SwingWorker<LocalFilesDataSource, Void> {
298 
301  private final Case currentCase;
302  private final XRYFolder xryFolder;
303  private final String uniqueUUID;
304  private final Host host;
305 
306  public XRYReportProcessorSwingWorker(XRYFolder folder,
307  DataSourceProcessorProgressMonitor progressMonitor,
309  Case currentCase, String uniqueUUID, Host host) {
310 
311  this.xryFolder = folder;
312  this.progressMonitor = progressMonitor;
313  this.callback = callback;
314  this.currentCase = currentCase;
315  this.uniqueUUID = uniqueUUID;
316  this.host = host;
317  }
318 
319  @Override
320  @NbBundle.Messages({
321  "XRYDataSourceProcessor.preppingFiles=Preparing to add files to the case database",
322  "XRYDataSourceProcessor.processingFiles=Processing all XRY files..."
323  })
324  protected LocalFilesDataSource doInBackground() throws TskCoreException,
325  TskDataException, IOException, BlackboardException {
326  progressMonitor.setProgressText(Bundle.XRYDataSourceProcessor_preppingFiles());
327 
328  List<Path> nonXRYFiles = xryFolder.getNonXRYFiles();
329  List<String> filePaths = nonXRYFiles.stream()
330  //Map paths to string representations.
331  .map(Path::toString)
332  .collect(Collectors.toList());
333  LocalFilesDataSource dataSource = currentCase.getServices().getFileManager().addLocalFilesDataSource(
334  uniqueUUID,
335  "XRY Text Export", //Name
336  "", //Timezone
337  host,
338  filePaths,
339  new ProgressMonitorAdapter(progressMonitor));
340 
341  //Process the report files.
342  progressMonitor.setProgressText(Bundle.XRYDataSourceProcessor_processingFiles());
343  XRYReportProcessor.process(xryFolder, dataSource, currentCase.getSleuthkitCase());
344  return dataSource;
345  }
346 
347  @Override
348  @NbBundle.Messages({
349  "XRYDataSourceProcessor.unexpectedError=Internal error occurred while processing XRY report"
350  })
351  public void done() {
352  try {
353  LocalFilesDataSource newDataSource = get();
355  Lists.newArrayList(), Lists.newArrayList(newDataSource));
356  } catch (InterruptedException ex) {
357  logger.log(Level.WARNING, "[XRY DSP] Thread was interrupted while processing the XRY report."
358  + " The case may or may not have the complete XRY report.", ex);
360  Lists.newArrayList(), Lists.newArrayList());
361  } catch (ExecutionException ex) {
362  logger.log(Level.SEVERE, "[XRY DSP] Unexpected internal error while processing XRY report.", ex);
364  Lists.newArrayList(Bundle.XRYDataSourceProcessor_unexpectedError(),
365  ex.toString()), Lists.newArrayList());
366  }
367  }
368 
373  private class ProgressMonitorAdapter implements FileManager.FileAddProgressUpdater {
374 
376 
378  this.progressMonitor = progressMonitor;
379  }
380 
381  @Override
382  @NbBundle.Messages({
383  "XRYDataSourceProcessor.fileAdded=Added %s to the case database"
384  })
385  public void fileAdded(AbstractFile newFile) {
386  progressMonitor.setProgressText(String.format(Bundle.XRYDataSourceProcessor_fileAdded(), newFile.getName()));
387  }
388  }
389  }
390 }
void process(String deviceId, Path dataSourcePath, Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack)
LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootVirtualDirectoryName, String timeZone, List< String > localFilePaths, FileAddProgressUpdater progressUpdater)
void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback)
void done(DataSourceProcessorResult result, List< String > errList, List< Content > newDataSources)
XRYReportProcessorSwingWorker(XRYFolder folder, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback, Case currentCase, String uniqueUUID, Host host)
void run(Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.