Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.datasourceprocessors.xry;
20
21import com.google.common.collect.Lists;
22import java.io.File;
23import java.io.IOException;
24import java.io.UncheckedIOException;
25import java.nio.file.Files;
26import java.nio.file.LinkOption;
27import java.nio.file.Path;
28import java.nio.file.attribute.BasicFileAttributes;
29import java.util.Iterator;
30import java.util.List;
31import java.util.UUID;
32import java.util.concurrent.ExecutionException;
33import java.util.logging.Level;
34import java.util.stream.Collectors;
35import java.util.stream.Stream;
36import javax.swing.JPanel;
37import javax.swing.SwingWorker;
38import org.openide.util.NbBundle;
39import org.openide.util.lookup.ServiceProvider;
40import org.openide.util.lookup.ServiceProviders;
41import org.sleuthkit.autopsy.casemodule.Case;
42import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
43import org.sleuthkit.autopsy.casemodule.services.FileManager;
44import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
45import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
46import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
47import org.sleuthkit.autopsy.coreutils.Logger;
48import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
49import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException;
50import org.sleuthkit.datamodel.AbstractFile;
51import org.sleuthkit.datamodel.Blackboard.BlackboardException;
52import org.sleuthkit.datamodel.Host;
53import org.sleuthkit.datamodel.LocalFilesDataSource;
54import org.sleuthkit.datamodel.TskCoreException;
55import 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
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,
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(
335 "XRY Text Export", //Name
336 "", //Timezone
337 host,
338 filePaths,
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 done(DataSourceProcessorResult result, List< String > errList, List< Content > newDataSources)
synchronized static Logger getLogger(String name)
Definition Logger.java:124
XRYReportProcessorSwingWorker(XRYFolder folder, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback, Case currentCase, String uniqueUUID, Host host)
void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback)
void process(String deviceId, Path dataSourcePath, Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack)
void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack)
void run(Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.