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.Objects;
29 import java.util.logging.Level;
30 import javax.swing.JOptionPane;
31 import org.apache.commons.io.FileUtils;
32 import org.openide.util.NbBundle;
33 import org.openide.util.io.NbObjectInputStream;
34 import org.openide.util.io.NbObjectOutputStream;
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.NodeList;
50 final class HashLookupSettings
implements Serializable {
52 private static final String SERIALIZATION_FILE_NAME =
"hashLookup.settings";
53 private static final String SERIALIZATION_FILE_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + SERIALIZATION_FILE_NAME;
54 private static final String SET_ELEMENT =
"hash_set";
55 private static final String SET_NAME_ATTRIBUTE =
"name";
56 private static final String SET_TYPE_ATTRIBUTE =
"type";
57 private static final String SEARCH_DURING_INGEST_ATTRIBUTE =
"use_for_ingest";
58 private static final String SEND_INGEST_MESSAGES_ATTRIBUTE =
"show_inbox_messages";
59 private static final String PATH_ELEMENT =
"hash_set_path";
60 private static final String LEGACY_PATH_NUMBER_ATTRIBUTE =
"number";
61 private static final String CONFIG_FILE_NAME =
"hashsets.xml";
62 private static final String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CONFIG_FILE_NAME;
63 private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
65 private static final long serialVersionUID = 1L;
66 private final List<HashDbInfo> hashDbInfoList;
73 HashLookupSettings(List<HashDbInfo> hashDbInfoList) {
74 this.hashDbInfoList = hashDbInfoList;
77 static List<HashDbInfo> convertHashSetList(List<HashDbManager.HashDb> hashSets)
throws HashLookupSettingsException{
78 List<HashDbInfo> dbInfoList =
new ArrayList<>();
79 for(HashDbManager.HashDb db:hashSets){
81 dbInfoList.add(
new HashDbInfo(db));
82 }
catch (TskCoreException ex){
83 logger.log(Level.SEVERE,
"Could not load hash set settings for {0}", db.getHashSetName());
94 List<HashDbInfo> getHashDbInfo() {
95 return hashDbInfoList;
106 static HashLookupSettings readSettings() throws HashLookupSettingsException {
107 File fileSetFile =
new File(SERIALIZATION_FILE_PATH);
108 if (fileSetFile.exists()) {
109 return readSerializedSettings();
111 return readXmlSettings();
124 private static HashLookupSettings readSerializedSettings() throws HashLookupSettingsException {
126 try (NbObjectInputStream in =
new NbObjectInputStream(
new FileInputStream(SERIALIZATION_FILE_PATH))) {
127 HashLookupSettings filesSetsSettings = (HashLookupSettings) in.readObject();
128 return filesSetsSettings;
130 }
catch (IOException | ClassNotFoundException ex) {
131 throw new HashLookupSettingsException(
"Could not read hash set settings.", ex);
144 private static HashLookupSettings readXmlSettings() throws HashLookupSettingsException {
145 File xmlFile =
new File(configFilePath);
146 if (xmlFile.exists()) {
147 boolean updatedSchema =
false;
150 final Document doc = XMLUtil.loadDoc(HashDbManager.class, configFilePath);
152 throw new HashLookupSettingsException(
"Could not open xml document.");
156 Element root = doc.getDocumentElement();
158 throw new HashLookupSettingsException(
"Error loading hash sets: invalid file format.");
162 NodeList setsNList = root.getElementsByTagName(SET_ELEMENT);
163 int numSets = setsNList.getLength();
166 String attributeErrorMessage =
"Missing %s attribute";
167 String elementErrorMessage =
"Empty %s element";
168 List<String> hashSetNames =
new ArrayList<>();
169 List<HashDbInfo> hashDbInfoList =
new ArrayList<>();
170 for (
int i = 0; i < numSets; ++i) {
171 Element setEl = (Element) setsNList.item(i);
173 String hashSetName = setEl.getAttribute(SET_NAME_ATTRIBUTE);
174 if (hashSetName.isEmpty()) {
175 throw new HashLookupSettingsException(String.format(attributeErrorMessage, SET_NAME_ATTRIBUTE));
179 if (hashSetNames.contains(hashSetName)) {
181 String newHashSetName;
184 newHashSetName = hashSetName + suffix;
185 }
while (hashSetNames.contains(newHashSetName));
186 logger.log(Level.INFO,
"Duplicate hash set name " + hashSetName +
" found. Replacing with " + newHashSetName +
".");
187 if (RuntimeProperties.runningWithGUI()) {
188 JOptionPane.showMessageDialog(null,
189 NbBundle.getMessage(HashLookupSettings.class,
190 "HashDbManager.replacingDuplicateHashsetNameMsg",
191 hashSetName, newHashSetName),
192 NbBundle.getMessage(HashLookupSettings.class,
"HashDbManager.openHashDbErr"),
193 JOptionPane.ERROR_MESSAGE);
194 hashSetName = newHashSetName;
198 String knownFilesType = setEl.getAttribute(SET_TYPE_ATTRIBUTE);
199 if (knownFilesType.isEmpty()) {
200 throw new HashLookupSettingsException(String.format(attributeErrorMessage, SET_TYPE_ATTRIBUTE));
204 if (knownFilesType.equals(
"NSRL")) {
205 knownFilesType = HashDbManager.HashDb.KnownFilesType.KNOWN.toString();
206 updatedSchema =
true;
209 final String searchDuringIngest = setEl.getAttribute(SEARCH_DURING_INGEST_ATTRIBUTE);
210 if (searchDuringIngest.isEmpty()) {
211 throw new HashLookupSettingsException(String.format(attributeErrorMessage, SEND_INGEST_MESSAGES_ATTRIBUTE));
213 Boolean searchDuringIngestFlag = Boolean.parseBoolean(searchDuringIngest);
215 final String sendIngestMessages = setEl.getAttribute(SEND_INGEST_MESSAGES_ATTRIBUTE);
216 if (searchDuringIngest.isEmpty()) {
217 throw new HashLookupSettingsException(String.format(attributeErrorMessage, SEND_INGEST_MESSAGES_ATTRIBUTE));
219 Boolean sendIngestMessagesFlag = Boolean.parseBoolean(sendIngestMessages);
222 NodeList pathsNList = setEl.getElementsByTagName(PATH_ELEMENT);
223 if (pathsNList.getLength() > 0) {
224 Element pathEl = (Element) pathsNList.item(0);
227 String legacyPathNumber = pathEl.getAttribute(LEGACY_PATH_NUMBER_ATTRIBUTE);
228 if (null != legacyPathNumber && !legacyPathNumber.isEmpty()) {
229 updatedSchema =
true;
232 dbPath = pathEl.getTextContent();
233 if (dbPath.isEmpty()) {
234 throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT));
237 throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT));
239 hashDbInfoList.add(
new HashDbInfo(hashSetName, HashDbManager.HashDb.KnownFilesType.valueOf(knownFilesType),
240 searchDuringIngestFlag, sendIngestMessagesFlag, dbPath));
241 hashSetNames.add(hashSetName);
245 String backupFilePath = configFilePath +
".v1_backup";
246 String messageBoxTitle = NbBundle.getMessage(HashLookupSettings.class,
247 "HashDbManager.msgBoxTitle.confFileFmtChanged");
248 String baseMessage = NbBundle.getMessage(HashLookupSettings.class,
249 "HashDbManager.baseMessage.updatedFormatHashDbConfig");
251 FileUtils.copyFile(
new File(configFilePath),
new File(backupFilePath));
252 logger.log(Level.INFO,
"Updated the schema, backup saved at: " + backupFilePath);
253 if (RuntimeProperties.runningWithGUI()) {
254 JOptionPane.showMessageDialog(null,
255 NbBundle.getMessage(HashLookupSettings.class,
256 "HashDbManager.savedBackupOfOldConfigMsg",
257 baseMessage, backupFilePath),
259 JOptionPane.INFORMATION_MESSAGE);
261 }
catch (IOException ex) {
262 logger.log(Level.WARNING,
"Failed to save backup of old format configuration file to " + backupFilePath, ex);
263 JOptionPane.showMessageDialog(null, baseMessage, messageBoxTitle, JOptionPane.INFORMATION_MESSAGE);
265 HashLookupSettings settings;
266 settings =
new HashLookupSettings(hashDbInfoList);
267 HashLookupSettings.writeSettings(settings);
269 return new HashLookupSettings(hashDbInfoList);
271 return new HashLookupSettings(
new ArrayList<>());
282 static boolean writeSettings(HashLookupSettings settings) {
284 try (NbObjectOutputStream out =
new NbObjectOutputStream(
new FileOutputStream(SERIALIZATION_FILE_PATH))) {
285 out.writeObject(settings);
287 }
catch (Exception ex) {
288 logger.log(Level.SEVERE,
"Could not write hash set settings.");
298 static final class HashDbInfo
implements Serializable {
305 private static final long serialVersionUID = 1L;
306 private final String hashSetName;
307 private final HashDbManager.HashDb.KnownFilesType knownFilesType;
308 private boolean searchDuringIngest;
309 private final boolean sendIngestMessages;
310 private final String path;
311 private final String version;
312 private final boolean readOnly;
313 private final int referenceSetID;
314 private DatabaseType dbType;
326 HashDbInfo(String hashSetName, HashDbManager.HashDb.KnownFilesType knownFilesType,
boolean searchDuringIngest,
boolean sendIngestMessages, String path) {
327 this.hashSetName = hashSetName;
328 this.knownFilesType = knownFilesType;
329 this.searchDuringIngest = searchDuringIngest;
330 this.sendIngestMessages = sendIngestMessages;
332 this.referenceSetID = -1;
334 this.readOnly =
false;
335 this.dbType = DatabaseType.FILE;
338 HashDbInfo(String hashSetName, String version,
int referenceSetID, HashDbManager.HashDb.KnownFilesType knownFilesType,
boolean readOnly,
boolean searchDuringIngest,
boolean sendIngestMessages){
339 this.hashSetName = hashSetName;
340 this.version = version;
341 this.referenceSetID = referenceSetID;
342 this.knownFilesType = knownFilesType;
343 this.readOnly = readOnly;
344 this.searchDuringIngest = searchDuringIngest;
345 this.sendIngestMessages = sendIngestMessages;
347 dbType = DatabaseType.CENTRAL_REPOSITORY;
350 HashDbInfo(HashDbManager.HashDb db) throws TskCoreException{
351 if(db instanceof HashDbManager.SleuthkitHashSet){
352 HashDbManager.SleuthkitHashSet fileTypeDb = (HashDbManager.SleuthkitHashSet)db;
353 this.hashSetName = fileTypeDb.getHashSetName();
354 this.knownFilesType = fileTypeDb.getKnownFilesType();
355 this.searchDuringIngest = fileTypeDb.getSearchDuringIngest();
356 this.sendIngestMessages = fileTypeDb.getSendIngestMessages();
357 this.referenceSetID = -1;
359 this.readOnly =
false;
360 this.dbType = DatabaseType.FILE;
361 if (fileTypeDb.hasIndexOnly()) {
362 this.path = fileTypeDb.getIndexPath();
364 this.path = fileTypeDb.getDatabasePath();
367 HashDbManager.CentralRepoHashSet centralRepoDb = (HashDbManager.CentralRepoHashSet)db;
368 this.hashSetName = centralRepoDb.getHashSetName();
369 this.version = centralRepoDb.getVersion();
370 this.knownFilesType = centralRepoDb.getKnownFilesType();
371 this.readOnly = ! centralRepoDb.isUpdateable();
372 this.searchDuringIngest = centralRepoDb.getSearchDuringIngest();
373 this.sendIngestMessages = centralRepoDb.getSendIngestMessages();
375 this.referenceSetID = centralRepoDb.getReferenceSetID();
376 this.dbType = DatabaseType.CENTRAL_REPOSITORY;
385 String getHashSetName() {
401 boolean isReadOnly(){
410 HashDbManager.HashDb.KnownFilesType getKnownFilesType() {
411 return knownFilesType;
419 boolean getSearchDuringIngest() {
420 return searchDuringIngest;
427 void setSearchDuringIngest(
boolean searchDuringIngest) {
428 this.searchDuringIngest = searchDuringIngest;
436 boolean getSendIngestMessages() {
437 return sendIngestMessages;
449 int getReferenceSetID(){
450 return referenceSetID;
457 boolean isFileDatabaseType(){
458 return dbType == DatabaseType.FILE;
461 boolean isCentralRepoDatabaseType(){
462 return dbType == DatabaseType.CENTRAL_REPOSITORY;
465 boolean matches(HashDb hashDb){
470 if( ! this.knownFilesType.equals(hashDb.getKnownFilesType())){
474 if((this.dbType == DatabaseType.CENTRAL_REPOSITORY) && (! (hashDb instanceof CentralRepoHashSet))
475 || (this.dbType == DatabaseType.FILE) && (! (hashDb instanceof SleuthkitHashSet))){
479 if( ! this.hashSetName.equals(hashDb.getHashSetName())){
483 if(hashDb instanceof CentralRepoHashSet){
484 CentralRepoHashSet crDb = (CentralRepoHashSet) hashDb;
485 if(this.referenceSetID != crDb.getReferenceSetID()){
489 if(! version.equals(crDb.getVersion())){
498 public boolean equals(Object obj) {
503 if (getClass() != obj.getClass()) {
507 final HashDbInfo other = (HashDbInfo) obj;
509 if(! this.dbType.equals(other.dbType)){
513 if(this.dbType.equals(DatabaseType.FILE)){
515 return (this.hashSetName.equals(other.hashSetName)
516 && this.knownFilesType.equals(other.knownFilesType));
519 return (this.hashSetName.equals(other.hashSetName)
520 && (this.referenceSetID == other.referenceSetID)
521 && this.knownFilesType.equals(other.knownFilesType));
526 public int hashCode() {
528 hash = 89 * hash + Objects.hashCode(this.hashSetName);
529 hash = 89 * hash + Objects.hashCode(this.knownFilesType);
530 hash = 89 * hash + Objects.hashCode(this.dbType);
531 if(this.dbType.equals(DatabaseType.CENTRAL_REPOSITORY)){
532 hash = 89 * hash + this.referenceSetID;
545 private void readObject(java.io.ObjectInputStream stream)
546 throws IOException, ClassNotFoundException {
547 stream.defaultReadObject();
550 dbType = DatabaseType.FILE;
560 static class HashLookupSettingsException
extends Exception {
562 private static final long serialVersionUID = 1L;
564 HashLookupSettingsException(String message) {
568 HashLookupSettingsException(String message, Throwable throwable) {
569 super(message, throwable);