properties loaded from plugin
This commit is contained in:
@ -5,98 +5,104 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.owasp.webgoat.plugins.PluginFileUtils.fileEndsWith;
|
||||
import static org.owasp.webgoat.plugins.PluginFileUtils.hasParentDirectoryWithName;
|
||||
|
||||
public class Plugin {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Plugin.class);
|
||||
private final Class<AbstractLesson> lesson;
|
||||
private static final String NAME_LESSON_SOLUTION_DIRECTORY = "lessonSolutions";
|
||||
private static final String NAME_LESSON_PLANS_DIRECTORY = "lessonPlans";
|
||||
private static final String NAME_LESSON_I18N_DIRECTORY = "i18n";
|
||||
private final Logger logger = LoggerFactory.getLogger(Plugin.class);
|
||||
private final Path pluginDirectory;
|
||||
private final Map<String, File> solutionLanguageFiles;
|
||||
private final Map<String, File> lessonPlansLanguageFiles;
|
||||
private final File lessonSourceFile;
|
||||
|
||||
private Class<AbstractLesson> lesson;
|
||||
private Map<String, File> solutionLanguageFiles = new HashMap<>();
|
||||
private Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
|
||||
private File lessonSourceFile;
|
||||
|
||||
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>();
|
||||
private final Map<String, File> solutionLanguageFiles = new HashMap<>();
|
||||
private final Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
|
||||
private File javaSource;
|
||||
|
||||
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();
|
||||
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader, classFile);
|
||||
try {
|
||||
String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", "");
|
||||
Class clazz = pluginClassLoader.loadClass(realClassName);
|
||||
if (AbstractLesson.class.isAssignableFrom(clazz)) {
|
||||
this.lesson = clazz;
|
||||
}
|
||||
loadedClasses.add(clazz.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error("Unable to load class {}", name);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBaseDirectory(Path pluginDirectory) {
|
||||
this.pluginDirectory = pluginDirectory;
|
||||
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, lessonPlansLanguageFiles, solutionLanguageFiles, javaSource);
|
||||
}
|
||||
|
||||
public void loadFiles(List<Path> files) {
|
||||
for (Path file : files) {
|
||||
if (file.getFileName().toString().endsWith(".html") && file.getParent().getParent().getFileName().toString()
|
||||
.endsWith("lessonSolutions")) {
|
||||
solutionLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
|
||||
}
|
||||
if (file.getFileName().toString().endsWith(".html") && file.getParent().getParent().getFileName().toString()
|
||||
.endsWith("lessonPlans")) {
|
||||
lessonPlansLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
|
||||
}
|
||||
if ( file.getFileName().toString().endsWith(".java")) {
|
||||
javaSource = file.toFile();
|
||||
}
|
||||
}
|
||||
public PluginLoadingFailure(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Plugin(Class<AbstractLesson> lesson, Path pluginDirectory, Map<String, File> lessonPlansLanguageFiles,
|
||||
Map<String, File> solutionLanguageFiles, File lessonSourceFile) {
|
||||
this.lesson = lesson;
|
||||
public Plugin(Path pluginDirectory) {
|
||||
this.pluginDirectory = pluginDirectory;
|
||||
this.lessonPlansLanguageFiles = lessonPlansLanguageFiles;
|
||||
this.solutionLanguageFiles = solutionLanguageFiles;
|
||||
this.lessonSourceFile = lessonSourceFile;
|
||||
}
|
||||
|
||||
public void loadClasses(Map<String, byte[]> classes) {
|
||||
for (Map.Entry<String, byte[]> clazz : classes.entrySet()) {
|
||||
loadClass(clazz.getKey(), clazz.getValue());
|
||||
}
|
||||
if (lesson == null) {
|
||||
throw new PluginLoadingFailure(String
|
||||
.format("Lesson class not found, following classes were detected in the plugin: %s",
|
||||
StringUtils.collectionToCommaDelimitedString(classes.keySet())));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadClass(String name, byte[] classFile) {
|
||||
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader, classFile);
|
||||
try {
|
||||
String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", "");
|
||||
Class clazz = pluginClassLoader.loadClass(realClassName);
|
||||
if (AbstractLesson.class.isAssignableFrom(clazz)) {
|
||||
this.lesson = clazz;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error("Unable to load class {}", name);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadFiles(List<Path> files) {
|
||||
for (Path file : files) {
|
||||
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_SOLUTION_DIRECTORY)) {
|
||||
solutionLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
|
||||
}
|
||||
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_PLANS_DIRECTORY)) {
|
||||
lessonPlansLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
|
||||
}
|
||||
if (fileEndsWith(file, ".java")) {
|
||||
lessonSourceFile = file.toFile();
|
||||
}
|
||||
if (fileEndsWith(file, ".properties") && hasParentDirectoryWithName(file, NAME_LESSON_I18N_DIRECTORY)) {
|
||||
try {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
Files.copy(file, bos);
|
||||
Path propertiesPath = createPropertiesDirectory();
|
||||
ResourceBundleClassLoader.setPropertiesPath(propertiesPath);
|
||||
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
|
||||
} catch (IOException io) {
|
||||
throw new PluginLoadingFailure("Property file detected, but unable to copy the properties", io);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Path createPropertiesDirectory() throws IOException {
|
||||
if (Files.exists(pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY))) {
|
||||
return pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY);
|
||||
} else {
|
||||
return Files.createDirectory(pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY));
|
||||
}
|
||||
}
|
||||
|
||||
public Class<AbstractLesson> getLesson() {
|
||||
@ -107,7 +113,9 @@ public class Plugin {
|
||||
return this.solutionLanguageFiles;
|
||||
}
|
||||
|
||||
public File getLessonSource() { return lessonSourceFile; }
|
||||
public File getLessonSource() {
|
||||
return lessonSourceFile;
|
||||
}
|
||||
|
||||
public Map<String, File> getLessonPlans() {
|
||||
return this.lessonPlansLanguageFiles;
|
||||
|
22
src/main/java/org/owasp/webgoat/plugins/PluginFileUtils.java
Normal file
22
src/main/java/org/owasp/webgoat/plugins/PluginFileUtils.java
Normal file
@ -0,0 +1,22 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class PluginFileUtils {
|
||||
|
||||
public static boolean fileEndsWith(Path p, String s) {
|
||||
return p.getFileName().toString().endsWith(s);
|
||||
}
|
||||
|
||||
public static boolean hasParentDirectoryWithName(Path p, String s) {
|
||||
if (p == null || p.getParent() == null || p.getRoot().equals(p.getParent())) {
|
||||
return false;
|
||||
}
|
||||
if (p.getParent().getFileName().toString().equals(s)) {
|
||||
return true;
|
||||
}
|
||||
return hasParentDirectoryWithName(p.getParent(), s);
|
||||
}
|
||||
|
||||
}
|
@ -31,11 +31,10 @@ public class PluginsLoader implements Runnable {
|
||||
try {
|
||||
PluginExtractor extractor = new PluginExtractor(file);
|
||||
extractor.extract();
|
||||
Plugin.Builder builder = new Plugin.Builder();
|
||||
builder.loadClasses(extractor.getClasses());
|
||||
builder.loadFiles(extractor.getFiles());
|
||||
builder.setBaseDirectory(extractor.getBaseDirectory());
|
||||
plugins.add(builder.build());
|
||||
Plugin plugin = new Plugin(extractor.getBaseDirectory());
|
||||
plugin.loadClasses(extractor.getClasses());
|
||||
plugin.loadFiles(extractor.getFiles());
|
||||
plugins.add(plugin);
|
||||
} catch (Plugin.PluginLoadingFailure e) {
|
||||
logger.error("Unable to load plugin, continue reading others...");
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ResourceBundleClassLoader {
|
||||
|
||||
private final static ResourceBundleClassLoader classLoader = new ResourceBundleClassLoader();
|
||||
private Path propertiesPath;
|
||||
|
||||
private ResourceBundleClassLoader() {
|
||||
}
|
||||
|
||||
public static void setPropertiesPath(Path path) {
|
||||
classLoader.propertiesPath = path;
|
||||
}
|
||||
|
||||
public static ClassLoader createPropertyFilesClassLoader(ClassLoader parentClassLoader) {
|
||||
final List<URL> urls = new ArrayList<>();
|
||||
|
||||
try {
|
||||
urls.add(classLoader.propertiesPath.toUri().toURL());
|
||||
} catch (IOException e) {
|
||||
throw new Plugin.PluginLoadingFailure("Unable to load the properties for the classloader", e);
|
||||
}
|
||||
return new URLClassLoader(urls.toArray(new URL[urls.size()]), Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user