From 62b7f86dae659deb2fc450285452d7c1439f92dc Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:47:21 -0700 Subject: [PATCH] Avoid and discourage use of Maven Central as a CDN (#12689) * 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 --- .../library/impl/MavenLibraryResolver.java | 34 ++++++++++++++++++- .../org/bukkit/plugin/java/LibraryLoader.java | 15 ++------ 2 files changed, 35 insertions(+), 14 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 107705db2d8..c1fccd64b13 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 7e4e702845f..a9cbd3d6cc0 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,11 +1,11 @@ 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; @@ -29,7 +29,6 @@ import org.eclipse.aether.resolution.DependencyResult; import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; import org.eclipse.aether.spi.connector.transport.TransporterFactory; import org.eclipse.aether.transfer.AbstractTransferListener; -import org.eclipse.aether.transfer.TransferCancelledException; import org.eclipse.aether.transfer.TransferEvent; import org.eclipse.aether.transport.http.HttpTransporterFactory; import org.jetbrains.annotations.NotNull; @@ -47,18 +46,8 @@ 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 - // TODO: Consider moving this and adding per plugin support for defining repositories private static List getRepositories() { - 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://repo.maven.apache.org/maven2"; - } - - return Arrays.asList(new RemoteRepository.Builder("central", "default", central).build()); - + return List.of(new RemoteRepository.Builder("central", "default", MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR).build()); } public LibraryLoader(@NotNull Logger logger) {