From 112ca3ab2289033b5f24335c5df749a2aeb14614 Mon Sep 17 00:00:00 2001
From: Nanne Baars <nanne.baars@owasp.org>
Date: Sat, 21 Dec 2024 18:47:30 +0100
Subject: [PATCH] fix: enable resource patterns again (#1993)

`LessonScanner.java` got removed by mistake.

Closes: gh-1992
---
 .../container/LessonResourceScanner.java      | 42 +++++++++++++++++++
 .../webgoat/container/MvcConfiguration.java   | 24 +++++++++++
 2 files changed, 66 insertions(+)
 create mode 100644 src/main/java/org/owasp/webgoat/container/LessonResourceScanner.java

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<String> 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<String> 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