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;
43 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
45 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
51 import org.
sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
58 @ServiceProvider(service = DataContentViewer.class, position = 4)
59 @SuppressWarnings(
"PMD.SingularField")
71 customizeComponents();
80 @SuppressWarnings(
"unchecked")
82 private
void initComponents() {
84 jPopupMenu1 =
new javax.swing.JPopupMenu();
85 jScrollPane2 =
new javax.swing.JScrollPane();
86 jTextPane1 =
new javax.swing.JTextPane();
88 setPreferredSize(
new java.awt.Dimension(100, 52));
90 jScrollPane2.setPreferredSize(
new java.awt.Dimension(610, 52));
92 jTextPane1.setEditable(
false);
93 jTextPane1.setPreferredSize(
new java.awt.Dimension(600, 52));
94 jScrollPane2.setViewportView(jTextPane1);
96 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
97 this.setLayout(layout);
98 layout.setHorizontalGroup(
99 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
100 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
102 layout.setVerticalGroup(
103 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
104 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
128 jTextPane1.setText(
"<html><head></head><body>" + str +
"</body></html>");
131 private void addHeader(StringBuilder sb, String header,
boolean spaced) {
132 sb.append(MessageFormat.format(
"<div class=\"{0}\"><h1 class=\"{1}\">{2}</h1></div>",
139 sb.append(MessageFormat.format(
"<table class=\"{0}\" valign=\"top\" align=\"left\"><tbody>",
144 sb.append(
"</tbody></table>");
147 private void addRow(StringBuilder sb, String key, String value) {
148 sb.append(MessageFormat.format(
"<tr><td class=\"{0}\"><span class=\"{1}\">{2}:</span></td><td class=\"{3}\">{4}</td></tr>",
158 sb.append(MessageFormat.format(
"<tr><td class=\"{0}\"><span class=\"{1}\">{2}</span></td></tr>",
166 String[] safeValues = values == null || values.length < 1 ?
new String[]{
""} : values;
168 addRow(sb, key, safeValues[0]);
169 Stream.of(safeValues)
171 .filter(line -> line != null)
176 "Metadata.headerTitle=Metadata",
177 "Metadata.tableRowTitle.mimeType=MIME Type",
178 "Metadata.nodeText.truncated=(results truncated)",
179 "Metadata.tableRowTitle.sha1=SHA1",
180 "Metadata.tableRowTitle.sha256=SHA-256",
181 "Metadata.tableRowTitle.imageType=Type",
182 "Metadata.tableRowTitle.sectorSize=Sector Size",
183 "Metadata.tableRowTitle.timezone=Time Zone",
184 "Metadata.tableRowTitle.deviceId=Device ID",
185 "Metadata.tableRowTitle.acquisitionDetails=Acquisition Details",
186 "Metadata.tableRowTitle.downloadSource=Downloaded From",
187 "Metadata.nodeText.unknown=Unknown",
188 "Metadata.nodeText.none=None",
189 "Metadata.nodeText.loading=Metadata loading..."})
193 if (worker != null) {
199 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
200 setText(Bundle.Metadata_nodeText_loading());
205 if (!isCancelled()) {
207 jTextPane1.setCaretPosition(0);
209 }
catch (InterruptedException | ExecutionException ex) {
210 LOGGER.log(Level.SEVERE,
"Failed to get metaData for node " + node.getName(), ex);
213 setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
232 private void addDownloadSourceRow(StringBuilder sb, BlackboardArtifact associatedArtifact)
throws TskCoreException {
233 if (associatedArtifact != null
234 && ((associatedArtifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID())
235 || (associatedArtifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID()))) {
236 BlackboardAttribute urlAttr = associatedArtifact.getAttribute(
new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL));
237 if (urlAttr != null) {
238 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.downloadSource"), urlAttr.getValueString());
250 if (dataSource != null) {
252 String details = dataSource.getAcquisitionDetails();
253 if (StringUtils.isEmpty(details)) {
254 details = Bundle.Metadata_nodeText_unknown();
256 String[] lines = (details != null) ? details.split(
"\n") :
new String[]{
""};
257 addRowWithMultipleValues(sb,
258 NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.acquisitionDetails"),
261 }
catch (TskCoreException ex) {
262 LOGGER.log(Level.SEVERE,
"Error reading acquisition details from case database", ex);
269 return getTitle(null);
273 "Metadata_dataArtifactTitle=Source File Metadata"
277 if (node != null && !node.getLookup().lookupAll(DataArtifact.class).isEmpty()) {
278 return Bundle.Metadata_dataArtifactTitle();
280 return NbBundle.getMessage(this.getClass(),
"Metadata.title");
286 return NbBundle.getMessage(this.getClass(),
"Metadata.toolTip");
306 Image image = node.getLookup().lookup(Image.class);
307 AbstractFile file = node.getLookup().lookup(AbstractFile.class);
308 return (file != null) || (image != null);
329 AbstractFile file = node.getLookup().lookup(AbstractFile.class);
330 Image image = node.getLookup().lookup(Image.class);
331 DataSource dataSource = node.getLookup().lookup(DataSource.class);
332 if (file == null && image == null) {
333 return NbBundle.getMessage(this.getClass(),
"Metadata.nodeText.nonFilePassedIn");
336 StringBuilder sb =
new StringBuilder();
337 addHeader(sb, Bundle.Metadata_headerTitle(),
false);
342 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.name"), file.getUniquePath());
343 }
catch (TskCoreException ex) {
344 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.name"), file.getParentPath() +
"/" + file.getName());
347 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.type"), file.getType().getName());
348 addRow(sb, Bundle.Metadata_tableRowTitle_mimeType(), file.getMIMEType());
349 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.size"), Long.toString(file.getSize()));
350 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.fileNameAlloc"), file.getDirFlagAsString());
351 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.metadataAlloc"), file.getMetaFlagsAsString());
357 String md5 = file.getMd5Hash();
359 md5 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
361 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.md5"), md5);
362 String sha256 = file.getSha256Hash();
363 if (sha256 == null) {
364 sha256 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
366 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.sha256"), sha256);
367 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.hashLookupResults"), file.getKnown().toString());
368 addAcquisitionDetails(sb, dataSource);
370 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.internalid"), Long.toString(file.getId()));
371 if (file.getType().compareTo(TSK_DB_FILES_TYPE_ENUM.LOCAL) == 0) {
372 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.localPath"), file.getLocalAbsPath());
376 List<BlackboardArtifact> associatedObjectArtifacts = file.getArtifacts(ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
377 if (!associatedObjectArtifacts.isEmpty()) {
378 BlackboardArtifact artifact = associatedObjectArtifacts.get(0);
379 BlackboardAttribute associatedArtifactAttribute = artifact.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
380 if (associatedArtifactAttribute != null) {
381 long artifactId = associatedArtifactAttribute.getValueLong();
382 BlackboardArtifact associatedArtifact = artifact.getSleuthkitCase().getBlackboardArtifact(artifactId);
383 addDownloadSourceRow(sb, associatedArtifact);
386 }
catch (TskCoreException ex) {
387 sb.append(NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
396 if (file instanceof FsContent) {
397 FsContent fsFile = (FsContent) file;
399 addHeader(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.text"),
true);
402 List<String> istatStrings = Collections.emptyList();
404 istatStrings = fsFile.getMetaDataText();
405 }
catch (TskCoreException ex) {
406 istatStrings = Arrays.asList(NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.exceptionNotice.text") + ex.getLocalizedMessage());
409 for (String str : istatStrings) {
410 addMonospacedRow(sb, str);
416 if (sb.length() > 50000) {
417 addMonospacedRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.truncated"));
427 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.name"), image.getUniquePath());
428 }
catch (TskCoreException ex) {
429 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.name"), image.getName());
431 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.imageType"), image.getType().getName());
432 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.size"), Long.toString(image.getSize()));
435 String md5 = image.getMd5();
436 if (md5 == null || md5.isEmpty()) {
437 md5 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
439 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.md5"), md5);
441 String sha1 = image.getSha1();
442 if (sha1 == null || sha1.isEmpty()) {
443 sha1 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
445 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.sha1"), sha1);
447 String sha256 = image.getSha256();
448 if (sha256 == null || sha256.isEmpty()) {
449 sha256 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
451 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.sha256"), sha256);
452 }
catch (TskCoreException ex) {
453 sb.append(NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
455 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.sectorSize"), Long.toString(image.getSsize()));
456 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.timezone"), image.getTimeZone());
457 addAcquisitionDetails(sb, dataSource);
458 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.deviceId"), image.getDeviceId());
459 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.internalid"), Long.toString(image.getId()));
462 String[] imagePaths = image.getPaths();
465 if (imagePaths.length > 0) {
466 addRowWithMultipleValues(sb,
467 NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.localPath"),
470 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.localPath"),
471 NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.none"));
481 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)