Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
ReportingConfigLoader.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.report.infrastructure;
20
21import org.sleuthkit.autopsy.report.ReportModuleSettings;
22import java.io.File;
23import java.io.FileInputStream;
24import java.io.FileOutputStream;
25import java.io.IOException;
26import java.nio.file.Files;
27import java.nio.file.Path;
28import java.nio.file.Paths;
29import java.util.Arrays;
30import java.util.Iterator;
31import java.util.List;
32import java.util.Map;
33import java.util.Map.Entry;
34import java.util.Set;
35import java.util.TreeSet;
36import java.util.logging.Level;
37import org.apache.commons.io.FileUtils;
38import org.openide.util.io.NbObjectInputStream;
39import org.openide.util.io.NbObjectOutputStream;
40import org.sleuthkit.autopsy.coreutils.Logger;
41import org.sleuthkit.autopsy.coreutils.PlatformUtil;
42import org.sleuthkit.autopsy.report.GeneralReportSettings;
43
49final class ReportingConfigLoader {
50
51 private static final Logger logger = Logger.getLogger(ReportingConfigLoader.class.getName());
52 private static final String REPORT_CONFIG_FOLDER = "ReportingConfigs"; //NON-NLS
53
54 private static final String REPORT_CONFIG_FOLDER_PATH_LEGACY = Paths.get(
55 PlatformUtil.getUserConfigDirectory(),
56 ReportingConfigLoader.REPORT_CONFIG_FOLDER
57 ).toAbsolutePath().toString();
58
59 private static final String REPORT_CONFIG_FOLDER_PATH = Paths.get(
60 PlatformUtil.getModuleConfigDirectory(),
61 ReportingConfigLoader.REPORT_CONFIG_FOLDER
62 ).toAbsolutePath().toString();
63
64 private static final String REPORT_SETTINGS_FILE_EXTENSION = ".settings";
65 private static final String TABLE_REPORT_CONFIG_FILE = "TableReportSettings.settings";
66 private static final String FILE_REPORT_CONFIG_FILE = "FileReportSettings.settings";
67 private static final String GENERAL_REPORT_CONFIG_FILE = "GeneralReportSettings.settings";
68 private static final String MODULE_CONFIG_FILE = "ModuleConfigs.settings";
69
70 // Collection of standard report modules that are no longer in Autopsy. We keep
71 // track to suppress any errors when searching for the module since it may still
72 // existing in the configuration file.
73 private static final List<String> DELETED_REPORT_MODULES = Arrays.asList("org.sleuthkit.autopsy.report.modules.stix.STIXReportModule");
74
94 @SuppressWarnings("unchecked")
95 static synchronized ReportingConfig loadConfig(String configName) throws ReportConfigException {
96
97 // reject names that are blank, self-referential, or contain path separators
98 if (configName == null || configName.isEmpty() || configName.equals(".")
99 || configName.indexOf('/') >= 0 || configName.indexOf('\\') >= 0
100 || configName.indexOf(File.separatorChar) >= 0) {
101 throw new ReportConfigException("Invalid report configuration name: " + configName);
102 }
103
104 // construct the configuration directory path and validate against traversal
105 Path reportDirPath = Paths.get(ReportingConfigLoader.REPORT_CONFIG_FOLDER_PATH, configName).normalize();
106 if (!reportDirPath.startsWith(Paths.get(ReportingConfigLoader.REPORT_CONFIG_FOLDER_PATH).normalize())) {
107 throw new ReportConfigException("Invalid report configuration name: " + configName);
108 }
109 File reportDirectory = reportDirPath.toFile();
110
111 // Return null if a reporting configuration for the given name does not exist.
112 if (!reportDirectory.exists()) {
113 throw new ReportConfigException("Unable to find report configuration folder for " + reportDirPath.toString() + ". Please configure in the application Options panel.");
114 }
115
116 if (!reportDirectory.isDirectory() || !reportDirectory.canRead()) {
117 throw new ReportConfigException("Unable to read reporting configuration directory " + reportDirPath.toString());
118 }
119
120 // read in the configuration
121 ReportingConfig config = new ReportingConfig(configName);
122
123 // read table report settings
124 String filePath = reportDirPath.toString() + File.separator + TABLE_REPORT_CONFIG_FILE;
125 try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePath))) {
126 config.setTableReportSettings((TableReportSettings) in.readObject());
127 } catch (IOException | ClassNotFoundException ex) {
128 throw new ReportConfigException("Unable to read table report settings " + filePath, ex);
129 }
130
131 // read file report settings
132 filePath = reportDirPath.toString() + File.separator + FILE_REPORT_CONFIG_FILE;
133 try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePath))) {
134 config.setFileReportSettings((FileReportSettings) in.readObject());
135 } catch (IOException | ClassNotFoundException ex) {
136 throw new ReportConfigException("Unable to read file report settings " + filePath, ex);
137 }
138
139 filePath = reportDirPath.resolve(GENERAL_REPORT_CONFIG_FILE).toString();
140 try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePath))) {
141 config.setGeneralReportSettings((GeneralReportSettings) in.readObject());
142 } catch (IOException | ClassNotFoundException ex) {
143 throw new ReportConfigException("Unable to read general report settings " + filePath, ex);
144 }
145
146 // read map of module configuration objects
147 Map<String, ReportModuleConfig> moduleConfigs = null;
148 filePath = reportDirPath.toString() + File.separator + MODULE_CONFIG_FILE;
149 try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePath))) {
150 moduleConfigs = (Map<String, ReportModuleConfig>) in.readObject();
151 } catch (IOException | ClassNotFoundException ex) {
152 throw new ReportConfigException("Unable to read module configurations map " + filePath, ex);
153 }
154
155 if (moduleConfigs == null || moduleConfigs.isEmpty()) {
156 return config;
157 }
158
159 // read each ReportModuleSettings object individually
160 for (Iterator<Entry<String, ReportModuleConfig>> iterator = moduleConfigs.entrySet().iterator(); iterator.hasNext();) {
161 ReportModuleConfig moduleConfig = iterator.next().getValue();
162 if (DELETED_REPORT_MODULES.contains(moduleConfig.getModuleClassName())) {
163 // Don't try to load settings for known deleted modules
164 continue;
165 }
166 filePath = reportDirPath.toString() + File.separator + moduleConfig.getModuleClassName() + REPORT_SETTINGS_FILE_EXTENSION;
167 try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePath))) {
168 moduleConfig.setModuleSettings((ReportModuleSettings) in.readObject());
169 } catch (IOException | ClassNotFoundException ex) {
170 /*
171 * NOTE: we do not want to re-throw the exception because we do
172 * not want a single error while reading in a (3rd party) report
173 * module to prevent us from reading the entire reporting
174 * configuration.
175 */
176 logger.log(Level.SEVERE, "Unable to read module settings " + filePath, ex);
177 iterator.remove();
178 }
179 }
180
181 config.setModuleConfigs(moduleConfigs);
182
183 return config;
184 }
185
206 static synchronized void saveConfig(ReportingConfig reportConfig) throws ReportConfigException {
207
208 if (reportConfig == null) {
209 throw new ReportConfigException("Reporting configuration is NULL");
210 }
211
212 // reject names that are blank, self-referential, or contain path separators
213 String configName = reportConfig.getName();
214 if (configName == null || configName.isEmpty() || configName.equals(".")
215 || configName.indexOf('/') >= 0 || configName.indexOf('\\') >= 0
216 || configName.indexOf(File.separatorChar) >= 0) {
217 throw new ReportConfigException("Invalid report configuration name: " + configName);
218 }
219
220 // construct the configuration directory path and validate against traversal
221 Path pathToConfigDir = Paths.get(ReportingConfigLoader.REPORT_CONFIG_FOLDER_PATH, configName).normalize();
222 if (!pathToConfigDir.startsWith(Paths.get(ReportingConfigLoader.REPORT_CONFIG_FOLDER_PATH).normalize())) {
223 throw new ReportConfigException("Invalid report configuration name: " + configName);
224 }
225
226 // create configuration directory
227 try {
228 Files.createDirectories(pathToConfigDir); // does not throw if directory already exists
229 } catch (IOException | SecurityException ex) {
230 throw new ReportConfigException("Failed to create reporting configuration directory " + pathToConfigDir.toString(), ex);
231 }
232
233 // save table report settings
234 String filePath = pathToConfigDir.toString() + File.separator + TABLE_REPORT_CONFIG_FILE;
235 try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(filePath))) {
236 out.writeObject(reportConfig.getTableReportSettings());
237 } catch (IOException ex) {
238 throw new ReportConfigException("Unable to save table report configuration " + filePath, ex);
239 }
240
241 // save file report settings
242 filePath = pathToConfigDir.toString() + File.separator + FILE_REPORT_CONFIG_FILE;
243 try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(filePath))) {
244 out.writeObject(reportConfig.getFileReportSettings());
245 } catch (IOException ex) {
246 throw new ReportConfigException("Unable to save file report configuration " + filePath, ex);
247 }
248
249 filePath = pathToConfigDir.resolve(GENERAL_REPORT_CONFIG_FILE).toString();
250 try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(filePath))) {
251 out.writeObject(reportConfig.getGeneralReportSettings());
252 } catch (IOException ex) {
253 throw new ReportConfigException("Unable to save general report configuration " + filePath, ex);
254 }
255
256 // save map of module configuration objects
257 filePath = pathToConfigDir.toString() + File.separator + MODULE_CONFIG_FILE;
258 try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(filePath))) {
259 out.writeObject(reportConfig.getModuleConfigs());
260 } catch (IOException ex) {
261 throw new ReportConfigException("Unable to save module configurations map " + filePath, ex);
262 }
263
264 // save each ReportModuleSettings object individually
265 /*
266 * NOTE: This is done to protect us from errors in reading/writing 3rd
267 * party report module settings. If we were to serialize the entire
268 * ReportingConfig object, then a single error while reading in a 3rd
269 * party report module would prevent us from reading the entire
270 * reporting configuration.
271 */
272 if (reportConfig.getModuleConfigs() == null) {
273 return;
274 }
275 for (ReportModuleConfig moduleConfig : reportConfig.getModuleConfigs().values()) {
276 ReportModuleSettings settings = moduleConfig.getModuleSettings();
277 filePath = pathToConfigDir.toString() + File.separator + moduleConfig.getModuleClassName() + REPORT_SETTINGS_FILE_EXTENSION;
278 try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(filePath))) {
279 out.writeObject(settings);
280 } catch (IOException ex) {
281 throw new ReportConfigException("Unable to save module settings " + filePath, ex);
282 }
283 }
284 }
285
293 static synchronized Set<String> getListOfReportConfigs() {
294 File reportDirPath = new File(ReportingConfigLoader.REPORT_CONFIG_FOLDER_PATH);
295 Set<String> reportNameList = new TreeSet<>();
296
297 if (!reportDirPath.exists()) {
298 return reportNameList;
299 }
300
301 for (File file : reportDirPath.listFiles()) {
302 reportNameList.add(file.getName());
303 }
304
305 return reportNameList;
306 }
307
317 static synchronized boolean configExists(String configName) {
318 // construct the configuration directory path
319 Path reportDirPath = Paths.get(ReportingConfigLoader.REPORT_CONFIG_FOLDER_PATH, configName);
320 File reportDirectory = reportDirPath.toFile();
321
322 return reportDirectory.exists();
323 }
324
325 static void upgradeConfig() throws IOException {
326 File oldPath = new File(REPORT_CONFIG_FOLDER_PATH_LEGACY);
327 File newPath = new File(REPORT_CONFIG_FOLDER_PATH);
328
329 if (oldPath.exists() && Files.list(oldPath.toPath()).findFirst().isPresent()
330 && (!newPath.exists() || !Files.list(newPath.toPath()).findFirst().isPresent())) {
331 newPath.mkdirs();
332 FileUtils.copyDirectory(oldPath, newPath);
333 }
334
335 }
336
337}

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