diff --git a/Dockerfile b/Dockerfile index a4c2b8abc..f7ad65528 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,12 @@ -FROM openjdk:15-alpine +FROM eclipse-temurin:17-jdk as build-java +COPY reposilite-backend /root/project +COPY gradlew /root/project/gradlew +COPY gradle /root/project/gradle +WORKDIR /root/project +RUN chmod +x ./gradlew +RUN ./gradlew shadowJar --no-daemon + +FROM openjdk:17-alpine # Build-time metadata stage ARG BUILD_DATE @@ -19,5 +27,5 @@ RUN apk add --no-cache mailcap WORKDIR /app RUN mkdir -p /app/data VOLUME /app/data -COPY ./reposilite-backend/build/libs/reposilite*-all.jar reposilite.jar +COPY --from=build-java /root/project/build/libs/reposilite*-all.jar reposilite.jar ENTRYPOINT exec java $JAVA_OPTS -jar reposilite.jar -wd=/app/data $REPOSILITE_OPTS diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ffed3a254..98debb84d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/reposilite-backend/build.gradle b/reposilite-backend/build.gradle index f0f8049cb..199b74a17 100644 --- a/reposilite-backend/build.gradle +++ b/reposilite-backend/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'com.github.johnrengelman.shadow' version '7.0.0' - id 'net.minecraftforge.gradleutils' version '1.+' + id 'com.github.johnrengelman.shadow' version '7.1.2' + id 'net.minecraftforge.gradleutils' version '2.+' id 'java' id 'groovy' id 'maven-publish' diff --git a/reposilite-backend/settings.gradle b/reposilite-backend/settings.gradle new file mode 100644 index 000000000..3703f364a --- /dev/null +++ b/reposilite-backend/settings.gradle @@ -0,0 +1,6 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { url = 'https://maven.minecraftforge.net/' } + } +} \ No newline at end of file diff --git a/reposilite-backend/src/main/java/org/panda_lang/reposilite/config/Configuration.java b/reposilite-backend/src/main/java/org/panda_lang/reposilite/config/Configuration.java index 47eb9801e..6360c37bd 100644 --- a/reposilite-backend/src/main/java/org/panda_lang/reposilite/config/Configuration.java +++ b/reposilite-backend/src/main/java/org/panda_lang/reposilite/config/Configuration.java @@ -89,7 +89,7 @@ public final class Configuration { @Description({ "", "# Repositories, in the order in which they will be searched.", - "# Repository names must mete the following criteria:", + "# Repository names must meet the following criteria:", "# No '-': This denotes a suffix for filtering.", "# Lowercase: To prevent ambiguity in requests.", "# Neither `releases` or `snapshots`: Reserved for multi-repo views.", @@ -101,10 +101,10 @@ public final class Configuration { "# # Prefix of paths that this repo will allow.", "# # May be empty to allow all paths", "# prefixes: []", - "# # Wither or not this repo requires authentication to read.", + "# # Whether or not this repo requires authentication to read.", "# hidden: false", - "# # Weither this repo can be browsed by non-autheticated users.", - "# beowseable: true", + "# # Whether this repo can be browsed by non-authenticated users.", + "# browseable: true", "# # Allow users with write access to upload.", "# allowUploads: true", "# # Control the maximum amount of data assigned to this repository.", @@ -112,12 +112,12 @@ public final class Configuration { "# diskQuota: \"\"", "# # List of remote repositories to proxy", "# # Files not found locally will be attempted to be found", - "# # in the following reposiories. And cached locally.", + "# # in the following repositories. And cached locally.", "# proxies: []", "# # Repository name to delegate requests to, if this one does not ", "# # have the requested file. This can not be used with 'proxies'.", "# # This is mainly intended to allow proxied files to be stored in", - "# # a seperate repo for organiztion.", + "# # a separate repo for organization.", "# delegate: \"\"", "# }", "# }" diff --git a/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/DeployService.java b/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/DeployService.java index 30820ef19..717fa7274 100644 --- a/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/DeployService.java +++ b/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/DeployService.java @@ -97,11 +97,6 @@ public Result>, ErrorDto> dep Reposilite.getLogger().info("DEPLOY " + authResult.get().getAlias() + " successfully deployed " + file + " from " + context.address()); - //TODO: Remove this when we remove metadata service - if (file.getName().contains("maven-metadata")) { - return Result.ok(CompletableFuture.completedFuture(Result.ok(fileDetails))); - } - //TODO: Design a better API for this, so we don't have to cast to internal types. CompletableFuture> task = ((RepositoryManager)repos).storeFile( uri, diff --git a/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/LookupService.java b/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/LookupService.java index f2219ccea..d412ca877 100644 --- a/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/LookupService.java +++ b/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/LookupService.java @@ -87,17 +87,36 @@ Result findFile(ReposiliteContext context) { if (filtered.isEmpty()) return ResponseUtils.error(SC_NOT_FOUND, "Can not find repo at: " + context.uri()); + // Filter out repos the user can't see + List visibleRepos = new ArrayList<>(); + for (IRepository repo : filtered) { + if (!repo.isHidden()) { + visibleRepos.add(repo); + } else { + Result auth = context.session('/' + repo.getName() + '/' + context.filepath()); + if (auth.isOk() && auth.get().hasAnyPermission(Permission.READ, Permission.WRITE, Permission.MANAGER)) { + visibleRepos.add(repo); + } + } + } + + if (visibleRepos.isEmpty()) { + // The user can't see any of repos that may contain the file, so tell them the file doesn't exist + return ResponseUtils.error(SC_NOT_FOUND, "File not found"); + } + // TODO: File hashes if (filtered.size() > 1 && isMeta) { - byte[] meta = metadataService.mergeMetadata(context.sanitized(), context.filepath(), filtered); + byte[] meta = metadataService.mergeMetadata(context.sanitized(), context.filepath(), visibleRepos); if (meta != null) return Result.ok(new LookupResponse("text/xml", meta)); } - return findFile(context, parts, isMeta, false, filtered.size() > 1 ? new HashSet<>() : null, filtered, 0, null); + return findFile(context, parts, isMeta, false, visibleRepos.size() > 1 ? new HashSet<>() : null, visibleRepos, 0, null); } - private Result findFile(ReposiliteContext context, String[] parts, boolean isMeta, boolean isExplicit, Set visited, List repos, int index, IRepository repo) { + private Result findFile(ReposiliteContext context, String[] parts, boolean isMeta, boolean isExplicit, Set visited, List repos, int index, + IRepository repo) { if (repo == null) repo = repos.get(index); diff --git a/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/MetadataService.java b/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/MetadataService.java index 4c74a5c01..7c6517167 100644 --- a/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/MetadataService.java +++ b/reposilite-backend/src/main/java/org/panda_lang/reposilite/repository/MetadataService.java @@ -16,6 +16,9 @@ package org.panda_lang.reposilite.repository; +import com.google.common.collect.ImmutableSet; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; import org.apache.maven.artifact.repository.metadata.Metadata; import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer; @@ -32,18 +35,18 @@ import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; public final class MetadataService implements ReposiliteConfiguration { private final MetadataXpp3Reader XML_READER = new MetadataXpp3Reader(); private final MetadataXpp3Writer XML_WRITER = new MetadataXpp3Writer(); - //TODO: Threading issues? Use Concurrent maps? - private final Map cache = new HashMap<>(); - private final Map> cacheInputs = new HashMap<>(); + private final Map>, CacheEntry> cache = new ConcurrentHashMap<>(); + private final Map> cacheInputs = new ConcurrentHashMap<>(); private final BiConsumer errorHandler; public MetadataService(BiConsumer errorHandler) { @@ -63,11 +66,14 @@ public MetadataService(BiConsumer errorHandler) { * 3) Maven Plugin Group: /group/maven-metadata.xml * This I dont think we can generate... So request from the proxy, or 404 */ - public byte[] mergeMetadata(String key, String filepath, List repos) { + public byte[] mergeMetadata(String key, String filepath, List reposList) { if (!filepath.endsWith("/maven-metadata.xml")) throw new IllegalArgumentException("Invalid maven-metadata.xml filename: " + filepath); - CacheEntry cached = cache.get(key); + // Different people can have access to different repos. + // This can affect the versions that are available to them, so we need to reflect this when checking the cache. + Set repos = ImmutableSet.copyOf(reposList); + CacheEntry cached = cache.get(ImmutablePair.of(key, repos)); if (cached != null) return cached.data; @@ -87,7 +93,7 @@ public byte[] mergeMetadata(String key, String filepath, List repos if (existing.size() == 1) { try { - return addCache(key, Files.readAllBytes(existing.get(0).toPath()), inputs); + return addCache(key, Files.readAllBytes(existing.get(0).toPath()), inputs, repos); } catch (IOException e) { return null; // TODO: Actually do something about this error? } @@ -117,12 +123,12 @@ public byte[] mergeMetadata(String key, String filepath, List repos return null; } - return addCache(key, bos.toByteArray(), inputs); + return addCache(key, bos.toByteArray(), inputs, repos); } - private byte[] addCache(String key, byte[] data, List inputs) { - CacheEntry entry = new CacheEntry(key, data, inputs); - cache.put(key, entry); + private byte[] addCache(String key, byte[] data, List inputs, Set repos) { + CacheEntry entry = new CacheEntry(key, data, inputs, repos); + cache.put(ImmutablePair.of(key, repos), entry); for (String input : inputs) cacheInputs.computeIfAbsent(input, k -> new ArrayList<>()).add(entry); @@ -134,7 +140,7 @@ public void clearMetadata(File file) { List entries = cacheInputs.remove(key); if (entries != null) { for (CacheEntry ent : entries) { - cache.remove(ent.path); + cache.remove(ImmutablePair.of(ent.path, ent.repos)); ent.inputs.remove(key); for (String input : ent.inputs) { List child = cacheInputs.get(input); @@ -176,10 +182,13 @@ private static class CacheEntry { final String path; final byte[] data; final List inputs; - private CacheEntry(String path, byte[] data, List inputs) { + final Set repos; + + private CacheEntry(String path, byte[] data, List inputs, Set repos) { this.path = path; this.data = data; this.inputs = inputs; + this.repos = repos; } } }