Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
JythonModuleLoader.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2014-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.python;
20 
21 import java.io.File;
22 import java.io.FileNotFoundException;
23 import java.io.FilenameFilter;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Scanner;
29 import java.util.Set;
30 import java.util.logging.Level;
31 import java.util.regex.Matcher;
32 import org.openide.DialogDisplayer;
33 import org.openide.NotifyDescriptor;
34 import org.openide.modules.InstalledFileLocator;
35 import org.openide.util.NbBundle;
36 import org.openide.util.NbBundle.Messages;
37 import org.python.util.PythonInterpreter;
45 import java.io.BufferedReader;
46 import java.io.FileReader;
47 import java.io.IOException;
48 import java.text.MessageFormat;
49 import java.util.Comparator;
50 import org.apache.commons.io.FileUtils;
51 
56 public final class JythonModuleLoader {
57 
58  private static final Logger logger = Logger.getLogger(JythonModuleLoader.class.getName());
59  private static final String INTERNAL_PYTHON_MODULES_FOLDER = "InternalPythonModules";
60 
67  public static synchronized List<IngestModuleFactory> getIngestModuleFactories() {
69  }
70 
77  public static synchronized List<GeneralReportModule> getGeneralReportModules() {
79  }
80 
87  public static synchronized List<DataSourceProcessor> getDataSourceProcessorModules() {
89  }
90 
95  private static File getUserDirInternalPython() {
97  }
98 
105  private static synchronized void copyInternalInstallToUserDir() {
106  File userDirInternalPython = getUserDirInternalPython();
107  if (!userDirInternalPython.exists()) {
108  userDirInternalPython.mkdirs();
109 
110  File installInternalPython = InstalledFileLocator.getDefault().locate(INTERNAL_PYTHON_MODULES_FOLDER, "org.sleuthkit.autopsy.core", false);
111  if (installInternalPython.exists()) {
112  try {
113  FileUtils.copyDirectory(installInternalPython, userDirInternalPython);
114  } catch (IOException ex) {
115  logger.log(Level.WARNING, MessageFormat.format("There was an error copying internal python modules from {0} to {1}.",
116  installInternalPython, userDirInternalPython), ex);
117  }
118  }
119  }
120  }
121 
122  @Messages({"JythonModuleLoader.pythonInterpreterError.title=Python Modules",
123  "JythonModuleLoader.pythonInterpreterError.msg=Failed to load python modules, See log for more details"})
124  private static <T> List<T> getInterfaceImplementations(LineFilter filter, Class<T> interfaceClass) {
126 
127  List<T> objects = new ArrayList<>();
128  Set<File> pythonModuleDirs = new HashSet<>();
129  PythonInterpreter interpreter = null;
130  // This method has previously thrown unchecked exceptions when it could not load because of non-latin characters.
131  try {
132  interpreter = new PythonInterpreter();
133  } catch (Exception ex) {
134  logger.log(Level.SEVERE, "Failed to load python Intepreter. Cannot load python modules", ex);
136  MessageNotifyUtil.Notify.show(Bundle.JythonModuleLoader_pythonInterpreterError_title(),Bundle.JythonModuleLoader_pythonInterpreterError_msg(), MessageNotifyUtil.MessageType.ERROR);
137  }
138  return objects;
139  }
140 
141  // add python modules from 'autospy/build/cluster/InternalPythonModules' folder
142  // which are copied from 'autopsy/*/release/InternalPythonModules' folders,
143  // and then copied to 'testuserdir/InternalPythonModules'
144  Collections.addAll(pythonModuleDirs, getUserDirInternalPython().listFiles());
145 
146  // add python modules from 'testuserdir/python_modules' folder
147  Collections.addAll(pythonModuleDirs, new File(PlatformUtil.getUserPythonModulesPath()).listFiles());
148 
149  for (File file : pythonModuleDirs) {
150  if (file.isDirectory()) {
151  File[] pythonScripts = file.listFiles(new PythonScriptFileFilter());
152  for (File script : pythonScripts) {
153  try (Scanner fileScanner = new Scanner(new BufferedReader(new FileReader(script)))) {
154  while (fileScanner.hasNextLine()) {
155  String line = fileScanner.nextLine();
156  if (line.startsWith("class ") && filter.accept(line)) { //NON-NLS
157  String className = line.substring(6, line.indexOf("("));
158  try {
159  objects.add(createObjectFromScript(interpreter, script, className, interfaceClass));
160  } catch (Exception ex) {
161  logger.log(Level.SEVERE, String.format("Failed to load %s from %s", className, script.getAbsolutePath()), ex); //NON-NLS
162  // NOTE: using ex.toString() because the current version is always returning null for ex.getMessage().
163  DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
164  NbBundle.getMessage(JythonModuleLoader.class, "JythonModuleLoader.errorMessages.failedToLoadModule", className, ex.toString()),
165  NotifyDescriptor.ERROR_MESSAGE));
166  }
167  }
168  }
169  } catch (FileNotFoundException ex) {
170  logger.log(Level.SEVERE, String.format("Failed to open %s", script.getAbsolutePath()), ex); //NON-NLS
171  DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
172  NbBundle.getMessage(JythonModuleLoader.class, "JythonModuleLoader.errorMessages.failedToOpenModule", script.getAbsolutePath()),
173  NotifyDescriptor.ERROR_MESSAGE));
174  }
175  }
176  }
177  }
178 
179  Collections.sort(objects, Comparator.comparing((T obj) -> obj.getClass().getSimpleName(), (s1, s2) -> s1.compareToIgnoreCase(s2)));
180  return objects;
181  }
182 
183  private static <T> T createObjectFromScript(PythonInterpreter interpreter, File script, String className, Class<T> interfaceClass) {
184  // Add the directory where the Python script resides to the Python
185  // module search path to allow the script to use other scripts bundled
186  // with it.
187  interpreter.exec("import sys"); //NON-NLS
188  String path = Matcher.quoteReplacement(script.getParent());
189  interpreter.exec("sys.path.append('" + path + "')"); //NON-NLS
190  String moduleName = script.getName().replaceAll("\\.py$", ""); //NON-NLS
191 
192  // reload the module so that the changes made to it can be loaded.
193  interpreter.exec("import " + moduleName); //NON-NLS
194  interpreter.exec("reload(" + moduleName + ")"); //NON-NLS
195 
196  // Importing the appropriate class from the Py Script which contains multiple classes.
197  interpreter.exec("from " + moduleName + " import " + className); //NON-NLS
198  interpreter.exec("obj = " + className + "()"); //NON-NLS
199 
200  T obj = interpreter.get("obj", interfaceClass); //NON-NLS
201 
202  // Remove the directory where the Python script resides from the Python
203  // module search path.
204  interpreter.exec("sys.path.remove('" + path + "')"); //NON-NLS
205 
206  return obj;
207  }
208 
209  private static class PythonScriptFileFilter implements FilenameFilter {
210 
211  @Override
212  public boolean accept(File dir, String name) {
213  return name.endsWith(".py"); //NON-NLS
214  } //NON-NLS
215  }
216 
217  private static interface LineFilter {
218 
219  boolean accept(String line);
220  }
221 
225  private static class IngestModuleFactoryDefFilter implements LineFilter {
226 
227  @Override
228  public boolean accept(String line) {
229  return (line.contains("IngestModuleFactoryAdapter") || line.contains("IngestModuleFactory")); //NON-NLS
230  }
231  }
232 
236  private static class GeneralReportModuleDefFilter implements LineFilter {
237 
238  @Override
239  public boolean accept(String line) {
240  return (line.contains("GeneralReportModuleAdapter") || line.contains("GeneralReportModule")); //NON-NLS
241  }
242  }
243 
247  private static class DataSourceProcessorDefFilter implements LineFilter {
248 
249  @Override
250  public boolean accept(String line) {
251  return (line.contains("DataSourceProcessorAdapter") || line.contains("DataSourceProcessor")); //NON-NLS
252  }
253  }
254 }
static< T > List< T > getInterfaceImplementations(LineFilter filter, Class< T > interfaceClass)
static synchronized List< IngestModuleFactory > getIngestModuleFactories()
static< T > T createObjectFromScript(PythonInterpreter interpreter, File script, String className, Class< T > interfaceClass)
static synchronized List< GeneralReportModule > getGeneralReportModules()
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void show(String title, String message, MessageType type, ActionListener actionListener)
static synchronized List< DataSourceProcessor > getDataSourceProcessorModules()

Copyright © 2012-2022 Basis Technology. Generated on: Tue Feb 6 2024
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.