Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions reposilite-backend/build.gradle
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
6 changes: 6 additions & 0 deletions reposilite-backend/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven { url = 'https://maven.minecraftforge.net/' }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand All @@ -101,23 +101,23 @@ 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.",
"# # May be null/empty to use the global quota.",
"# 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: \"\"",
"# }",
"# }"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,6 @@ public Result<CompletableFuture<Result<FileDetailsDto, ErrorDto>>, 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<Result<FileDetailsDto, ErrorDto>> task = ((RepositoryManager)repos).storeFile(
uri,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,36 @@ Result<LookupResponse, ErrorDto> 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<IRepository> visibleRepos = new ArrayList<>();
for (IRepository repo : filtered) {
if (!repo.isHidden()) {
visibleRepos.add(repo);
} else {
Result<Session, String> 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<LookupResponse, ErrorDto> findFile(ReposiliteContext context, String[] parts, boolean isMeta, boolean isExplicit, Set<String> visited, List<IRepository> repos, int index, IRepository repo) {
private Result<LookupResponse, ErrorDto> findFile(ReposiliteContext context, String[] parts, boolean isMeta, boolean isExplicit, Set<String> visited, List<IRepository> repos, int index,
IRepository repo) {
if (repo == null)
repo = repos.get(index);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<String, CacheEntry> cache = new HashMap<>();
private final Map<String, List<CacheEntry>> cacheInputs = new HashMap<>();
private final Map<Pair<String, Set<IRepository>>, CacheEntry> cache = new ConcurrentHashMap<>();
private final Map<String, List<CacheEntry>> cacheInputs = new ConcurrentHashMap<>();
private final BiConsumer<String, Exception> errorHandler;

public MetadataService(BiConsumer<String, Exception> errorHandler) {
Expand All @@ -63,11 +66,14 @@ public MetadataService(BiConsumer<String, Exception> 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<IRepository> repos) {
public byte[] mergeMetadata(String key, String filepath, List<IRepository> 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<IRepository> repos = ImmutableSet.copyOf(reposList);
CacheEntry cached = cache.get(ImmutablePair.of(key, repos));
if (cached != null)
return cached.data;

Expand All @@ -87,7 +93,7 @@ public byte[] mergeMetadata(String key, String filepath, List<IRepository> 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?
}
Expand Down Expand Up @@ -117,12 +123,12 @@ public byte[] mergeMetadata(String key, String filepath, List<IRepository> repos
return null;
}

return addCache(key, bos.toByteArray(), inputs);
return addCache(key, bos.toByteArray(), inputs, repos);
}

private byte[] addCache(String key, byte[] data, List<String> inputs) {
CacheEntry entry = new CacheEntry(key, data, inputs);
cache.put(key, entry);
private byte[] addCache(String key, byte[] data, List<String> inputs, Set<IRepository> 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);

Expand All @@ -134,7 +140,7 @@ public void clearMetadata(File file) {
List<CacheEntry> 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<CacheEntry> child = cacheInputs.get(input);
Expand Down Expand Up @@ -176,10 +182,13 @@ private static class CacheEntry {
final String path;
final byte[] data;
final List<String> inputs;
private CacheEntry(String path, byte[] data, List<String> inputs) {
final Set<IRepository> repos;

private CacheEntry(String path, byte[] data, List<String> inputs, Set<IRepository> repos) {
this.path = path;
this.data = data;
this.inputs = inputs;
this.repos = repos;
}
}
}