Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
HashLookupSettings.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011 - 2016 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.modules.hashdatabase;
20 
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.Serializable;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.logging.Level;
29 import javax.swing.JOptionPane;
30 import org.apache.commons.io.FileUtils;
31 import org.openide.util.NbBundle;
32 import org.openide.util.io.NbObjectInputStream;
33 import org.openide.util.io.NbObjectOutputStream;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.Element;
41 import org.w3c.dom.NodeList;
42 
46 final class HashLookupSettings implements Serializable {
47 
48  private static final String SERIALIZATION_FILE_NAME = "hashLookup.settings"; //NON-NLS
49  private static final String SERIALIZATION_FILE_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + SERIALIZATION_FILE_NAME; //NON-NLS
50  private static final String SET_ELEMENT = "hash_set"; //NON-NLS
51  private static final String SET_NAME_ATTRIBUTE = "name"; //NON-NLS
52  private static final String SET_TYPE_ATTRIBUTE = "type"; //NON-NLS
53  private static final String SEARCH_DURING_INGEST_ATTRIBUTE = "use_for_ingest"; //NON-NLS
54  private static final String SEND_INGEST_MESSAGES_ATTRIBUTE = "show_inbox_messages"; //NON-NLS
55  private static final String PATH_ELEMENT = "hash_set_path"; //NON-NLS
56  private static final String LEGACY_PATH_NUMBER_ATTRIBUTE = "number"; //NON-NLS
57  private static final String CONFIG_FILE_NAME = "hashsets.xml"; //NON-NLS
58  private static final String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CONFIG_FILE_NAME;
59  private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
60 
61  private static final long serialVersionUID = 1L;
62  private final List<HashDbInfo> hashDbInfoList;
63 
69  HashLookupSettings(List<HashDbInfo> hashDbInfoList) {
70  this.hashDbInfoList = hashDbInfoList;
71  }
72 
79  HashLookupSettings(List<HashDbManager.HashDb> knownHashSets, List<HashDbManager.HashDb> knownBadHashSets) throws HashLookupSettingsException {
80  hashDbInfoList = new ArrayList<>();
81  this.addHashesToList(knownHashSets);
82  this.addHashesToList(knownBadHashSets);
83  }
84 
92  private void addHashesToList(List<HashDbManager.HashDb> hashSetList) throws HashLookupSettingsException {
93  for (HashDbManager.HashDb hashDb : hashSetList) {
94  try {
95  String dbPath;
96  if (hashDb.hasIndexOnly()) {
97  dbPath = hashDb.getIndexPath();
98  } else {
99  dbPath = hashDb.getDatabasePath();
100  }
101  hashDbInfoList.add(new HashDbInfo(hashDb.getHashSetName(), hashDb.getKnownFilesType(), hashDb.getSearchDuringIngest(), hashDb.getSendIngestMessages(), dbPath));
102  } catch (TskCoreException ex) {
103  throw new HashLookupSettingsException("Couldn't add hash database named: " + hashDb.getHashSetName(), ex);
104  }
105  }
106  }
107 
113  List<HashDbInfo> getHashDbInfo() {
114  return hashDbInfoList;
115  }
116 
125  static HashLookupSettings readSettings() throws HashLookupSettingsException {
126  File fileSetFile = new File(SERIALIZATION_FILE_PATH);
127  if (fileSetFile.exists()) {
128  return readSerializedSettings();
129  }
130  return readXmlSettings();
131 
132  }
133 
143  private static HashLookupSettings readSerializedSettings() throws HashLookupSettingsException {
144  try {
145  try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(SERIALIZATION_FILE_PATH))) {
146  HashLookupSettings filesSetsSettings = (HashLookupSettings) in.readObject();
147  return filesSetsSettings;
148  }
149  } catch (IOException | ClassNotFoundException ex) {
150  throw new HashLookupSettingsException("Could not read hash database settings.", ex);
151  }
152  }
153 
163  private static HashLookupSettings readXmlSettings() throws HashLookupSettingsException {
164  File xmlFile = new File(configFilePath);
165  if (xmlFile.exists()) {
166  boolean updatedSchema = false;
167 
168  // Open the XML document that implements the configuration file.
169  final Document doc = XMLUtil.loadDoc(HashDbManager.class, configFilePath);
170  if (doc == null) {
171  throw new HashLookupSettingsException("Could not open xml document.");
172  }
173 
174  // Get the root element.
175  Element root = doc.getDocumentElement();
176  if (root == null) {
177  throw new HashLookupSettingsException("Error loading hash sets: invalid file format.");
178  }
179 
180  // Get the hash set elements.
181  NodeList setsNList = root.getElementsByTagName(SET_ELEMENT);
182  int numSets = setsNList.getLength();
183 
184  // Create HashDbInfo objects for each hash set element. Throws on malformed xml.
185  String attributeErrorMessage = "Missing %s attribute"; //NON-NLS
186  String elementErrorMessage = "Empty %s element"; //NON-NLS
187  List<String> hashSetNames = new ArrayList<>();
188  List<HashDbInfo> hashDbInfoList = new ArrayList<>();
189  for (int i = 0; i < numSets; ++i) {
190  Element setEl = (Element) setsNList.item(i);
191 
192  String hashSetName = setEl.getAttribute(SET_NAME_ATTRIBUTE);
193  if (hashSetName.isEmpty()) {
194  throw new HashLookupSettingsException(String.format(attributeErrorMessage, SET_NAME_ATTRIBUTE));
195  }
196 
197  // Handle configurations saved before duplicate hash set names were not permitted.
198  if (hashSetNames.contains(hashSetName)) {
199  int suffix = 0;
200  String newHashSetName;
201  do {
202  ++suffix;
203  newHashSetName = hashSetName + suffix;
204  } while (hashSetNames.contains(newHashSetName));
205  logger.log(Level.INFO, "Duplicate hash set name " + hashSetName + " found. Replacing with " + newHashSetName + ".");
206  if (RuntimeProperties.runningWithGUI()) {
207  JOptionPane.showMessageDialog(null,
208  NbBundle.getMessage(HashLookupSettings.class,
209  "HashDbManager.replacingDuplicateHashsetNameMsg",
210  hashSetName, newHashSetName),
211  NbBundle.getMessage(HashLookupSettings.class, "HashDbManager.openHashDbErr"),
212  JOptionPane.ERROR_MESSAGE);
213  hashSetName = newHashSetName;
214  }
215  }
216 
217  String knownFilesType = setEl.getAttribute(SET_TYPE_ATTRIBUTE);
218  if (knownFilesType.isEmpty()) {
219  throw new HashLookupSettingsException(String.format(attributeErrorMessage, SET_TYPE_ATTRIBUTE));
220  }
221 
222  // Handle legacy known files types.
223  if (knownFilesType.equals("NSRL")) { //NON-NLS
224  knownFilesType = HashDbManager.HashDb.KnownFilesType.KNOWN.toString();
225  updatedSchema = true;
226  }
227 
228  final String searchDuringIngest = setEl.getAttribute(SEARCH_DURING_INGEST_ATTRIBUTE);
229  if (searchDuringIngest.isEmpty()) {
230  throw new HashLookupSettingsException(String.format(attributeErrorMessage, SEND_INGEST_MESSAGES_ATTRIBUTE));
231  }
232  Boolean searchDuringIngestFlag = Boolean.parseBoolean(searchDuringIngest);
233 
234  final String sendIngestMessages = setEl.getAttribute(SEND_INGEST_MESSAGES_ATTRIBUTE);
235  if (searchDuringIngest.isEmpty()) {
236  throw new HashLookupSettingsException(String.format(attributeErrorMessage, SEND_INGEST_MESSAGES_ATTRIBUTE));
237  }
238  Boolean sendIngestMessagesFlag = Boolean.parseBoolean(sendIngestMessages);
239 
240  String dbPath;
241  NodeList pathsNList = setEl.getElementsByTagName(PATH_ELEMENT);
242  if (pathsNList.getLength() > 0) {
243  Element pathEl = (Element) pathsNList.item(0); // Shouldn't be more than one.
244 
245  // Check for legacy path number attribute.
246  String legacyPathNumber = pathEl.getAttribute(LEGACY_PATH_NUMBER_ATTRIBUTE);
247  if (null != legacyPathNumber && !legacyPathNumber.isEmpty()) {
248  updatedSchema = true;
249  }
250 
251  dbPath = pathEl.getTextContent();
252  if (dbPath.isEmpty()) {
253  throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT));
254  }
255  } else {
256  throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT));
257  }
258  hashDbInfoList.add(new HashDbInfo(hashSetName, HashDbManager.HashDb.KnownFilesType.valueOf(knownFilesType),
259  searchDuringIngestFlag, sendIngestMessagesFlag, dbPath));
260  hashSetNames.add(hashSetName);
261  }
262 
263  if (updatedSchema) {
264  String backupFilePath = configFilePath + ".v1_backup"; //NON-NLS
265  String messageBoxTitle = NbBundle.getMessage(HashLookupSettings.class,
266  "HashDbManager.msgBoxTitle.confFileFmtChanged");
267  String baseMessage = NbBundle.getMessage(HashLookupSettings.class,
268  "HashDbManager.baseMessage.updatedFormatHashDbConfig");
269  try {
270  FileUtils.copyFile(new File(configFilePath), new File(backupFilePath));
271  logger.log(Level.INFO, "Updated the schema, backup saved at: " + backupFilePath);
272  if (RuntimeProperties.runningWithGUI()) {
273  JOptionPane.showMessageDialog(null,
274  NbBundle.getMessage(HashLookupSettings.class,
275  "HashDbManager.savedBackupOfOldConfigMsg",
276  baseMessage, backupFilePath),
277  messageBoxTitle,
278  JOptionPane.INFORMATION_MESSAGE);
279  }
280  } catch (IOException ex) {
281  logger.log(Level.WARNING, "Failed to save backup of old format configuration file to " + backupFilePath, ex); //NON-NLS
282  JOptionPane.showMessageDialog(null, baseMessage, messageBoxTitle, JOptionPane.INFORMATION_MESSAGE);
283  }
284  HashLookupSettings settings;
285  settings = new HashLookupSettings(hashDbInfoList);
286  HashLookupSettings.writeSettings(settings);
287  }
288  return new HashLookupSettings(hashDbInfoList);
289  } else {
290  return new HashLookupSettings(new ArrayList<>());
291  }
292  }
293 
301  static boolean writeSettings(HashLookupSettings settings) {
302  try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(SERIALIZATION_FILE_PATH))) {
303  out.writeObject(settings);
304  return true;
305  } catch (Exception ex) {
306  logger.log(Level.SEVERE, "Could not wtite hash database settings.");
307  return false;
308  }
309  }
310 
316  static final class HashDbInfo implements Serializable {
317 
318  private static final long serialVersionUID = 1L;
319  private final String hashSetName;
320  private final HashDbManager.HashDb.KnownFilesType knownFilesType;
321  private final boolean searchDuringIngest;
322  private final boolean sendIngestMessages;
323  private final String path;
324 
335  HashDbInfo(String hashSetName, HashDbManager.HashDb.KnownFilesType knownFilesType, boolean searchDuringIngest, boolean sendIngestMessages, String path) {
336  this.hashSetName = hashSetName;
337  this.knownFilesType = knownFilesType;
338  this.searchDuringIngest = searchDuringIngest;
339  this.sendIngestMessages = sendIngestMessages;
340  this.path = path;
341  }
342 
348  String getHashSetName() {
349  return hashSetName;
350  }
351 
357  HashDbManager.HashDb.KnownFilesType getKnownFilesType() {
358  return knownFilesType;
359  }
360 
366  boolean getSearchDuringIngest() {
367  return searchDuringIngest;
368  }
369 
375  boolean getSendIngestMessages() {
376  return sendIngestMessages;
377  }
378 
384  String getPath() {
385  return path;
386  }
387  }
388 
394  static class HashLookupSettingsException extends Exception {
395 
396  private static final long serialVersionUID = 1L;
397 
398  HashLookupSettingsException(String message) {
399  super(message);
400  }
401 
402  HashLookupSettingsException(String message, Throwable throwable) {
403  super(message, throwable);
404  }
405  }
406 }

Copyright © 2012-2016 Basis Technology. Generated on: Mon Apr 24 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.