Skip to content

Commit

Permalink
Development: Add parsing of server sided endpoints (#8455)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan-Thurner authored Jun 4, 2024
1 parent 7eed1c7 commit 03e2b10
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 6 deletions.
13 changes: 9 additions & 4 deletions .github/workflows/analysis-of-endpoint-connections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
- 'src/main/webapp/**'

jobs:
show-modified-files:
analysis-of-endpoint-connections:
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
Expand All @@ -23,7 +23,12 @@ jobs:
run: |
git diff --name-only origin/${{ github.event.pull_request.base.ref }} HEAD > modified_files.txt
- name: Display modified files
- name: Set up JDK 21
uses: actions/setup-java@v2
with:
java-version: '21'
distribution: 'adopt'

- name: Run analysis-of-endpoint-connections
run: |
echo "Modified files in this pull request:"
cat modified_files.txt
./gradlew :supporting_scripts:analysis-of-endpoint-connections:run --args="$(cat modified_files.txt)"
7 changes: 5 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ repositories {
ext["jackson.version"] = fasterxml_version
ext["junit-jupiter.version"] = junit_version

ext { qDoxVersionReusable = "com.thoughtworks.qdox:qdox:2.1.0" }
ext { springBootStarterWeb = "org.springframework.boot:spring-boot-starter-web:${spring_boot_version}" }

dependencies {

// Note: jenkins-client is not well maintained and includes dependencies to libraries with critical security issues (e.g. CVE-2020-10683 for dom4j@1.6.1)
Expand Down Expand Up @@ -291,7 +294,7 @@ dependencies {
}
}

implementation "com.thoughtworks.qdox:qdox:2.1.0"
implementation qDoxVersionReusable
implementation "io.sentry:sentry-logback:${sentry_version}"
implementation "io.sentry:sentry-spring-boot-starter-jakarta:${sentry_version}"

Expand Down Expand Up @@ -361,7 +364,7 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-aop:${spring_boot_version}"
implementation "org.springframework.boot:spring-boot-starter-data-jpa:${spring_boot_version}"
implementation "org.springframework.boot:spring-boot-starter-security:${spring_boot_version}"
implementation("org.springframework.boot:spring-boot-starter-web:${spring_boot_version}") {
implementation(springBootStarterWeb) {
exclude module: "spring-boot-starter-undertow"
}
implementation "org.springframework.boot:spring-boot-starter-tomcat:${spring_boot_version}"
Expand Down
2 changes: 2 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ pluginManagement {
}

rootProject.name = 'Artemis'

include 'supporting_scripts:analysis-of-endpoint-connections'
32 changes: 32 additions & 0 deletions supporting_scripts/analysis-of-endpoint-connections/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
plugins {
id 'java'
id 'application'
}

group 'de.tum.in.www1.artemis'
version '1.0-SNAPSHOT'

repositories {
mavenCentral()
}

evaluationDependsOn(':')

dependencies {
implementation rootProject.ext.qDoxVersionReusable
implementation rootProject.ext.springBootStarterWeb
}

test {
useJUnitPlatform()
}

application {
mainClassName = 'de.tum.cit.endpointanalysis.AnalysisOfEndpointConnections'
}

run {
if (project.hasProperty('appArgs')) {
args = project.appArgs.split(' ')
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package de.tum.cit.endpointanalysis;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;

public class AnalysisOfEndpointConnections {

/**
* This is the entry point of the analysis of server sided endpoints.
*
* @param args List of files that should be analyzed regarding endpoints.
*/
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("No files to analyze.");
return;
}
String[] filePaths = args[0].split("\n");
String[] serverFiles = Arrays.stream(filePaths).map(filePath -> Paths.get("..", "..", filePath).toString())
.filter(filePath -> Files.exists(Paths.get(filePath)) && filePath.endsWith(".java")).toArray(String[]::new);
analyzeServerEndpoints(serverFiles);
}

private static void analyzeServerEndpoints(String[] filePaths) {
final Set<String> httpMethodClasses = Set.of(GetMapping.class.getName(), PostMapping.class.getName(), PutMapping.class.getName(), DeleteMapping.class.getName(),
PatchMapping.class.getName(), RequestMapping.class.getName());

JavaProjectBuilder builder = new JavaProjectBuilder();
for (String filePath : filePaths) {
builder.addSourceTree(new File(filePath));
}

Collection<JavaClass> classes = builder.getClasses();
for (JavaClass javaClass : classes) {
Optional<JavaAnnotation> requestMappingOptional = javaClass.getAnnotations().stream()
.filter(annotation -> annotation.getType().getFullyQualifiedName().equals(RequestMapping.class.getName())).findFirst();

boolean hasEndpoint = javaClass.getMethods().stream().flatMap(method -> method.getAnnotations().stream())
.anyMatch(annotation -> httpMethodClasses.contains(annotation.getType().getFullyQualifiedName()));

if (hasEndpoint) {
System.out.println("==================================================");
System.out.println("Class: " + javaClass.getFullyQualifiedName());
requestMappingOptional.ifPresent(annotation -> System.out.println("Class Request Mapping: " + annotation.getProperty("value")));
System.out.println("==================================================");
}

for (JavaMethod method : javaClass.getMethods()) {
for (JavaAnnotation annotation : method.getAnnotations()) {
if (httpMethodClasses.contains(annotation.getType().getFullyQualifiedName())) {
System.out.println("Endpoint: " + method.getName());
System.out.println(
annotation.getType().getFullyQualifiedName().equals(RequestMapping.class.getName()) ? "RequestMapping·method: " + annotation.getProperty("method")
: "HTTP method annotation: " + annotation.getType().getName());
System.out.println("Path: " + annotation.getProperty("value"));
System.out.println("Line: " + method.getLineNumber());
List<String> annotations = method.getAnnotations().stream().filter(a -> !a.equals(annotation)).map(a -> a.getType().getName()).toList();
System.out.println("Other annotations: " + annotations);
System.out.println("---------------------------------------------------");
}
}
}
}
}
}

0 comments on commit 03e2b10

Please sign in to comment.