/* * Autopsy Forensic Browser * * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sleuthkit.autopsy.modules.fileextmismatch; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; import org.openide.util.io.NbObjectInputStream; import org.openide.util.io.NbObjectOutputStream; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * Serialization settings for file extension mismatch. Contains static methods * for reading and writing settings, and instances of this class are what is * written to the serialized file. */ class FileExtMismatchSettings implements Serializable { private static final long serialVersionUID = 1L; private HashMap<String, Set<String>> mimeTypeToExtsMap; private static final Logger logger = Logger.getLogger(FileExtMismatchSettings.class.getName()); private static final String SIG_EL = "signature"; //NON-NLS private static final String EXT_EL = "ext"; //NON-NLS private static final String SIG_MIMETYPE_ATTR = "mimetype"; //NON-NLS private static final String DEFAULT_CONFIG_FILE_NAME = "mismatch_config.xml"; //NON-NLS private static final String FILTER_CONFIG_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + DEFAULT_CONFIG_FILE_NAME; private static final String DEFAULT_SERIALIZED_FILE_NAME = "mismatch_config.settings"; private static final String DEFAULT_SERIALIZED_FILE_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + DEFAULT_SERIALIZED_FILE_NAME; static { try { PlatformUtil.extractResourceToUserConfigDir(FileExtMismatchSettings.class, DEFAULT_CONFIG_FILE_NAME, false); } catch (IOException ex) { logger.log(Level.SEVERE, "Error copying default mismatch configuration to user dir ", ex); //NON-NLS } } /** * Makes a settings object based on given mime type map * * @param mimeTypeToExtsMap */ FileExtMismatchSettings(HashMap<String, Set<String>> mimeTypeToExtsMap) { this.mimeTypeToExtsMap = mimeTypeToExtsMap; } /** * @return the mime type to extension map */ HashMap<String, Set<String>> getMimeTypeToExtsMap() { return mimeTypeToExtsMap; } /** * Sets the signature to extension map for this settings. */ void setMimeTypeToExtsMap(HashMap<String, Set<String>> mimeTypeToExtsMap) { this.mimeTypeToExtsMap = mimeTypeToExtsMap; } /** * Reads the file extension mismatch settings. * * @return Loaded settings (empty if there are no settings to load). */ static synchronized FileExtMismatchSettings readSettings() throws FileExtMismatchSettingsException { File serializedFile = new File(DEFAULT_SERIALIZED_FILE_PATH); //Tries reading the serialized file first, as this is the prioritized settings. if (serializedFile.exists()) { return readSerializedSettings(); } return readXmlSettings(); } private static FileExtMismatchSettings readSerializedSettings() throws FileExtMismatchSettingsException { File serializedFile = new File(DEFAULT_SERIALIZED_FILE_PATH); try { try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(serializedFile))) { FileExtMismatchSettings fileExtMismatchSettings = (FileExtMismatchSettings) in.readObject(); return fileExtMismatchSettings; } } catch (IOException | ClassNotFoundException ex) { throw new FileExtMismatchSettingsException("Couldn't read serialized settings.", ex); } } private static FileExtMismatchSettings readXmlSettings() throws FileExtMismatchSettingsException { HashMap<String, Set<String>> sigTypeToExtMap = new HashMap<>(); //Next tries to read the xml file if the serialized file did not exist File xmlFile = new File(FILTER_CONFIG_FILE); if (xmlFile.exists()) { try { final Document doc = XMLUtil.loadDoc(FileExtMismatchSettings.class, FILTER_CONFIG_FILE); if (doc == null) { throw new FileExtMismatchSettingsException("Error loading config file: invalid file format (could not load doc)."); } Element root = doc.getDocumentElement(); if (root == null) { throw new FileExtMismatchSettingsException("Error loading config file: invalid file format (bad root)."); //NON-NLS } NodeList sigNList = root.getElementsByTagName(SIG_EL); final int numSigs = sigNList.getLength(); if (numSigs == 0) { throw new FileExtMismatchSettingsException("Error loading config file: invalid file format (no signature)."); //NON-NLS } for (int sigIndex = 0; sigIndex < numSigs; ++sigIndex) { Element sigEl = (Element) sigNList.item(sigIndex); final String mimetype = sigEl.getAttribute(SIG_MIMETYPE_ATTR); NodeList extNList = sigEl.getElementsByTagName(EXT_EL); final int numExts = extNList.getLength(); if (numExts != 0) { Set<String> extStrings = new HashSet<>(); for (int extIndex = 0; extIndex < numExts; ++extIndex) { Element extEl = (Element) extNList.item(extIndex); extStrings.add(extEl.getTextContent()); } sigTypeToExtMap.put(mimetype, extStrings); } else { sigTypeToExtMap.put(mimetype, null); //ok to have an empty type (the ingest module will not use it) } } } catch (Exception e) { throw new FileExtMismatchSettingsException("Error loading config file.", e); //NON-NLS } } return new FileExtMismatchSettings(sigTypeToExtMap); } /** * Save settings to disk. * * @param settings The settings to save to disk * * @return Loaded hash map or null on error or null if data does not exist */ static synchronized void writeSettings(FileExtMismatchSettings settings) throws FileExtMismatchSettingsException { try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(DEFAULT_SERIALIZED_FILE_PATH))) { out.writeObject(settings); } catch (IOException ex) { throw new FileExtMismatchSettingsException(String.format("Failed to write settings to %s", DEFAULT_SERIALIZED_FILE_PATH), ex); } } /** * Used to translate more implementation-details-specific exceptions (which * are logged by this class) into more generic exceptions for propagation to * clients of the user-defined file types manager. */ static class FileExtMismatchSettingsException extends Exception { private static final long serialVersionUID = 1L; FileExtMismatchSettingsException(String message) { super(message); } FileExtMismatchSettingsException(String message, Throwable throwable) { super(message, throwable); } } }