Autopsy  4.5.0
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.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;
41 import org.sleuthkit.datamodel.TskCoreException;
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.NodeList;
46 
50 final class HashLookupSettings implements Serializable {
51 
52  private static final String SERIALIZATION_FILE_NAME = "hashLookup.settings"; //NON-NLS
53  private static final String SERIALIZATION_FILE_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + SERIALIZATION_FILE_NAME; //NON-NLS
54  private static final String SET_ELEMENT = "hash_set"; //NON-NLS
55  private static final String SET_NAME_ATTRIBUTE = "name"; //NON-NLS
56  private static final String SET_TYPE_ATTRIBUTE = "type"; //NON-NLS
57  private static final String SEARCH_DURING_INGEST_ATTRIBUTE = "use_for_ingest"; //NON-NLS
58  private static final String SEND_INGEST_MESSAGES_ATTRIBUTE = "show_inbox_messages"; //NON-NLS
59  private static final String PATH_ELEMENT = "hash_set_path"; //NON-NLS
60  private static final String LEGACY_PATH_NUMBER_ATTRIBUTE = "number"; //NON-NLS
61  private static final String CONFIG_FILE_NAME = "hashsets.xml"; //NON-NLS
62  private static final String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CONFIG_FILE_NAME;
63  private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
64 
65  private static final long serialVersionUID = 1L;
66  private final List<HashDbInfo> hashDbInfoList;
67 
73  HashLookupSettings(List<HashDbInfo> hashDbInfoList) {
74  this.hashDbInfoList = hashDbInfoList;
75  }
76 
77  static List<HashDbInfo> convertHashSetList(List<HashDbManager.HashDb> hashSets) throws HashLookupSettingsException{
78  List<HashDbInfo> dbInfoList = new ArrayList<>();
79  for(HashDbManager.HashDb db:hashSets){
80  try{
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());
84  }
85  }
86  return dbInfoList;
87  }
88 
94  List<HashDbInfo> getHashDbInfo() {
95  return hashDbInfoList;
96  }
97 
106  static HashLookupSettings readSettings() throws HashLookupSettingsException {
107  File fileSetFile = new File(SERIALIZATION_FILE_PATH);
108  if (fileSetFile.exists()) {
109  return readSerializedSettings();
110  }
111  return readXmlSettings();
112 
113  }
114 
124  private static HashLookupSettings readSerializedSettings() throws HashLookupSettingsException {
125  try {
126  try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(SERIALIZATION_FILE_PATH))) {
127  HashLookupSettings filesSetsSettings = (HashLookupSettings) in.readObject();
128  return filesSetsSettings;
129  }
130  } catch (IOException | ClassNotFoundException ex) {
131  throw new HashLookupSettingsException("Could not read hash set settings.", ex);
132  }
133  }
134 
144  private static HashLookupSettings readXmlSettings() throws HashLookupSettingsException {
145  File xmlFile = new File(configFilePath);
146  if (xmlFile.exists()) {
147  boolean updatedSchema = false;
148 
149  // Open the XML document that implements the configuration file.
150  final Document doc = XMLUtil.loadDoc(HashDbManager.class, configFilePath);
151  if (doc == null) {
152  throw new HashLookupSettingsException("Could not open xml document.");
153  }
154 
155  // Get the root element.
156  Element root = doc.getDocumentElement();
157  if (root == null) {
158  throw new HashLookupSettingsException("Error loading hash sets: invalid file format.");
159  }
160 
161  // Get the hash set elements.
162  NodeList setsNList = root.getElementsByTagName(SET_ELEMENT);
163  int numSets = setsNList.getLength();
164 
165  // Create HashDbInfo objects for each hash set element. Throws on malformed xml.
166  String attributeErrorMessage = "Missing %s attribute"; //NON-NLS
167  String elementErrorMessage = "Empty %s element"; //NON-NLS
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);
172 
173  String hashSetName = setEl.getAttribute(SET_NAME_ATTRIBUTE);
174  if (hashSetName.isEmpty()) {
175  throw new HashLookupSettingsException(String.format(attributeErrorMessage, SET_NAME_ATTRIBUTE));
176  }
177 
178  // Handle configurations saved before duplicate hash set names were not permitted.
179  if (hashSetNames.contains(hashSetName)) {
180  int suffix = 0;
181  String newHashSetName;
182  do {
183  ++suffix;
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;
195  }
196  }
197 
198  String knownFilesType = setEl.getAttribute(SET_TYPE_ATTRIBUTE);
199  if (knownFilesType.isEmpty()) {
200  throw new HashLookupSettingsException(String.format(attributeErrorMessage, SET_TYPE_ATTRIBUTE));
201  }
202 
203  // Handle legacy known files types.
204  if (knownFilesType.equals("NSRL")) { //NON-NLS
205  knownFilesType = HashDbManager.HashDb.KnownFilesType.KNOWN.toString();
206  updatedSchema = true;
207  }
208 
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));
212  }
213  Boolean searchDuringIngestFlag = Boolean.parseBoolean(searchDuringIngest);
214 
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));
218  }
219  Boolean sendIngestMessagesFlag = Boolean.parseBoolean(sendIngestMessages);
220 
221  String dbPath;
222  NodeList pathsNList = setEl.getElementsByTagName(PATH_ELEMENT);
223  if (pathsNList.getLength() > 0) {
224  Element pathEl = (Element) pathsNList.item(0); // Shouldn't be more than one.
225 
226  // Check for legacy path number attribute.
227  String legacyPathNumber = pathEl.getAttribute(LEGACY_PATH_NUMBER_ATTRIBUTE);
228  if (null != legacyPathNumber && !legacyPathNumber.isEmpty()) {
229  updatedSchema = true;
230  }
231 
232  dbPath = pathEl.getTextContent();
233  if (dbPath.isEmpty()) {
234  throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT));
235  }
236  } else {
237  throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT));
238  }
239  hashDbInfoList.add(new HashDbInfo(hashSetName, HashDbManager.HashDb.KnownFilesType.valueOf(knownFilesType),
240  searchDuringIngestFlag, sendIngestMessagesFlag, dbPath));
241  hashSetNames.add(hashSetName);
242  }
243 
244  if (updatedSchema) {
245  String backupFilePath = configFilePath + ".v1_backup"; //NON-NLS
246  String messageBoxTitle = NbBundle.getMessage(HashLookupSettings.class,
247  "HashDbManager.msgBoxTitle.confFileFmtChanged");
248  String baseMessage = NbBundle.getMessage(HashLookupSettings.class,
249  "HashDbManager.baseMessage.updatedFormatHashDbConfig");
250  try {
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),
258  messageBoxTitle,
259  JOptionPane.INFORMATION_MESSAGE);
260  }
261  } catch (IOException ex) {
262  logger.log(Level.WARNING, "Failed to save backup of old format configuration file to " + backupFilePath, ex); //NON-NLS
263  JOptionPane.showMessageDialog(null, baseMessage, messageBoxTitle, JOptionPane.INFORMATION_MESSAGE);
264  }
265  HashLookupSettings settings;
266  settings = new HashLookupSettings(hashDbInfoList);
267  HashLookupSettings.writeSettings(settings);
268  }
269  return new HashLookupSettings(hashDbInfoList);
270  } else {
271  return new HashLookupSettings(new ArrayList<>());
272  }
273  }
274 
282  static boolean writeSettings(HashLookupSettings settings) {
283 
284  try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(SERIALIZATION_FILE_PATH))) {
285  out.writeObject(settings);
286  return true;
287  } catch (Exception ex) {
288  logger.log(Level.SEVERE, "Could not write hash set settings.");
289  return false;
290  }
291  }
292 
298  static final class HashDbInfo implements Serializable {
299 
300  enum DatabaseType{
301  FILE,
302  CENTRAL_REPOSITORY
303  };
304 
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;
315 
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;
331  this.path = path;
332  this.referenceSetID = -1;
333  this.version = "";
334  this.readOnly = false;
335  this.dbType = DatabaseType.FILE;
336  }
337 
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;
346  this.path = "";
347  dbType = DatabaseType.CENTRAL_REPOSITORY;
348  }
349 
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;
358  this.version = "";
359  this.readOnly = false;
360  this.dbType = DatabaseType.FILE;
361  if (fileTypeDb.hasIndexOnly()) {
362  this.path = fileTypeDb.getIndexPath();
363  } else {
364  this.path = fileTypeDb.getDatabasePath();
365  }
366  } else {
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();
374  this.path = "";
375  this.referenceSetID = centralRepoDb.getReferenceSetID();
376  this.dbType = DatabaseType.CENTRAL_REPOSITORY;
377  }
378  }
379 
385  String getHashSetName() {
386  return hashSetName;
387  }
388 
393  String getVersion(){
394  return version;
395  }
396 
401  boolean isReadOnly(){
402  return readOnly;
403  }
404 
410  HashDbManager.HashDb.KnownFilesType getKnownFilesType() {
411  return knownFilesType;
412  }
413 
419  boolean getSearchDuringIngest() {
420  return searchDuringIngest;
421  }
422 
427  void setSearchDuringIngest(boolean searchDuringIngest) {
428  this.searchDuringIngest = searchDuringIngest;
429  }
430 
436  boolean getSendIngestMessages() {
437  return sendIngestMessages;
438  }
439 
445  String getPath() {
446  return path;
447  }
448 
449  int getReferenceSetID(){
450  return referenceSetID;
451  }
452 
457  boolean isFileDatabaseType(){
458  return dbType == DatabaseType.FILE;
459  }
460 
461  boolean isCentralRepoDatabaseType(){
462  return dbType == DatabaseType.CENTRAL_REPOSITORY;
463  }
464 
465  boolean matches(HashDb hashDb){
466  if(hashDb == null){
467  return false;
468  }
469 
470  if( ! this.knownFilesType.equals(hashDb.getKnownFilesType())){
471  return false;
472  }
473 
474  if((this.dbType == DatabaseType.CENTRAL_REPOSITORY) && (! (hashDb instanceof CentralRepoHashSet))
475  || (this.dbType == DatabaseType.FILE) && (! (hashDb instanceof SleuthkitHashSet))){
476  return false;
477  }
478 
479  if( ! this.hashSetName.equals(hashDb.getHashSetName())){
480  return false;
481  }
482 
483  if(hashDb instanceof CentralRepoHashSet){
484  CentralRepoHashSet crDb = (CentralRepoHashSet) hashDb;
485  if(this.referenceSetID != crDb.getReferenceSetID()){
486  return false;
487  }
488 
489  if(! version.equals(crDb.getVersion())){
490  return false;
491  }
492  }
493 
494  return true;
495  }
496 
497  @Override
498  public boolean equals(Object obj) {
499  if (obj == null) {
500  return false;
501  }
502 
503  if (getClass() != obj.getClass()) {
504  return false;
505  }
506 
507  final HashDbInfo other = (HashDbInfo) obj;
508 
509  if(! this.dbType.equals(other.dbType)){
510  return false;
511  }
512 
513  if(this.dbType.equals(DatabaseType.FILE)){
514  // For files, we expect the name and known type to match
515  return (this.hashSetName.equals(other.hashSetName)
516  && this.knownFilesType.equals(other.knownFilesType));
517  } else {
518  // For central repo, the name, index, and known files type should match
519  return (this.hashSetName.equals(other.hashSetName)
520  && (this.referenceSetID == other.referenceSetID)
521  && this.knownFilesType.equals(other.knownFilesType));
522  }
523  }
524 
525  @Override
526  public int hashCode() {
527  int hash = 5;
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;
533  }
534 
535  return hash;
536  }
537 
545  private void readObject(java.io.ObjectInputStream stream)
546  throws IOException, ClassNotFoundException {
547  stream.defaultReadObject();
548 
549  if(dbType == null){
550  dbType = DatabaseType.FILE;
551  }
552  }
553  }
554 
560  static class HashLookupSettingsException extends Exception {
561 
562  private static final long serialVersionUID = 1L;
563 
564  HashLookupSettingsException(String message) {
565  super(message);
566  }
567 
568  HashLookupSettingsException(String message, Throwable throwable) {
569  super(message, throwable);
570  }
571  }
572 }

Copyright © 2012-2016 Basis Technology. Generated on: Tue Feb 20 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.