1 /*
 2  * Autopsy Forensic Browser
 3  *
 4  * Copyright 2013-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.contentviewers;
 20 
 21 import java.awt.Component;
 22 import java.util.List;
 23 import java.util.logging.Level;
 24 import org.apache.commons.lang3.StringUtils;
 
 25 import org.openide.nodes.Node;
 
 26 import org.openide.util.NbBundle;
 
 27 import org.openide.util.NbBundle.Messages;
 
 28 import org.openide.util.lookup.ServiceProvider;
 
 34 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
 
 36 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
 
 41 import org.
sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
 
 42 
 48 @ServiceProvider(service = DataContentViewer.class, position = 6)
 49 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
 51 
 53  
 58  initComponents();
 59  customizeComponents();
 60  }
 61 
 67  @SuppressWarnings("unchecked")
 68  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
 69   private 
void initComponents() {
 
 70 
 71  jPopupMenu1 = new javax.swing.JPopupMenu();
 72  jScrollPane2 = new javax.swing.JScrollPane();
 73  jTextPane1 = new javax.swing.JTextPane();
 74 
 75  setPreferredSize(new java.awt.Dimension(100, 52));
 76 
 77  jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
 78  jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
 79  jScrollPane2.setPreferredSize(new java.awt.Dimension(610, 52));
 80 
 81  jTextPane1.setEditable(false);
 82  jTextPane1.setPreferredSize(new java.awt.Dimension(600, 52));
 83  jScrollPane2.setViewportView(jTextPane1);
 84 
 85  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
 86  this.setLayout(layout);
 87  layout.setHorizontalGroup(
 88  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 89  .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 90  );
 91  layout.setVerticalGroup(
 92  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 93  .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 94  );
 95  }// </editor-fold>//GEN-END:initComponents
 96  // Variables declaration - do not modify//GEN-BEGIN:variables
 100  // End of variables declaration//GEN-END:variables
 101 
 103  /*
 104  * jTextPane1.setComponentPopupMenu(rightClickMenu); ActionListener
 105  * actList = new ActionListener(){ @Override public void
 106  * actionPerformed(ActionEvent e){ JMenuItem jmi = (JMenuItem)
 107  * e.getSource(); if(jmi.equals(copyMenuItem)) outputViewPane.copy();
 108  * else if(jmi.equals(selectAllMenuItem)) outputViewPane.selectAll(); }
 109  * }; copyMenuItem.addActionListener(actList);
 110  * selectAllMenuItem.addActionListener(actList);
 111  */
 112 
 114  }
 115 
 117  jTextPane1.setText("<html><body>" + str + "</body></html>"); //NON-NLS
 118  }
 119 
 121  sb.append("<table>"); //NON-NLS
 122  }
 123 
 125  sb.append("</table>"); //NON-NLS
 126  }
 127 
 128   private void addRow(StringBuilder sb, String key, String value) {
 
 129  sb.append("<tr><td valign=\"top\">"); //NON-NLS
 130  sb.append(key);
 131  sb.append("</td><td>"); //NON-NLS
 132  sb.append(value);
 133  sb.append("</td></tr>"); //NON-NLS
 134  }
 135 
 136  @Messages({
 137  "Metadata.tableRowTitle.mimeType=MIME Type",
 138  "Metadata.nodeText.truncated=(results truncated)",
 139  "Metadata.tableRowTitle.sha1=SHA1",
 140  "Metadata.tableRowTitle.sha256=SHA256",
 141  "Metadata.tableRowTitle.imageType=Type",
 142  "Metadata.tableRowTitle.sectorSize=Sector Size",
 143  "Metadata.tableRowTitle.timezone=Time Zone",
 144  "Metadata.tableRowTitle.deviceId=Device ID",
 145  "Metadata.tableRowTitle.acquisitionDetails=Acquisition Details",
 146  "Metadata.tableRowTitle.downloadSource=Downloaded From",
 147  "Metadata.nodeText.unknown=Unknown",
 148  "Metadata.nodeText.none=None"})
 149  @Override
 151  AbstractFile file = node.getLookup().lookup(AbstractFile.class);
 152  Image image = node.getLookup().lookup(Image.class);
 153  DataSource dataSource = node.getLookup().lookup(DataSource.class);
 154  if (file == null && image == null) {
 155  setText(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.nonFilePassedIn"));
 156  return;
 157  }
 158 
 159  StringBuilder sb = new StringBuilder();
 160  startTable(sb);
 161 
 162  if (file != null) {
 163  try {
 164  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getUniquePath());
 165  } catch (TskCoreException ex) {
 166  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getParentPath() + "/" + file.getName());
 167  }
 168 
 169  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.type"), file.getType().getName());
 170  addRow(sb, Bundle.Metadata_tableRowTitle_mimeType(), file.getMIMEType());
 171  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), Long.toString(file.getSize()));
 172  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.fileNameAlloc"), file.getDirFlagAsString());
 173  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.metadataAlloc"), file.getMetaFlagsAsString());
 174  addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.modified"), 
ContentUtils.
getStringTime(file.getMtime(), file));
 
 175  addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.accessed"), 
ContentUtils.
getStringTime(file.getAtime(), file));
 
 176  addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.created"), 
ContentUtils.
getStringTime(file.getCrtime(), file));
 
 177  addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.changed"), 
ContentUtils.
getStringTime(file.getCtime(), file));
 
 178 
 179 
 180  String md5 = file.getMd5Hash();
 181  if (md5 == null) {
 182  md5 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
 183  }
 184  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.md5"), md5);
 185  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.hashLookupResults"), file.getKnown().toString());
 186  addAcquisitionDetails(sb, dataSource);
 187  
 188  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.internalid"), Long.toString(file.getId()));
 189  if (file.getType().compareTo(TSK_DB_FILES_TYPE_ENUM.LOCAL) == 0) {
 190  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), file.getLocalAbsPath());
 191  }
 192  
 193  try {
 194  List<BlackboardArtifact> associatedObjectArtifacts = file.getArtifacts(ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
 195  if (!associatedObjectArtifacts.isEmpty()) {
 196  BlackboardArtifact artifact = associatedObjectArtifacts.get(0);
 197  BlackboardAttribute associatedArtifactAttribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
 198  if (associatedArtifactAttribute != null) {
 199  long artifactId = associatedArtifactAttribute.getValueLong();
 200  BlackboardArtifact associatedArtifact = artifact.getSleuthkitCase().getBlackboardArtifact(artifactId);
 201  addDownloadSourceRow(sb, associatedArtifact);
 202  }
 203  }
 204  } catch (TskCoreException ex) {
 205  sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
 206  }
 207  
 208  endTable(sb);
 209 
 210  /*
 211  * If we have a file system file, grab the more detailed metadata text
 212  * too
 213  */
 214  try {
 215  if (file instanceof FsContent) {
 216  FsContent fsFile = (FsContent) file;
 217 
 218  sb.append("<hr /><pre>\n"); //NON-NLS
 219  sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.text"));
 220  sb.append(" <br /><br />"); // NON-NLS
 221  for (String str : fsFile.getMetaDataText()) {
 222  sb.append(str).append("<br />"); //NON-NLS
 223 
 224  /* 
 225  * Very long results can cause the UI to hang before displaying,
 226  * so truncate the results if necessary.
 227  */
 228  if(sb.length() > 50000){
 229  sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.truncated"));
 230  break;
 231  }
 232  }
 233  sb.append("</pre>\n"); //NON-NLS
 234  }
 235  } catch (TskCoreException ex) {
 236  sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
 237  }
 238  } else {
 239  try {
 240  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), image.getUniquePath());
 241  } catch (TskCoreException ex) {
 242  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), image.getName());
 243  }
 244  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.imageType"), image.getType().getName()); 
 245  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), Long.toString(image.getSize()));
 246 
 247  try {
 248  String md5 = image.getMd5();
 249  if (md5 == null || md5.isEmpty()) {
 250  md5 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
 251  }
 252  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.md5"), md5);
 253 
 254  String sha1 = image.getSha1();
 255  if (sha1 == null || sha1.isEmpty()) {
 256  sha1 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
 257  }
 258  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.sha1"), sha1);
 259 
 260  String sha256 = image.getSha256();
 261  if (sha256 == null || sha256.isEmpty()) {
 262  sha256 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
 263  }
 264  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.sha256"), sha256);
 265  } catch (TskCoreException ex) {
 266  sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
 267  }
 268  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.sectorSize"), Long.toString(image.getSsize()));
 269  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.timezone"), image.getTimeZone());
 270  addAcquisitionDetails(sb, dataSource);
 271  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.deviceId"), image.getDeviceId());
 272  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.internalid"), Long.toString(image.getId()));
 273 
 274  // Add all the data source paths to the "Local Path" value cell.
 275  String[] imagePaths = image.getPaths();
 276  if (imagePaths.length > 0) {
 277  StringBuilder pathValues = new StringBuilder("<div>");
 278  pathValues.append(imagePaths[0]);
 279  pathValues.append("</div>");
 280  for (int i=1; i < imagePaths.length; i++) {
 281  pathValues.append("<div>");
 282  pathValues.append(imagePaths[i]);
 283  pathValues.append("</div>");
 284  }
 285  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), pathValues.toString());
 286  } else {
 287  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), 
 288  NbBundle.getMessage(this.getClass(), "Metadata.nodeText.none"));
 289  }
 290  }
 291  
 292  setText(sb.toString());
 293  jTextPane1.setCaretPosition(0);
 294  this.setCursor(null);
 295  }
 296  
 306   private void addDownloadSourceRow(StringBuilder sb, BlackboardArtifact associatedArtifact ) 
throws TskCoreException {
 
 307  if (associatedArtifact != null && 
 308  ((associatedArtifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID()) || 
 309  (associatedArtifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID())) ) {
 310  BlackboardAttribute urlAttr = associatedArtifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL));
 311  if (urlAttr != null) {
 312  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.downloadSource"), urlAttr.getValueString());
 313  }
 314  }
 315  }
 316  
 324  if (dataSource != null) {
 325  try {
 326  String details = dataSource.getAcquisitionDetails();
 327  if (StringUtils.isEmpty(details)) {
 328  details = Bundle.Metadata_nodeText_unknown();
 329  }
 330  details = details.replaceAll("\n", "<br>");
 331  addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.acquisitionDetails"), details);
 332  } catch (TskCoreException ex) {
 333  LOGGER.log(Level.SEVERE, "Error reading acquisition details from case database", ex); //NON-NLS
 334  }
 335  }
 336  }
 337 
 338  @Override
 340  return NbBundle.getMessage(this.getClass(), "Metadata.title");
 341  }
 342 
 343  @Override
 345  return NbBundle.getMessage(this.getClass(), "Metadata.toolTip");
 346  }
 347 
 348  @Override
 351  }
 352 
 353  @Override
 355  return this;
 356  }
 357 
 358  @Override
 360  setText("");
 361  }
 362 
 363  @Override
 365  Image image = node.getLookup().lookup(Image.class);
 366  AbstractFile file = node.getLookup().lookup(AbstractFile.class);
 367  return (file != null) || (image != null);
 368  }
 369 
 370  @Override
 372  return 1;
 373  }
 374 }
void endTable(StringBuilder sb)
static String getStringTime(long epochSeconds, TimeZone tzone)
void addRow(StringBuilder sb, String key, String value)
void addAcquisitionDetails(StringBuilder sb, DataSource dataSource)
javax.swing.JTextPane jTextPane1
javax.swing.JPopupMenu jPopupMenu1
void customizeComponents()
static void configureTextPaneAsHtml(JTextPane pane)
boolean isSupported(Node node)
void addDownloadSourceRow(StringBuilder sb, BlackboardArtifact associatedArtifact)
DataContentViewer createInstance()
int isPreferred(Node node)
javax.swing.JScrollPane jScrollPane2
synchronized static Logger getLogger(String name)
void startTable(StringBuilder sb)