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)