From 6abf5f0b747db2d9d098d5d35f4859f68f20c867 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Mon, 23 Jun 2025 22:34:01 -0700
Subject: [PATCH] Avoid and discourage use of Maven Central as a CDN (#12692)
* Default LibraryLoader to Google's Maven Central mirror, add MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR, and warn on use of Maven Central with MavenLibraryResolver
* Account for both Maven Central URLs
* Update Javadoc
(cherry picked from commit 62b7f86dae659deb2fc450285452d7c1439f92dc)
---
.../library/impl/MavenLibraryResolver.java | 34 ++++++++++++++++++-
.../org/bukkit/plugin/java/LibraryLoader.java | 8 +++--
2 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/paper-api/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java b/paper-api/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java
index 107705db2d..c1fccd64b1 100644
--- a/paper-api/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java
+++ b/paper-api/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java
@@ -41,7 +41,7 @@ import org.slf4j.LoggerFactory;
* MavenLibraryResolver resolver = new MavenLibraryResolver();
* resolver.addDependency(new Dependency(new DefaultArtifact("org.jooq:jooq:3.17.7"), null));
* resolver.addRepository(new RemoteRepository.Builder(
- * "central", "default", "https://repo1.maven.org/maven2/"
+ * "central", "default", MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR
* ).build());
* }
*
@@ -50,6 +50,21 @@ import org.slf4j.LoggerFactory;
@NullMarked
public class MavenLibraryResolver implements ClassPathLibrary {
+ /**
+ * The default Maven Central mirror, configurable through the {@code PAPER_DEFAULT_CENTRAL_REPOSITORY} environment
+ * variable. Use this instead of Maven Central directly when you do not have your own mirror, as using
+ * Maven Central as a CDN is against the Maven Central Terms of Service, and you will cause users to hit
+ * rate limits.
+ *
+ *
This repository is also used by the legacy {@link org.bukkit.plugin.java.LibraryLoader}.
+ */
+ public static final String MAVEN_CENTRAL_DEFAULT_MIRROR = getDefaultMavenCentralMirror();
+ private static final List MAVEN_CENTRAL_URLS = List.of(
+ "https://repo1.maven.org/maven2",
+ "http://repo1.maven.org/maven2",
+ "https://repo.maven.apache.org/maven2",
+ "http://repo.maven.apache.org/maven2"
+ );
private static final Logger LOGGER = LoggerFactory.getLogger("MavenLibraryResolver");
private final RepositorySystem repository;
@@ -105,6 +120,12 @@ public class MavenLibraryResolver implements ClassPathLibrary {
* dependencies from
*/
public void addRepository(final RemoteRepository remoteRepository) {
+ if (MAVEN_CENTRAL_URLS.stream().anyMatch(remoteRepository.getUrl()::startsWith)) {
+ LOGGER.warn(
+ "Use of Maven Central as a CDN is against the Maven Central Terms of Service. Use MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR instead.",
+ new RuntimeException("Plugin used Maven Central for library resolution")
+ );
+ }
this.repositories.add(remoteRepository);
}
@@ -130,4 +151,15 @@ public class MavenLibraryResolver implements ClassPathLibrary {
store.addLibrary(file.toPath());
}
}
+
+ private static String getDefaultMavenCentralMirror() {
+ String central = System.getenv("PAPER_DEFAULT_CENTRAL_REPOSITORY");
+ if (central == null) {
+ central = System.getProperty("org.bukkit.plugin.java.LibraryLoader.centralURL");
+ }
+ if (central == null) {
+ central = "https://maven-central.storage-download.googleapis.com/maven2";
+ }
+ return central;
+ }
}
diff --git a/paper-api/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/paper-api/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
index c66252802c..c43cc85bb2 100644
--- a/paper-api/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
+++ b/paper-api/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
@@ -1,12 +1,12 @@
// CHECKSTYLE:OFF
package org.bukkit.plugin.java;
+import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -49,6 +49,10 @@ public class LibraryLoader
public static java.util.function.BiFunction LIBRARY_LOADER_FACTORY; // Paper - rewrite reflection in libraries
public static java.util.function.Function, List> REMAPPER; // Paper - remap libraries
+ private static List getRepositories() {
+ return List.of(new RemoteRepository.Builder("central", "default", MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR).build());
+ }
+
public LibraryLoader(@NotNull Logger logger)
{
this.logger = logger;
@@ -78,7 +82,7 @@ public class LibraryLoader
session.setSystemProperties( System.getProperties() );
session.setReadOnly();
- this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) );
+ this.repositories = repository.newResolutionRepositories( session, getRepositories() );
}
@Nullable