Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
CaseMetadata.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.casemodule;
20 
21 import java.io.BufferedWriter;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.io.StringWriter;
26 import java.nio.file.Path;
27 import java.nio.file.Paths;
28 import java.text.DateFormat;
29 import java.text.SimpleDateFormat;
30 import java.util.Date;
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.parsers.ParserConfigurationException;
34 import javax.xml.transform.OutputKeys;
35 import javax.xml.transform.Result;
36 import javax.xml.transform.Source;
37 import javax.xml.transform.Transformer;
38 import javax.xml.transform.TransformerException;
39 import javax.xml.transform.TransformerFactory;
40 import javax.xml.transform.dom.DOMSource;
41 import javax.xml.transform.stream.StreamResult;
44 import org.w3c.dom.Document;
45 import org.w3c.dom.Element;
46 import org.w3c.dom.NodeList;
47 import org.xml.sax.SAXException;
48 
52 public final class CaseMetadata {
53 
54  private static final String FILE_EXTENSION = ".aut";
55  private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)");
56  private static final String SCHEMA_VERSION_ONE = "1.0";
57  private final static String AUTOPSY_CREATED_VERSION_ELEMENT_NAME = "AutopsyCreatedVersion"; //NON-NLS
58  private final static String CASE_DATABASE_NAME_ELEMENT_NAME = "DatabaseName"; //NON-NLS
59  private final static String TEXT_INDEX_NAME_ELEMENT = "TextIndexName"; //NON-NLS
60  private static final String CURRENT_SCHEMA_VERSION = "2.0";
61  private final static String ROOT_ELEMENT_NAME = "AutopsyCase"; //NON-NLS
62  private final static String SCHEMA_VERSION_ELEMENT_NAME = "SchemaVersion"; //NON-NLS
63  private final static String CREATED_DATE_ELEMENT_NAME = "CreatedDate"; //NON-NLS
64  private final static String MODIFIED_DATE_ELEMENT_NAME = "ModifiedDate"; //NON-NLS
65  private final static String AUTOPSY_CREATED_BY_ELEMENT_NAME = "CreatedByAutopsyVersion"; //NON-NLS
66  private final static String AUTOPSY_SAVED_BY_ELEMENT_NAME = "SavedByAutopsyVersion"; //NON-NLS
67  private final static String CASE_ELEMENT_NAME = "Case"; //NON-NLS
68  private final static String CASE_NAME_ELEMENT_NAME = "Name"; //NON-NLS
69  private final static String CASE_NUMBER_ELEMENT_NAME = "Number"; //NON-NLS
70  private final static String EXAMINER_ELEMENT_NAME = "Examiner"; //NON-NLS
71  private final static String CASE_TYPE_ELEMENT_NAME = "CaseType"; //NON-NLS
72  private final static String CASE_DATABASE_ELEMENT_NAME = "Database"; //NON-NLS
73  private final static String TEXT_INDEX_ELEMENT = "TextIndex"; //NON-NLS
74  private final Path metadataFilePath;
76  private String caseName;
77  private String caseNumber;
78  private String examiner;
79  private String caseDatabase;
80  private String textIndexName;
81  private String createdDate;
82  private String createdByVersion;
83 
89  public static String getFileExtension() {
90  return FILE_EXTENSION;
91  }
92 
110  CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDatabase, String caseTextIndexName) throws CaseMetadataException {
111  metadataFilePath = Paths.get(caseDirectory, caseName + FILE_EXTENSION);
112  this.caseType = caseType;
113  this.caseName = caseName;
114  this.caseNumber = caseNumber;
115  this.examiner = examiner;
116  this.caseDatabase = caseDatabase;
117  this.textIndexName = caseTextIndexName;
118  createdByVersion = Version.getVersion();
119  createdDate = CaseMetadata.DATE_FORMAT.format(new Date());
120  writeToFile();
121  }
122 
132  public CaseMetadata(Path metadataFilePath) throws CaseMetadataException {
133  this.metadataFilePath = metadataFilePath;
134  readFromFile();
135  }
136 
142  Path getFilePath() {
143  return metadataFilePath;
144  }
145 
151  public String getCaseDirectory() {
152  return metadataFilePath.getParent().toString();
153  }
154 
161  return caseType;
162  }
163 
169  public String getCaseName() {
170  return caseName;
171  }
172 
179  void setCaseName(String caseName) throws CaseMetadataException {
180  String oldCaseName = caseName;
181  this.caseName = caseName;
182  try {
183  writeToFile();
184  } catch (CaseMetadataException ex) {
185  this.caseName = oldCaseName;
186  throw ex;
187  }
188  }
189 
195  public String getCaseNumber() {
196  return caseNumber;
197  }
198 
204  public String getExaminer() {
205  return examiner;
206  }
207 
213  public String getCaseDatabaseName() {
215  return caseDatabase;
216  } else {
217  return Paths.get(caseDatabase).getFileName().toString();
218  }
219  }
220 
229  public String getCaseDatabasePath() throws UnsupportedOperationException {
231  return caseDatabase;
232  } else {
233  throw new UnsupportedOperationException();
234  }
235  }
236 
242  public String getTextIndexName() {
243  return textIndexName;
244  }
245 
251  String getCreatedDate() {
252  return createdDate;
253  }
254 
261  void setCreatedDate(String createdDate) throws CaseMetadataException {
262  String oldCreatedDate = createdDate;
263  this.createdDate = createdDate;
264  try {
265  writeToFile();
266  } catch (CaseMetadataException ex) {
267  this.createdDate = oldCreatedDate;
268  throw ex;
269  }
270  }
271 
277  String getCreatedByVersion() {
278  return createdByVersion;
279  }
280 
287  void setCreatedByVersion(String buildVersion) throws CaseMetadataException {
288  String oldCreatedByVersion = this.createdByVersion;
289  this.createdByVersion = buildVersion;
290  try {
291  this.writeToFile();
292  } catch (CaseMetadataException ex) {
293  this.createdByVersion = oldCreatedByVersion;
294  throw ex;
295  }
296  }
297 
304  private void writeToFile() throws CaseMetadataException {
305  try {
306  /*
307  * Create the XML DOM.
308  */
309  Document doc = XMLUtil.createDocument();
310  createXMLDOM(doc);
311  doc.normalize();
312 
313  /*
314  * Prepare the DOM for pretty printing to the metadata file.
315  */
316  Source source = new DOMSource(doc);
317  StringWriter stringWriter = new StringWriter();
318  Result streamResult = new StreamResult(stringWriter);
319  Transformer transformer = TransformerFactory.newInstance().newTransformer();
320  transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //NON-NLS
321  transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); //NON-NLS
322  transformer.transform(source, streamResult);
323 
324  /*
325  * Write the DOM to the metadata file.
326  */
327  try (BufferedWriter fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(metadataFilePath.toFile())))) {
328  fileWriter.write(stringWriter.toString());
329  fileWriter.flush();
330  }
331 
332  } catch (ParserConfigurationException | TransformerException | IOException ex) {
333  throw new CaseMetadataException(String.format("Error writing to case metadata file %s", metadataFilePath), ex);
334  }
335  }
336 
337  /*
338  * Creates an XML DOM from the case metadata.
339  */
340  private void createXMLDOM(Document doc) {
341  /*
342  * Create the root element and its children.
343  */
344  Element rootElement = doc.createElement(ROOT_ELEMENT_NAME);
345  doc.appendChild(rootElement);
346  createChildElement(doc, rootElement, SCHEMA_VERSION_ELEMENT_NAME, CURRENT_SCHEMA_VERSION);
347  createChildElement(doc, rootElement, CREATED_DATE_ELEMENT_NAME, createdDate);
348  createChildElement(doc, rootElement, MODIFIED_DATE_ELEMENT_NAME, DATE_FORMAT.format(new Date()));
349  createChildElement(doc, rootElement, AUTOPSY_CREATED_BY_ELEMENT_NAME, createdByVersion);
350  createChildElement(doc, rootElement, AUTOPSY_SAVED_BY_ELEMENT_NAME, Version.getVersion());
351  Element caseElement = doc.createElement(CASE_ELEMENT_NAME);
352  rootElement.appendChild(caseElement);
353 
354  /*
355  * Create the children of the case element.
356  */
357  createChildElement(doc, caseElement, CASE_NAME_ELEMENT_NAME, caseName);
358  createChildElement(doc, caseElement, CASE_NUMBER_ELEMENT_NAME, caseNumber);
359  createChildElement(doc, caseElement, EXAMINER_ELEMENT_NAME, examiner);
360  createChildElement(doc, caseElement, CASE_TYPE_ELEMENT_NAME, caseType.toString());
361  createChildElement(doc, caseElement, CASE_DATABASE_ELEMENT_NAME, caseDatabase);
362  createChildElement(doc, caseElement, TEXT_INDEX_ELEMENT, textIndexName);
363  }
364 
374  private void createChildElement(Document doc, Element parentElement, String elementName, String elementContent) {
375  Element element = doc.createElement(elementName);
376  element.appendChild(doc.createTextNode(elementContent));
377  parentElement.appendChild(element);
378  }
379 
386  private void readFromFile() throws CaseMetadataException {
387  try {
388  /*
389  * Parse the file into an XML DOM and get the root element.
390  */
391  DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
392  Document doc = builder.parse(this.getFilePath().toFile());
393  doc.getDocumentElement().normalize();
394  Element rootElement = doc.getDocumentElement();
395  if (!rootElement.getNodeName().equals(ROOT_ELEMENT_NAME)) {
396  throw new CaseMetadataException("Case metadata file corrupted");
397  }
398 
399  /*
400  * Get the content of the relevant children of the root element.
401  */
402  String schemaVersion = getElementTextContent(rootElement, SCHEMA_VERSION_ELEMENT_NAME, true);
403  this.createdDate = getElementTextContent(rootElement, CREATED_DATE_ELEMENT_NAME, true);
404  if (schemaVersion.equals(SCHEMA_VERSION_ONE)) {
405  this.createdByVersion = getElementTextContent(rootElement, AUTOPSY_CREATED_VERSION_ELEMENT_NAME, true);
406  } else {
407  this.createdByVersion = getElementTextContent(rootElement, AUTOPSY_CREATED_BY_ELEMENT_NAME, true);
408  }
409 
410  /*
411  * Get the content of the children of the case element.
412  */
413  NodeList caseElements = doc.getElementsByTagName(CASE_ELEMENT_NAME);
414  if (caseElements.getLength() == 0) {
415  throw new CaseMetadataException("Case metadata file corrupted");
416  }
417  Element caseElement = (Element) caseElements.item(0);
418  this.caseName = getElementTextContent(caseElement, CASE_NAME_ELEMENT_NAME, true);
419  this.caseNumber = getElementTextContent(caseElement, CASE_NUMBER_ELEMENT_NAME, false);
420  this.examiner = getElementTextContent(caseElement, EXAMINER_ELEMENT_NAME, false);
421  this.caseType = Case.CaseType.fromString(getElementTextContent(caseElement, CASE_TYPE_ELEMENT_NAME, true));
422  if (null == this.caseType) {
423  throw new CaseMetadataException("Case metadata file corrupted");
424  }
425  if (schemaVersion.equals(SCHEMA_VERSION_ONE)) {
426  this.caseDatabase = getElementTextContent(caseElement, CASE_DATABASE_NAME_ELEMENT_NAME, true);
427  this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_NAME_ELEMENT, true);
428  } else {
429  this.caseDatabase = getElementTextContent(caseElement, CASE_DATABASE_ELEMENT_NAME, true);
430  this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, true);
431  }
432 
433  /*
434  * Update the file to the current schema, if necessary.
435  */
436  if (!schemaVersion.equals(CURRENT_SCHEMA_VERSION)) {
437  writeToFile();
438  }
439 
440  } catch (ParserConfigurationException | SAXException | IOException ex) {
441  throw new CaseMetadataException(String.format("Error reading from case metadata file %s", metadataFilePath), ex);
442  }
443  }
444 
457  private String getElementTextContent(Element parentElement, String elementName, boolean contentIsRequired) throws CaseMetadataException {
458  NodeList elementsList = parentElement.getElementsByTagName(elementName);
459  if (elementsList.getLength() == 0) {
460  throw new CaseMetadataException(String.format("Missing %s element from case metadata file %s", elementName, metadataFilePath));
461  }
462  String textContent = elementsList.item(0).getTextContent();
463  if (textContent.isEmpty() && contentIsRequired) {
464  throw new CaseMetadataException(String.format("Empty %s element in case metadata file %s", elementName, metadataFilePath));
465  }
466  return textContent;
467  }
468 
473  public final static class CaseMetadataException extends Exception {
474 
475  private static final long serialVersionUID = 1L;
476 
477  private CaseMetadataException(String message) {
478  super(message);
479  }
480 
481  private CaseMetadataException(String message, Throwable cause) {
482  super(message, cause);
483  }
484  }
485 
486 }
static CaseType fromString(String typeName)
Definition: Case.java:140
void createChildElement(Document doc, Element parentElement, String elementName, String elementContent)
String getElementTextContent(Element parentElement, String elementName, boolean contentIsRequired)
static final String AUTOPSY_CREATED_VERSION_ELEMENT_NAME

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