Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
PDFViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020 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.BorderLayout;
22 import java.awt.Component;
23 import java.io.IOException;
24 import java.lang.reflect.InvocationTargetException;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Properties;
28 import java.util.ResourceBundle;
29 import java.util.concurrent.ExecutionException;
30 import java.util.logging.Level;
31 
32 import javax.swing.JPanel;
33 import javax.swing.SwingUtilities;
34 import javax.swing.SwingWorker;
35 import org.icepdf.core.SecurityCallback;
36 
37 import org.openide.util.NbBundle;
38 
39 import org.sleuthkit.datamodel.AbstractFile;
40 import org.sleuthkit.datamodel.ReadContentInputStream;
41 
44 
45 import org.icepdf.core.exceptions.PDFException;
46 import org.icepdf.core.exceptions.PDFSecurityException;
47 import org.icepdf.core.pobjects.Document;
48 
49 import org.icepdf.ri.common.ComponentKeyBinding;
50 import org.icepdf.ri.common.MyGUISecurityCallback;
51 import org.icepdf.ri.common.SwingController;
52 import org.icepdf.ri.common.SwingViewBuilder;
53 import org.icepdf.ri.common.views.DocumentViewControllerImpl;
54 import org.icepdf.ri.common.views.DocumentViewModelImpl;
55 import org.icepdf.ri.util.PropertiesManager;
56 
60 final class PDFViewer implements FileTypeViewer {
61 
62  private static final Logger logger = Logger.getLogger(PDFViewer.class.getName());
63 
64  private JPanel container;
65  private final PropertiesManager propsManager;
66  private final ResourceBundle messagesBundle;
67 
68  PDFViewer() {
69  container = createNewContainer();
70  messagesBundle = getMessagesBundle();
71  propsManager = getCustomProperties();
72  }
73 
74  @Override
75  public List<String> getSupportedMIMETypes() {
76  return Arrays.asList("application/pdf");
77  }
78 
79  @Override
80  public void setFile(AbstractFile file) {
81  // The 'C' in IcePDFs MVC set up.
82  SwingController controller = new SwingController(messagesBundle);
83 
84  // Builder for the 'V' in IcePDFs MVC set up
85  SwingViewBuilder viewBuilder = new SwingViewBuilder(controller, propsManager);
86 
87  // The 'V' in IcePDFs MVC set up.
88  JPanel icePdfPanel = viewBuilder.buildViewerPanel();
89 
90  // This connects keyboard commands performed on the view to the controller.
91  // The only keyboard commands that the controller supports is Ctrl-C for
92  // copying selected text.
93  ComponentKeyBinding.install(controller, icePdfPanel);
94 
95  // Ensure the preferredSize is in sync with the parent container.
96  icePdfPanel.setPreferredSize(this.container.getPreferredSize());
97 
98  // Add the IcePDF view to the center of our container.
99  this.container.add(icePdfPanel, BorderLayout.CENTER);
100 
101  // Document is the 'M' in IcePDFs MVC set up. Read the data needed to
102  // populate the model in the background.
103  new SwingWorker<Document, Void>() {
104  @Override
105  protected Document doInBackground() throws PDFException, PDFSecurityException, IOException {
106  ReadContentInputStream stream = new ReadContentInputStream(file);
107  Document doc = new Document();
108 
109  // Prompts the user for a password if the document is password
110  // protected.
111  doc.setSecurityCallback(createPasswordDialogCallback());
112 
113  // This will read the stream into memory and invoke the
114  // security callback if needed.
115  doc.setInputStream(stream, null);
116  return doc;
117  }
118 
119  @Override
120  protected void done() {
121  // Customize the view selection modes on the EDT. Each of these
122  // will cause UI widgets to be updated.
123  try {
124  Document doc = get();
125  controller.openDocument(doc, null);
126  // This makes the PDF viewer appear as one continuous
127  // document, which is the default for most popular PDF viewers.
128  controller.setPageViewMode(DocumentViewControllerImpl.ONE_COLUMN_VIEW, true);
129  // This makes it possible to select text by left clicking and dragging.
130  controller.setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION);
131  } catch (InterruptedException ex) {
132  // Do nothing.
133  } catch (ExecutionException ex) {
134  Throwable exCause = ex.getCause();
135  if (exCause instanceof PDFSecurityException) {
136  showEncryptionDialog();
137  } else {
138  logger.log(Level.WARNING, String.format("PDF content viewer "
139  + "was unable to open document with id %d and name %s",
140  file.getId(), file.getName()), ex);
141  showErrorDialog();
142  }
143  }
144  }
145  }.execute();
146  }
147 
148  @Override
149  public Component getComponent() {
150  return container;
151  }
152 
153  @Override
154  public void resetComponent() {
155  container = createNewContainer();
156  }
157 
158  // The container should have a BorderLayout otherwise the IcePDF panel may
159  // not be visible.
160  private JPanel createNewContainer() {
161  return new JPanel(new BorderLayout());
162  }
163 
164  @Override
165  public boolean isSupported(AbstractFile file) {
166  return getSupportedMIMETypes().contains(file.getMIMEType());
167  }
168 
173  private PropertiesManager getCustomProperties() {
174  Properties props = new Properties();
175 
176  // See link for available properties. https://www.icesoft.org/wiki/display/PDF/Customizing+the+Viewer
177  props.setProperty(PropertiesManager.PROPERTY_SHOW_UTILITY_SAVE, "false");
178  props.setProperty(PropertiesManager.PROPERTY_SHOW_UTILITY_OPEN, "false");
179  props.setProperty(PropertiesManager.PROPERTY_SHOW_UTILITY_PRINT, "false");
180  props.setProperty(PropertiesManager.PROPERTY_SHOW_TOOLBAR_ANNOTATION, "false");
181  props.setProperty(PropertiesManager.PROPERTY_SHOW_UTILITYPANE_ANNOTATION, "false");
182 
183  // This suppresses a pop-up, from IcePDF, that asks if you'd like to
184  // save configuration changes to disk.
185  props.setProperty("application.showLocalStorageDialogs", "false");
186 
187  return new PropertiesManager(System.getProperties(), props, messagesBundle);
188  }
189 
190  private ResourceBundle getMessagesBundle() {
191  return NbBundle.getBundle(PDFViewer.class);
192  }
193 
194  @NbBundle.Messages({
195  "PDFViewer.errorDialog=An error occurred while opening this PDF document. "
196  + "Check the logs for more information. You may continue to use "
197  + "this feature on other PDF documents."
198  })
199  private void showErrorDialog() {
200  MessageNotifyUtil.Message.error(Bundle.PDFViewer_errorDialog());
201  }
202 
203  @NbBundle.Messages({
204  "PDFViewer.encryptedDialog=This document is password protected."
205  })
206  private void showEncryptionDialog() {
207  MessageNotifyUtil.Message.error(Bundle.PDFViewer_encryptedDialog());
208  }
209 
213  private SecurityCallback createPasswordDialogCallback() {
214  // MyGUISecurityCallback is a reference implementation from IcePDF.
215  return new MyGUISecurityCallback(null, messagesBundle) {
216  private String password;
217 
218  @Override
219  public String requestPassword(Document document) {
220  try {
221  SwingUtilities.invokeAndWait(() -> {
222  // Show the password dialog on the EDT.
223  this.password = super.requestPassword(document);
224  });
225  return this.password;
226  } catch (InterruptedException | InvocationTargetException ex) {
227  return null;
228  }
229  }
230  };
231  }
232 }

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