diff --git a/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java b/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java index fbe2e35344..c0c1e970b8 100755 --- a/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java +++ b/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java @@ -70,6 +70,7 @@ public final class JythonModuleLoader { private static List getInterfaceImplementations(LineFilter filter, Class interfaceClass) { List objects = new ArrayList<>(); Set pythonModuleDirs = new HashSet<>(); + PythonInterpreter interpreter = new PythonInterpreter(); // add python modules from 'autospy/build/cluster/InternalPythonModules' folder // which are copied from 'autopsy/*/release/InternalPythonModules' folders. @@ -90,7 +91,7 @@ public final class JythonModuleLoader { if (line.startsWith("class ") && filter.accept(line)) { //NON-NLS String className = line.substring(6, line.indexOf("(")); try { - objects.add( createObjectFromScript(script, className, interfaceClass)); + objects.add( createObjectFromScript(interpreter, script, className, interfaceClass)); } catch (Exception ex) { logger.log(Level.SEVERE, String.format("Failed to load %s from %s", className, script.getAbsolutePath()), ex); //NON-NLS // NOTE: using ex.toString() because the current version is always returning null for ex.getMessage(). @@ -112,23 +113,23 @@ public final class JythonModuleLoader { return objects; } - private static T createObjectFromScript(File script, String className, Class interfaceClass) { - // Make a "fresh" interpreter every time to avoid name collisions, etc. - PythonInterpreter interpreter = new PythonInterpreter(); - + private static T createObjectFromScript(PythonInterpreter interpreter, File script, String className, Class interfaceClass) { // Add the directory where the Python script resides to the Python // module search path to allow the script to use other scripts bundled // with it. interpreter.exec("import sys"); //NON-NLS String path = Matcher.quoteReplacement(script.getParent()); interpreter.exec("sys.path.append('" + path + "')"); //NON-NLS + String moduleName = script.getName().replaceAll(".py", ""); //NON-NLS + + // reload the module so that the changes made to it can be loaded. + interpreter.exec("import " + moduleName); //NON-NLS + interpreter.exec("reload(" + moduleName + ")"); //NON-NLS - // Execute the script and create an instance of the desired class. - interpreter.execfile(script.getAbsolutePath()); // Importing the appropriate class from the Py Script which contains multiple classes. - interpreter.exec("from " + script.getName().replaceAll(".py", "") + " import " + className); + interpreter.exec("from " + moduleName + " import " + className); interpreter.exec("obj = " + className + "()"); //NON-NLS - + T obj = interpreter.get("obj", interfaceClass); //NON-NLS // Remove the directory where the Python script resides from the Python diff --git a/pythonExamples/dataSourceIngestModule.py b/pythonExamples/dataSourceIngestModule.py index 36a2d79a9e..6dde622796 100755 --- a/pythonExamples/dataSourceIngestModule.py +++ b/pythonExamples/dataSourceIngestModule.py @@ -32,6 +32,7 @@ # See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation import jarray +import inspect from java.lang import System from java.util.logging import Level from org.sleuthkit.datamodel import SleuthkitCase @@ -58,11 +59,11 @@ from org.sleuthkit.autopsy.casemodule.services import FileManager class SampleJythonDataSourceIngestModuleFactory(IngestModuleFactoryAdapter): # TODO: give it a unique name. Will be shown in module list, logs, etc. - moduleName = "Sample Data Source Module" - + moduleName = "Sample Data Source Module" + def getModuleDisplayName(self): return self.moduleName - + # TODO: Give it a description def getModuleDescription(self): return "Sample module that does X, Y, and Z." @@ -82,6 +83,11 @@ class SampleJythonDataSourceIngestModuleFactory(IngestModuleFactoryAdapter): # TODO: Rename this to something more specific. Could just remove "Factory" from above name. class SampleJythonDataSourceIngestModule(DataSourceIngestModule): + _logger = Logger.getLogger(SampleJythonDataSourceIngestModuleFactory.moduleName) + + def log(self, level, msg): + self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg) + def __init__(self): self.context = None @@ -93,8 +99,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule): self.context = context # Throw an IngestModule.IngestModuleException exception if there was a problem setting up # raise IngestModuleException(IngestModule(), "Oh No!") - - + # Where the analysis is done. # The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content. # See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html @@ -104,8 +109,6 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule): def process(self, dataSource, progressBar): if self.context.isJobCancelled(): return IngestModule.ProcessResult.OK - - logger = Logger.getLogger(SampleJythonDataSourceIngestModuleFactory.moduleName) # we don't know how much work there is yet progressBar.switchToIndeterminate() @@ -115,13 +118,13 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule): services = Services(sleuthkitCase) fileManager = services.getFileManager() - # For our example, we will use FileManager to get all + # For our example, we will use FileManager to get all # files with the word "test" # in the name and then count and read them files = fileManager.findFiles(dataSource, "%test%") numFiles = len(files) - logger.logp(Level.INFO, SampleJythonDataSourceIngestModule.__name__, "process", "found " + str(numFiles) + " files") + self.log(Level.INFO, "found " + str(numFiles) + " files") progressBar.switchToDeterminate(numFiles) fileCount = 0; for file in files: @@ -130,7 +133,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule): if self.context.isJobCancelled(): return IngestModule.ProcessResult.OK - logger.logp(Level.INFO, SampleJythonDataSourceIngestModule.__name__, "process", "Processing file: " + file.getName()) + self.log(Level.INFO, "Processing file: " + file.getName()) fileCount += 1 # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of @@ -139,7 +142,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule): att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), SampleJythonDataSourceIngestModuleFactory.moduleName, "Test file") art.addAttribute(att) - + # To further the example, this code will read the contents of the file and count the number of bytes inputStream = ReadContentInputStream(file) buffer = jarray.zeros(1024, "b") @@ -159,4 +162,4 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule): "Sample Jython Data Source Ingest Module", "Found %d files" % fileCount) IngestServices.getInstance().postMessage(message) - return IngestModule.ProcessResult.OK; + return IngestModule.ProcessResult.OK; \ No newline at end of file diff --git a/pythonExamples/fileIngestModule.py b/pythonExamples/fileIngestModule.py index d97c7b3752..a8194803a8 100755 --- a/pythonExamples/fileIngestModule.py +++ b/pythonExamples/fileIngestModule.py @@ -32,6 +32,7 @@ # See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation import jarray +import inspect from java.lang import System from java.util.logging import Level from org.sleuthkit.datamodel import SleuthkitCase @@ -84,12 +85,16 @@ class SampleJythonFileIngestModuleFactory(IngestModuleFactoryAdapter): # Looks at the attributes of the passed in file. class SampleJythonFileIngestModule(FileIngestModule): + _logger = Logger.getLogger(SampleJythonFileIngestModuleFactory.moduleName) + + def log(self, level, msg): + self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg) + # Where any setup and configuration is done # 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext. # See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html # TODO: Add any setup code that you need here. def startUp(self, context): - self.logger = Logger.getLogger(SampleJythonFileIngestModuleFactory.moduleName) self.filesFound = 0 # Throw an IngestModule.IngestModuleException exception if there was a problem setting up @@ -101,7 +106,6 @@ class SampleJythonFileIngestModule(FileIngestModule): # See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/classorg_1_1sleuthkit_1_1datamodel_1_1_abstract_file.html # TODO: Add your analysis code in here. def process(self, file): - # Skip non-files if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) or (file.isFile() == False)): return IngestModule.ProcessResult.OK @@ -109,7 +113,7 @@ class SampleJythonFileIngestModule(FileIngestModule): # For an example, we will flag files with .txt in the name and make a blackboard artifact. if file.getName().find(".txt") != -1: - self.logger.logp(Level.INFO, SampleJythonFileIngestModule.__name__, "process", "Found a text file: " + file.getName()) + self.log(Level.INFO, "Found a text file: " + file.getName()) self.filesFound+=1 # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of @@ -125,7 +129,7 @@ class SampleJythonFileIngestModule(FileIngestModule): for artifact in artifactList: attributeList = artifact.getAttributes(); for attrib in attributeList: - self.logger.logp(Level.INFO, SampleJythonFileIngestModule.__name__, "process", attrib.toString()) + self.log(Level.INFO, attrib.toString()) # To further the example, this code will read the contents of the file and count the number of bytes inputStream = ReadContentInputStream(file) @@ -143,4 +147,4 @@ class SampleJythonFileIngestModule(FileIngestModule): def shutDown(self): # As a final part of this example, we'll send a message to the ingest inbox with the number of files found (in this thread) message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, SampleJythonFileIngestModuleFactory.moduleName, str(self.filesFound) + " files found") - ingestServices = IngestServices.getInstance().postMessage(message) \ No newline at end of file + ingestServices = IngestServices.getInstance().postMessage(message) diff --git a/pythonExamples/fileIngestModuleWithGui.py b/pythonExamples/fileIngestModuleWithGui.py index 7780dcf3f2..842bce83be 100755 --- a/pythonExamples/fileIngestModuleWithGui.py +++ b/pythonExamples/fileIngestModuleWithGui.py @@ -39,6 +39,7 @@ import jarray +import inspect from java.lang import System from java.util.logging import Level from javax.swing import JCheckBox @@ -68,10 +69,10 @@ class SampleFileIngestModuleWithUIFactory(IngestModuleFactoryAdapter): # TODO: give it a unique name. Will be shown in module list, logs, etc. moduleName = "Sample Data Source Module with UI" - + def getModuleDisplayName(self): return self.moduleName - + # TODO: Give it a description def getModuleDescription(self): return "Sample module that does X, Y, and Z." @@ -109,6 +110,11 @@ class SampleFileIngestModuleWithUIFactory(IngestModuleFactoryAdapter): # Looks at the attributes of the passed in file. class SampleFileIngestModuleWithUI(FileIngestModule): + _logger = Logger.getLogger(SampleFileIngestModuleWithUIFactory.moduleName) + + def log(self, level, msg): + self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg) + # Autopsy will pass in the settings from the UI panel def __init__(self, settings): self.local_settings = settings @@ -117,14 +123,12 @@ class SampleFileIngestModuleWithUI(FileIngestModule): # Where any setup and configuration is done # TODO: Add any setup code that you need here. def startUp(self, context): - self.logger = Logger.getLogger(SampleFileIngestModuleWithUIFactory.moduleName) - # As an example, determine if user configured a flag in UI if self.local_settings.getFlag(): - self.logger.logp(Level.INFO, SampleFileIngestModuleWithUI.__name__, "startUp", "flag is set") + self.log(Level.INFO, "flag is set") else: - self.logger.logp(Level.INFO, SampleFileIngestModuleWithUI.__name__, "startUp", "flag is not set") - + self.log(Level.INFO, "flag is not set") + # Throw an IngestModule.IngestModuleException exception if there was a problem setting up # raise IngestModuleException(IngestModule(), "Oh No!") pass @@ -171,7 +175,7 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan # is present, it creates a read-only 'settings' property. This auto- # generated read-only property overshadows the instance-variable - # 'settings' - + # We get passed in a previous version of the settings so that we can # prepopulate the UI # TODO: Update this for your UI @@ -179,7 +183,7 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan self.local_settings = settings self.initComponents() self.customizeComponents() - + # TODO: Update this for your UI def checkBoxEvent(self, event): if self.checkbox.isSelected(): @@ -201,4 +205,3 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan def getSettings(self): return self.local_settings -