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

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