refactored so the extracting is not tangled with the loading the plugin
This commit is contained in:
		| @ -1,21 +1,43 @@ | ||||
| package org.owasp.webgoat.plugins; | ||||
|  | ||||
| import org.owasp.webgoat.lessons.AbstractLesson; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import org.springframework.util.StringUtils; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.nio.charset.Charset; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class Plugin { | ||||
|  | ||||
|     private static final Logger logger = LoggerFactory.getLogger(Plugin.class); | ||||
|     private final Class<AbstractLesson> lesson; | ||||
|     private final Path pluginDirectory; | ||||
|  | ||||
|     public static class PluginLoadingFailure extends RuntimeException { | ||||
|  | ||||
|         public PluginLoadingFailure(String message) { | ||||
|             super(message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static class Builder { | ||||
|  | ||||
|         private Path pluginDirectory; | ||||
|         private Class lesson; | ||||
|         private final List<String> loadedClasses = new ArrayList<String>(); | ||||
|  | ||||
|         public Builder loadClasses(Map<String, byte[]> classes) { | ||||
|             for (Map.Entry<String, byte[]> clazz : classes.entrySet() ) { | ||||
|                 loadClass(clazz.getKey(), clazz.getValue()); | ||||
|             } | ||||
|             return this; | ||||
|         } | ||||
|  | ||||
|         public Builder loadClass(String name, byte[] classFile) { | ||||
|             ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); | ||||
| @ -26,20 +48,27 @@ public class Plugin { | ||||
|                 if (AbstractLesson.class.isAssignableFrom(clazz)) { | ||||
|                     this.lesson = clazz; | ||||
|                 } | ||||
|                 loadedClasses.add(clazz.getName()); | ||||
|             } catch (ClassNotFoundException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 logger.error("Unable to load class {}", name); | ||||
|             } | ||||
|             return this; | ||||
|         } | ||||
|  | ||||
|         public Builder setBaseDirectory(Path pluginDirectory) { | ||||
|             this.pluginDirectory = pluginDirectory; | ||||
|             //Find necessary files flag if something went wrong plugin should complain | ||||
|             return this; | ||||
|         } | ||||
|  | ||||
|         public Plugin build() { | ||||
|             if ( lesson == null ) { | ||||
|                 throw new PluginLoadingFailure(String.format("Lesson class not found, following classes were detected in the plugin: %s", | ||||
|                     StringUtils.collectionToCommaDelimitedString(loadedClasses))); | ||||
|             } | ||||
|             return new Plugin(this.lesson, pluginDirectory); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public Plugin(Class<AbstractLesson> lesson, Path pluginDirectory) { | ||||
| @ -52,9 +81,9 @@ public class Plugin { | ||||
|         try { | ||||
|             Files.readAllLines(lesson_plans.resolve(this.lesson.getSimpleName() + ".html"), Charset.defaultCharset()); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             logger.error("No html found in directory {}", lesson_plans.toString()); | ||||
|         } | ||||
|         return lesson_plans.resolve(this.lesson.getSimpleName() + ".html").toFile().toString(); | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public Class<AbstractLesson> getLesson() { | ||||
|  | ||||
| @ -13,10 +13,5 @@ public class PluginClassLoader extends ClassLoader { | ||||
|         return defineClass(name, classFile, 0, classFile.length); | ||||
|     } | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -13,60 +13,59 @@ import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.nio.file.Paths; | ||||
| import java.nio.file.SimpleFileVisitor; | ||||
| import java.nio.file.StandardCopyOption; | ||||
| import java.nio.file.attribute.BasicFileAttributes; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; | ||||
|  | ||||
| /** | ||||
|  * Extract the zip file and place the files in a temp directory | ||||
|  * | ||||
|  * TODO: should only do the extraction of the zip file return should be the base directory of the extracted | ||||
|  * plugin. The PluginLoader should take care of the loading | ||||
|  * | ||||
|  * Extract the wpf file and collect the classes to load and remember the base directory in which we extracted | ||||
|  * the files (lesson plans etc) | ||||
|  */ | ||||
| public class PluginExtractor { | ||||
|  | ||||
|     private static final String DIRECTORY = "webgoat"; | ||||
|     private final Path pluginArchive; | ||||
|     private final Logger logger = LoggerFactory.getLogger(getClass()); | ||||
|     private final List<byte[]> classes = new ArrayList<byte[]>(); | ||||
|     private final Map<String, byte[]> classes = new HashMap<String, byte[]>(); | ||||
|     private Path baseDirectory; | ||||
|  | ||||
|     public PluginExtractor(Path pluginArchive) { | ||||
|         this.pluginArchive = pluginArchive; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public Plugin extract() { | ||||
|         final Plugin.Builder pluginBuilder = new Plugin.Builder(); | ||||
|     public void extract() { | ||||
|         FileSystem zip = null; | ||||
|         try { | ||||
|             zip = createZipFileSystem(); | ||||
|             final Path root = zip.getPath("/"); | ||||
|             final Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"), DIRECTORY); | ||||
|             pluginBuilder.setBaseDirectory(tmpDir); | ||||
|             baseDirectory = Paths.get(System.getProperty("java.io.tmpdir"), DIRECTORY); | ||||
|             Files.walkFileTree(root, new SimpleFileVisitor<Path>() { | ||||
|                 @Override | ||||
|                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { | ||||
|                     if (file.toString().endsWith(".class")) { | ||||
|                         ByteArrayOutputStream bos = new ByteArrayOutputStream(); | ||||
|                         Files.copy(file, bos); | ||||
|                         pluginBuilder.loadClass(file.toString(), bos.toByteArray()); | ||||
|                         classes.put(file.toString(), bos.toByteArray()); | ||||
|                     } | ||||
|  | ||||
|                     Files.copy(file, Paths.get(tmpDir.toString(), file.toString()), StandardCopyOption.REPLACE_EXISTING); | ||||
|                     Files.copy(file, Paths.get(baseDirectory.toString(), file.toString()), REPLACE_EXISTING); | ||||
|                     return FileVisitResult.CONTINUE; | ||||
|                 } | ||||
|             }); | ||||
|             return pluginBuilder.build(); | ||||
|         } catch (IOException io) { | ||||
|             logger.error(String.format("Unable to extract: %s", pluginArchive.getFileName()), io); | ||||
|         } finally { | ||||
|             closeZipFileSystem(zip); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|         return pluginBuilder.build(); | ||||
|     public Map<String, byte[]> getClasses() { | ||||
|         return this.classes; | ||||
|     } | ||||
|  | ||||
|     public Path getBaseDirectory() { | ||||
|         return this.baseDirectory; | ||||
|     } | ||||
|  | ||||
|     private FileSystem createZipFileSystem() throws IOException { | ||||
|  | ||||
| @ -1,5 +1,8 @@ | ||||
| package org.owasp.webgoat.plugins; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.nio.file.FileVisitResult; | ||||
| import java.nio.file.Files; | ||||
| @ -11,6 +14,7 @@ import java.util.List; | ||||
|  | ||||
| public class PluginsLoader { | ||||
|  | ||||
|     private final Logger logger = LoggerFactory.getLogger(this.getClass()); | ||||
|     private final Path path; | ||||
|  | ||||
|     public PluginsLoader(Path path) { | ||||
| @ -24,13 +28,22 @@ public class PluginsLoader { | ||||
|  | ||||
|                 @Override | ||||
|                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { | ||||
|                     plugins.add(new PluginExtractor(file).extract()); | ||||
|                     try { | ||||
|                         PluginExtractor extractor = new PluginExtractor(file); | ||||
|                         extractor.extract(); | ||||
|                         Plugin.Builder builder = new Plugin.Builder(); | ||||
|                         builder.loadClasses(extractor.getClasses()); | ||||
|                         builder.setBaseDirectory(extractor.getBaseDirectory()); | ||||
|                         plugins.add(builder.build()); | ||||
|                     } catch (Plugin.PluginLoadingFailure e) { | ||||
|                        logger.error("Unable to load plugin, continue reading others..."); | ||||
|                     } | ||||
|                     return FileVisitResult.CONTINUE; | ||||
|                 } | ||||
|  | ||||
|             }); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             logger.error("Loading plugins failed", e); | ||||
|         } | ||||
|         return plugins; | ||||
|     } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user