Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.python;
20
21import java.io.File;
22import java.io.FileNotFoundException;
23import java.io.FilenameFilter;
24import java.util.ArrayList;
25import java.util.Collections;
26import java.util.HashSet;
27import java.util.List;
28import java.util.Scanner;
29import java.util.Set;
30import java.util.logging.Level;
31import java.util.regex.Matcher;
32import org.openide.DialogDisplayer;
33import org.openide.NotifyDescriptor;
34import org.openide.modules.InstalledFileLocator;
35import org.openide.util.NbBundle;
36import org.openide.util.NbBundle.Messages;
37import org.python.util.PythonInterpreter;
38import org.sleuthkit.autopsy.core.RuntimeProperties;
39import org.sleuthkit.autopsy.coreutils.Logger;
40import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
41import org.sleuthkit.autopsy.coreutils.PlatformUtil;
42import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
43import org.sleuthkit.autopsy.report.GeneralReportModule;
44import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
45import java.io.BufferedReader;
46import java.io.FileReader;
47import java.io.IOException;
48import java.text.MessageFormat;
49import java.util.Comparator;
50import org.apache.commons.io.FileUtils;
51
56public 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}
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static void show(String title, String message, MessageType type, ActionListener actionListener)
static synchronized List< IngestModuleFactory > getIngestModuleFactories()
static< T > List< T > getInterfaceImplementations(LineFilter filter, Class< T > interfaceClass)
static synchronized List< GeneralReportModule > getGeneralReportModules()
static synchronized List< DataSourceProcessor > getDataSourceProcessorModules()
static< T > T createObjectFromScript(PythonInterpreter interpreter, File script, String className, Class< T > interfaceClass)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.