19 package org.sleuthkit.autopsy.modules.hashdatabase;
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;
46 final class HashLookupSettings
implements Serializable {
48 private static final String SERIALIZATION_FILE_NAME =
"hashLookup.settings";
49 private static final String SERIALIZATION_FILE_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + SERIALIZATION_FILE_NAME;
50 private static final String SET_ELEMENT =
"hash_set";
51 private static final String SET_NAME_ATTRIBUTE =
"name";
52 private static final String SET_TYPE_ATTRIBUTE =
"type";
53 private static final String SEARCH_DURING_INGEST_ATTRIBUTE =
"use_for_ingest";
54 private static final String SEND_INGEST_MESSAGES_ATTRIBUTE =
"show_inbox_messages";
55 private static final String PATH_ELEMENT =
"hash_set_path";
56 private static final String LEGACY_PATH_NUMBER_ATTRIBUTE =
"number";
57 private static final String CONFIG_FILE_NAME =
"hashsets.xml";
58 private static final String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CONFIG_FILE_NAME;
59 private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
61 private static final long serialVersionUID = 1L;
62 private final List<HashDbInfo> hashDbInfoList;
69 HashLookupSettings(List<HashDbInfo> hashDbInfoList) {
70 this.hashDbInfoList = hashDbInfoList;
79 HashLookupSettings(List<HashDbManager.HashDb> knownHashSets, List<HashDbManager.HashDb> knownBadHashSets)
throws HashLookupSettingsException {
80 hashDbInfoList =
new ArrayList<>();
81 this.addHashesToList(knownHashSets);
82 this.addHashesToList(knownBadHashSets);
92 private void addHashesToList(List<HashDbManager.HashDb> hashSetList)
throws HashLookupSettingsException {
93 for (HashDbManager.HashDb hashDb : hashSetList) {
96 if (hashDb.hasIndexOnly()) {
97 dbPath = hashDb.getIndexPath();
99 dbPath = hashDb.getDatabasePath();
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);
113 List<HashDbInfo> getHashDbInfo() {
114 return hashDbInfoList;
125 static HashLookupSettings readSettings() throws HashLookupSettingsException {
126 File fileSetFile =
new File(SERIALIZATION_FILE_PATH);
127 if (fileSetFile.exists()) {
128 return readSerializedSettings();
130 return readXmlSettings();
143 private static HashLookupSettings readSerializedSettings() throws HashLookupSettingsException {
145 try (NbObjectInputStream in =
new NbObjectInputStream(
new FileInputStream(SERIALIZATION_FILE_PATH))) {
146 HashLookupSettings filesSetsSettings = (HashLookupSettings) in.readObject();
147 return filesSetsSettings;
149 }
catch (IOException | ClassNotFoundException ex) {
150 throw new HashLookupSettingsException(
"Could not read hash database settings.", ex);
163 private static HashLookupSettings readXmlSettings() throws HashLookupSettingsException {
164 File xmlFile =
new File(configFilePath);
165 if (xmlFile.exists()) {
166 boolean updatedSchema =
false;
169 final Document doc = XMLUtil.loadDoc(HashDbManager.class, configFilePath);
171 throw new HashLookupSettingsException(
"Could not open xml document.");
175 Element root = doc.getDocumentElement();
177 throw new HashLookupSettingsException(
"Error loading hash sets: invalid file format.");
181 NodeList setsNList = root.getElementsByTagName(SET_ELEMENT);
182 int numSets = setsNList.getLength();
185 String attributeErrorMessage =
"Missing %s attribute";
186 String elementErrorMessage =
"Empty %s element";
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);
192 String hashSetName = setEl.getAttribute(SET_NAME_ATTRIBUTE);
193 if (hashSetName.isEmpty()) {
194 throw new HashLookupSettingsException(String.format(attributeErrorMessage, SET_NAME_ATTRIBUTE));
198 if (hashSetNames.contains(hashSetName)) {
200 String newHashSetName;
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;
217 String knownFilesType = setEl.getAttribute(SET_TYPE_ATTRIBUTE);
218 if (knownFilesType.isEmpty()) {
219 throw new HashLookupSettingsException(String.format(attributeErrorMessage, SET_TYPE_ATTRIBUTE));
223 if (knownFilesType.equals(
"NSRL")) {
224 knownFilesType = HashDbManager.HashDb.KnownFilesType.KNOWN.toString();
225 updatedSchema =
true;
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));
232 Boolean searchDuringIngestFlag = Boolean.parseBoolean(searchDuringIngest);
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));
238 Boolean sendIngestMessagesFlag = Boolean.parseBoolean(sendIngestMessages);
241 NodeList pathsNList = setEl.getElementsByTagName(PATH_ELEMENT);
242 if (pathsNList.getLength() > 0) {
243 Element pathEl = (Element) pathsNList.item(0);
246 String legacyPathNumber = pathEl.getAttribute(LEGACY_PATH_NUMBER_ATTRIBUTE);
247 if (null != legacyPathNumber && !legacyPathNumber.isEmpty()) {
248 updatedSchema =
true;
251 dbPath = pathEl.getTextContent();
252 if (dbPath.isEmpty()) {
253 throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT));
256 throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT));
258 hashDbInfoList.add(
new HashDbInfo(hashSetName, HashDbManager.HashDb.KnownFilesType.valueOf(knownFilesType),
259 searchDuringIngestFlag, sendIngestMessagesFlag, dbPath));
260 hashSetNames.add(hashSetName);
264 String backupFilePath = configFilePath +
".v1_backup";
265 String messageBoxTitle = NbBundle.getMessage(HashLookupSettings.class,
266 "HashDbManager.msgBoxTitle.confFileFmtChanged");
267 String baseMessage = NbBundle.getMessage(HashLookupSettings.class,
268 "HashDbManager.baseMessage.updatedFormatHashDbConfig");
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),
278 JOptionPane.INFORMATION_MESSAGE);
280 }
catch (IOException ex) {
281 logger.log(Level.WARNING,
"Failed to save backup of old format configuration file to " + backupFilePath, ex);
282 JOptionPane.showMessageDialog(null, baseMessage, messageBoxTitle, JOptionPane.INFORMATION_MESSAGE);
284 HashLookupSettings settings;
285 settings =
new HashLookupSettings(hashDbInfoList);
286 HashLookupSettings.writeSettings(settings);
288 return new HashLookupSettings(hashDbInfoList);
290 return new HashLookupSettings(
new ArrayList<>());
301 static boolean writeSettings(HashLookupSettings settings) {
302 try (NbObjectOutputStream out =
new NbObjectOutputStream(
new FileOutputStream(SERIALIZATION_FILE_PATH))) {
303 out.writeObject(settings);
305 }
catch (Exception ex) {
306 logger.log(Level.SEVERE,
"Could not wtite hash database settings.");
316 static final class HashDbInfo
implements Serializable {
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;
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;
348 String getHashSetName() {
357 HashDbManager.HashDb.KnownFilesType getKnownFilesType() {
358 return knownFilesType;
366 boolean getSearchDuringIngest() {
367 return searchDuringIngest;
375 boolean getSendIngestMessages() {
376 return sendIngestMessages;
394 static class HashLookupSettingsException
extends Exception {
396 private static final long serialVersionUID = 1L;
398 HashLookupSettingsException(String message) {
402 HashLookupSettingsException(String message, Throwable throwable) {
403 super(message, throwable);