19 package org.sleuthkit.autopsy.contentviewers;
 
   21 import java.awt.Component;
 
   22 import java.awt.Cursor;
 
   23 import java.text.MessageFormat;
 
   24 import java.util.Arrays;
 
   25 import java.util.Collections;
 
   26 import java.util.List;
 
   27 import java.util.concurrent.ExecutionException;
 
   28 import java.util.logging.Level;
 
   29 import java.util.stream.Stream;
 
   30 import javax.swing.SwingWorker;
 
   31 import org.apache.commons.lang3.StringUtils;
 
   32 import org.openide.nodes.Node;
 
   33 import org.openide.util.NbBundle;
 
   34 import org.openide.util.NbBundle.Messages;
 
   35 import org.openide.util.lookup.ServiceProvider;
 
   44 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
 
   46 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
 
   52 import org.
sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
 
   59 @ServiceProvider(service = DataContentViewer.class, position = 4)
 
   60 @SuppressWarnings(
"PMD.SingularField") 
 
   72         customizeComponents();
 
   81     @SuppressWarnings(
"unchecked")
 
   83     private 
void initComponents() {
 
   85         jPopupMenu1 = 
new javax.swing.JPopupMenu();
 
   86         jScrollPane2 = 
new javax.swing.JScrollPane();
 
   87         jTextPane1 = 
new javax.swing.JTextPane();
 
   89         setPreferredSize(
new java.awt.Dimension(100, 52));
 
   91         jScrollPane2.setPreferredSize(
new java.awt.Dimension(610, 52));
 
   93         jTextPane1.setEditable(
false);
 
   94         jTextPane1.setPreferredSize(
new java.awt.Dimension(600, 52));
 
   95         jScrollPane2.setViewportView(jTextPane1);
 
   97         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
   98         this.setLayout(layout);
 
   99         layout.setHorizontalGroup(
 
  100             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  101             .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  103         layout.setVerticalGroup(
 
  104             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  105             .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  129         jTextPane1.setText(
"<html><head></head><body>" + str + 
"</body></html>"); 
 
  132     private void addHeader(StringBuilder sb, String header, 
boolean spaced) {
 
  133         sb.append(MessageFormat.format(
"<div class=\"{0}\"><h1 class=\"{1}\">{2}</h1></div>",
 
  140         sb.append(MessageFormat.format(
"<table class=\"{0}\" valign=\"top\" align=\"left\"><tbody>",
 
  145         sb.append(
"</tbody></table>"); 
 
  148     private void addRow(StringBuilder sb, String key, String value) {
 
  149         sb.append(MessageFormat.format(
"<tr><td class=\"{0}\"><span class=\"{1}\">{2}:</span></td><td class=\"{3}\">{4}</td></tr>",
 
  159         sb.append(MessageFormat.format(
"<tr><td class=\"{0}\"><span class=\"{1}\">{2}</span></td></tr>",
 
  167         String[] safeValues = values == null || values.length < 1 ? 
new String[]{
""} : values;
 
  169         addRow(sb, key, safeValues[0]);
 
  170         Stream.of(safeValues)
 
  172                 .filter(line -> line != null)
 
  177         "Metadata.headerTitle=Metadata",
 
  178         "Metadata.tableRowTitle.mimeType=MIME Type",
 
  179         "Metadata.nodeText.truncated=(results truncated)",
 
  180         "Metadata.tableRowTitle.sha1=SHA1",
 
  181         "Metadata.tableRowTitle.sha256=SHA-256",
 
  182         "Metadata.tableRowTitle.imageType=Type",
 
  183         "Metadata.tableRowTitle.sectorSize=Sector Size",
 
  184         "Metadata.tableRowTitle.timezone=Time Zone",
 
  185         "Metadata.tableRowTitle.deviceId=Device ID",
 
  186         "Metadata.tableRowTitle.acquisitionDetails=Acquisition Details",
 
  187         "Metadata.tableRowTitle.downloadSource=Downloaded From",
 
  188         "Metadata.nodeText.unknown=Unknown",
 
  189         "Metadata.nodeText.none=None",
 
  190         "Metadata.nodeText.loading=Metadata loading..."})
 
  194         if (worker != null) {
 
  200             setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  201             setText(Bundle.Metadata_nodeText_loading());
 
  206                         if (!isCancelled()) {
 
  208                             jTextPane1.setCaretPosition(0);
 
  210                     } 
catch (InterruptedException | ExecutionException ex) {
 
  211                         LOGGER.log(Level.SEVERE, 
"Failed to get metaData for node " + node.getName(), ex);
 
  214                     setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
 
  233     private void addDownloadSourceRow(StringBuilder sb, BlackboardArtifact associatedArtifact) 
throws TskCoreException {
 
  234         if (associatedArtifact != null
 
  235                 && ((associatedArtifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID())
 
  236                 || (associatedArtifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID()))) {
 
  237             BlackboardAttribute urlAttr = associatedArtifact.getAttribute(
new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL));
 
  238             if (urlAttr != null) {
 
  239                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.downloadSource"), urlAttr.getValueString());
 
  251         if (dataSource != null) {
 
  253                 String details = dataSource.getAcquisitionDetails();
 
  254                 if (StringUtils.isEmpty(details)) {
 
  255                     details = Bundle.Metadata_nodeText_unknown();
 
  257                 String[] lines = (details != null) ? details.split(
"\n") : 
new String[]{
""};
 
  258                 addRowWithMultipleValues(sb,
 
  259                         NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.acquisitionDetails"),
 
  262             } 
catch (TskCoreException ex) {
 
  263                 LOGGER.log(Level.SEVERE, 
"Error reading acquisition details from case database", ex); 
 
  270         return getTitle(null);
 
  274         "Metadata_dataArtifactTitle=Source File Metadata" 
  278         if (node != null && !node.getLookup().lookupAll(DataArtifact.class).isEmpty()) {
 
  279             return Bundle.Metadata_dataArtifactTitle();
 
  281             return NbBundle.getMessage(this.getClass(), 
"Metadata.title");
 
  287         return NbBundle.getMessage(this.getClass(), 
"Metadata.toolTip");
 
  307         Image image = node.getLookup().lookup(Image.class);
 
  308         AbstractFile file = node.getLookup().lookup(AbstractFile.class);
 
  309         return (file != null) || (image != null);
 
  328         @Messages(
"MetadataWorker.doInBackground.noDataMsg=No Data")
 
  331             AbstractFile file = node.getLookup().lookup(AbstractFile.class);
 
  332             Image image = node.getLookup().lookup(Image.class);
 
  333             DataSource dataSource = node.getLookup().lookup(DataSource.class);
 
  334             if (file == null && image == null) {
 
  335                 return NbBundle.getMessage(this.getClass(), 
"Metadata.nodeText.nonFilePassedIn");
 
  338             StringBuilder sb = 
new StringBuilder();
 
  339             addHeader(sb, Bundle.Metadata_headerTitle(), 
false);
 
  344                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.name"), file.getUniquePath());
 
  345                 } 
catch (TskCoreException ex) {
 
  346                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.name"), file.getParentPath() + 
"/" + file.getName());
 
  349                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.type"), file.getType().getName());
 
  350                 addRow(sb, Bundle.Metadata_tableRowTitle_mimeType(), file.getMIMEType());
 
  351                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.size"), Long.toString(file.getSize()));
 
  352                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.fileNameAlloc"), file.getDirFlagAsString());
 
  353                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.metadataAlloc"), file.getMetaFlagsAsString());
 
  359                 String md5 = file.getMd5Hash();
 
  361                     md5 = NbBundle.getMessage(this.getClass(), 
"Metadata.tableRowContent.md5notCalc");
 
  363                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.md5"), md5);
 
  364                 String sha256 = file.getSha256Hash();
 
  365                 if (sha256 == null) {
 
  366                     sha256 = NbBundle.getMessage(this.getClass(), 
"Metadata.tableRowContent.md5notCalc");
 
  368                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.sha256"), sha256);
 
  369                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.hashLookupResults"), file.getKnown().toString());
 
  370                 addAcquisitionDetails(sb, dataSource);
 
  372                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.internalid"), Long.toString(file.getId()));
 
  373                 if (file.getType().compareTo(TSK_DB_FILES_TYPE_ENUM.LOCAL) == 0) {
 
  374                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.localPath"), file.getLocalAbsPath());
 
  378                     List<BlackboardArtifact> associatedObjectArtifacts = file.getArtifacts(ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
 
  379                     if (!associatedObjectArtifacts.isEmpty()) {
 
  380                         BlackboardArtifact artifact = associatedObjectArtifacts.get(0);
 
  381                         BlackboardAttribute associatedArtifactAttribute = artifact.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
 
  382                         if (associatedArtifactAttribute != null) {
 
  383                             long artifactId = associatedArtifactAttribute.getValueLong();
 
  384                             BlackboardArtifact associatedArtifact = artifact.getSleuthkitCase().getBlackboardArtifact(artifactId);
 
  385                             addDownloadSourceRow(sb, associatedArtifact);
 
  388                 } 
catch (TskCoreException ex) {
 
  389                     sb.append(NbBundle.getMessage(
this.getClass(), 
"Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
 
  398                 if (file instanceof FsContent) {
 
  399                     FsContent fsFile = (FsContent) file;
 
  401                     addHeader(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.nodeText.text"), 
true);
 
  403                     List<String> istatStrings = Collections.emptyList();
 
  405                         istatStrings = fsFile.getMetaDataText();
 
  406                     } 
catch (TskCoreException ex) {
 
  407                         istatStrings = Arrays.asList(NbBundle.getMessage(
this.getClass(), 
"Metadata.nodeText.exceptionNotice.text") + ex.getLocalizedMessage());
 
  410                     if (istatStrings.isEmpty() || (istatStrings.size() == 1 && StringUtils.isEmpty(istatStrings.get(0)))) {
 
  411                         sb.append(MessageFormat.format(
"<div class=\"{0}\"><p class=\"{1}\">{2}</p><div>",
 
  414                                 Bundle.MetadataWorker_doInBackground_noDataMsg()));
 
  418                         for (String str : istatStrings) {
 
  419                             addMonospacedRow(sb, str);
 
  425                             if (sb.length() > 50000) {
 
  426                                 addMonospacedRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.nodeText.truncated"));
 
  437                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.name"), image.getUniquePath());
 
  438                 } 
catch (TskCoreException ex) {
 
  439                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.name"), image.getName());
 
  441                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.imageType"), image.getType().getName());
 
  442                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.size"), Long.toString(image.getSize()));
 
  445                     String md5 = image.getMd5();
 
  446                     if (md5 == null || md5.isEmpty()) {
 
  447                         md5 = NbBundle.getMessage(this.getClass(), 
"Metadata.tableRowContent.md5notCalc");
 
  449                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.md5"), md5);
 
  451                     String sha1 = image.getSha1();
 
  452                     if (sha1 == null || sha1.isEmpty()) {
 
  453                         sha1 = NbBundle.getMessage(this.getClass(), 
"Metadata.tableRowContent.md5notCalc");
 
  455                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.sha1"), sha1);
 
  457                     String sha256 = image.getSha256();
 
  458                     if (sha256 == null || sha256.isEmpty()) {
 
  459                         sha256 = NbBundle.getMessage(this.getClass(), 
"Metadata.tableRowContent.md5notCalc");
 
  461                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.sha256"), sha256);
 
  462                 } 
catch (TskCoreException ex) {
 
  463                     sb.append(NbBundle.getMessage(
this.getClass(), 
"Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
 
  465                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.sectorSize"), Long.toString(image.getSsize()));
 
  466                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.timezone"), image.getTimeZone());
 
  467                 addAcquisitionDetails(sb, dataSource);
 
  468                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.deviceId"), image.getDeviceId());
 
  469                 addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.internalid"), Long.toString(image.getId()));
 
  472                 String[] imagePaths = image.getPaths();
 
  474                 if (imagePaths.length > 0) {
 
  475                     addRowWithMultipleValues(sb,
 
  476                             NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.localPath"),
 
  479                     addRow(sb, NbBundle.getMessage(
this.getClass(), 
"Metadata.tableRowTitle.localPath"),
 
  480                             NbBundle.getMessage(
this.getClass(), 
"Metadata.nodeText.none"));
 
  490             return sb.toString();
 
static String escapeHtml(String toEscape)
 
void endTable(StringBuilder sb)
 
static String getSpacedSectionClassName()
 
void addRow(StringBuilder sb, String key, String value)
 
static String getTextClassName()
 
void addAcquisitionDetails(StringBuilder sb, DataSource dataSource)
 
void addRowWithMultipleValues(StringBuilder sb, String key, String[] values)
 
static String getFormattedTime(long epochTime)
 
javax.swing.JTextPane jTextPane1
 
javax.swing.JPopupMenu jPopupMenu1
 
static String getKeyColumnClassName()
 
static String getIndentedClassName()
 
void customizeComponents()
 
String getTitle(Node node)
 
boolean isSupported(Node node)
 
void addHeader(StringBuilder sb, String header, boolean spaced)
 
void addDownloadSourceRow(StringBuilder sb, BlackboardArtifact associatedArtifact)
 
static void setupHtmlJTextPane(JTextPane textPane)
 
DataContentViewer createInstance()
 
int isPreferred(Node node)
 
static String getHeaderClassName()
 
javax.swing.JScrollPane jScrollPane2
 
static String getMonospacedClassName()
 
synchronized static Logger getLogger(String name)
 
void startTable(StringBuilder sb)
 
void addMonospacedRow(StringBuilder sb, String key)