diff --git a/src/main/java/org/owasp/webgoat/container/LessonResourceScanner.java b/src/main/java/org/owasp/webgoat/container/LessonResourceScanner.java new file mode 100644 index 000000000..a6a55e6d1 --- /dev/null +++ b/src/main/java/org/owasp/webgoat/container/LessonResourceScanner.java @@ -0,0 +1,42 @@ +package org.owasp.webgoat.container; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class LessonResourceScanner { + + private static final Pattern lessonPattern = Pattern.compile("^.*/lessons/([^/]*)/.*$"); + + @Getter private final Set lessons = new HashSet<>(); + + public LessonResourceScanner(ResourcePatternResolver resourcePatternResolver) { + try { + var resources = resourcePatternResolver.getResources("classpath:/lessons/*/*"); + for (var resource : resources) { + // WG can run as a fat jar or as directly from file system we need to support both so use + // the URL + var url = resource.getURL(); + var matcher = lessonPattern.matcher(url.toString()); + if (matcher.matches()) { + lessons.add(matcher.group(1)); + } + } + log.debug("Found {} lessons", lessons.size()); + } catch (IOException e) { + log.warn("No lessons found..."); + } + } + + public List applyPattern(String pattern) { + return lessons.stream().map(lesson -> String.format(pattern, lesson)).toList(); + } +} diff --git a/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java b/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java index 7a91d18d0..deaaf2400 100644 --- a/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java +++ b/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java @@ -73,6 +73,8 @@ public class MvcConfiguration implements WebMvcConfigurer { private static final String UTF8 = "UTF-8"; + private final LessonResourceScanner lessonScanner; + @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); @@ -184,6 +186,28 @@ public class MvcConfiguration implements WebMvcConfigurer { registry .addResourceHandler("/fonts/**") .addResourceLocations("classpath:/webgoat/static/fonts/"); + + // WebGoat lessons + registry + .addResourceHandler("/images/**") + .addResourceLocations( + lessonScanner.applyPattern("classpath:/lessons/%s/images/").toArray(String[]::new)); + registry + .addResourceHandler("/lesson_js/**") + .addResourceLocations( + lessonScanner.applyPattern("classpath:/lessons/%s/js/").toArray(String[]::new)); + registry + .addResourceHandler("/lesson_css/**") + .addResourceLocations( + lessonScanner.applyPattern("classpath:/lessons/%s/css/").toArray(String[]::new)); + registry + .addResourceHandler("/lesson_templates/**") + .addResourceLocations( + lessonScanner.applyPattern("classpath:/lessons/%s/templates/").toArray(String[]::new)); + registry + .addResourceHandler("/video/**") + .addResourceLocations( + lessonScanner.applyPattern("classpath:/lessons/%s/video/").toArray(String[]::new)); } @Bean