Add public token generation

This commit is contained in:
2026-04-26 19:48:42 +02:00
parent 1c6b127543
commit 02b92ff134
5 changed files with 110 additions and 15 deletions

View File

@@ -0,0 +1,20 @@
package sh.rhiobet.lalafin.file.access;
import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection
public class FileToken {
public String user;
public long timestamp;
public String ip;
public String file;
public FileToken() {}
public FileToken(String user, long timestamp, String ip, String file) {
this.user = user;
this.timestamp = timestamp;
this.ip = ip;
this.file = file;
}
}

View File

@@ -0,0 +1,34 @@
package sh.rhiobet.lalafin.file.access;
import java.util.UUID;
import io.quarkus.redis.datasource.RedisDataSource;
import io.quarkus.redis.datasource.value.SetArgs;
import io.quarkus.security.identity.SecurityIdentity;
import io.vertx.core.http.HttpServerRequest;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class FileTokenProvider {
@Inject
RedisDataSource redisDataSource;
@Inject
SecurityIdentity securityIdentity;
@Inject
HttpServerRequest request;
public String getFileToken(String fileUri) {
FileToken token = new FileToken(this.securityIdentity.getPrincipal().getName(),
System.currentTimeMillis(), this.request.remoteAddress().host(), fileUri);
String uniqueID = UUID.randomUUID().toString();
this.redisDataSource.value(FileToken.class).set(
"fileToken-" + uniqueID, token, new SetArgs().pxAt(System.currentTimeMillis() + 86400000));
return uniqueID;
}
}

View File

@@ -11,7 +11,7 @@ public class FileInfo extends FileInfoBase {
this.publicApiUrl = publicApiUrl; this.publicApiUrl = publicApiUrl;
} }
public FileInfo(String filename, String directUrl) { public FileInfo(String filename, String directUrl, String publicApiUrl) {
this(filename, "", directUrl, ""); this(filename, "", directUrl, publicApiUrl);
} }
} }

View File

@@ -7,7 +7,6 @@ import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import sh.rhiobet.lalafin.LalafinConfiguration; import sh.rhiobet.lalafin.LalafinConfiguration;
import sh.rhiobet.lalafin.api.internal.redis.FileTokenProvider;
import sh.rhiobet.lalafin.core.path.model.Path; import sh.rhiobet.lalafin.core.path.model.Path;
import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver; import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver;
import sh.rhiobet.lalafin.core.thumbnail.ThumbnailGenerator; import sh.rhiobet.lalafin.core.thumbnail.ThumbnailGenerator;
@@ -29,11 +28,15 @@ public class FileMetadataService {
@Named("file/resolver/thumbnail") @Named("file/resolver/thumbnail")
PathURIResolver fileThumbnailURIResolver; PathURIResolver fileThumbnailURIResolver;
@Inject
@Named("file/resolver/token")
PathURIResolver fileTokenURIResolver;
@Inject @Inject
@Named("file/thumbnail") @Named("file/thumbnail")
ThumbnailGenerator fileThumbnailGenerator; ThumbnailGenerator fileThumbnailGenerator;
public FileInfoBase getInfo(Path filePath, FileTokenProvider fileTokenProvider) { public FileInfoBase getInfo(Path filePath) {
if (filePath.exists()) { if (filePath.exists()) {
Optional<String> fileUrl = this.fileURIResolver.resolve(filePath); Optional<String> fileUrl = this.fileURIResolver.resolve(filePath);
Optional<String> thumbUrl = this.fileThumbnailURIResolver.resolve(filePath); Optional<String> thumbUrl = this.fileThumbnailURIResolver.resolve(filePath);
@@ -57,16 +60,13 @@ public class FileMetadataService {
try { try {
for (Path child : filePath.getChildren()) { for (Path child : filePath.getChildren()) {
if (child.getFilename().startsWith(".")) { if (child.getFilename().startsWith(".") ||
fileConfiguration.ignored().isPresent() &&
fileConfiguration.ignored().get().stream()
.anyMatch(i -> child.getFilename().endsWith(i)))
{
continue; continue;
} }
if (fileConfiguration.ignored().isPresent()) {
for (String ignoreString : fileConfiguration.ignored().get()) {
if (child.getFilename().endsWith(ignoreString)) {
continue;
}
}
}
Optional<String> childFileUrl = this.fileURIResolver.resolve(child); Optional<String> childFileUrl = this.fileURIResolver.resolve(child);
Optional<String> childThumbUrl = this.fileThumbnailURIResolver.resolve(child); Optional<String> childThumbUrl = this.fileThumbnailURIResolver.resolve(child);
@@ -85,8 +85,12 @@ public class FileMetadataService {
contentInfo = new FolderInfo(child.getFilename(), contentInfo = new FolderInfo(child.getFilename(),
childFileUrl.isPresent() ? childFileUrl.get() : ""); childFileUrl.isPresent() ? childFileUrl.get() : "");
} else { } else {
contentInfo = new FileInfo(child.getFilename(), Optional<String> childTokenUrl = this.fileTokenURIResolver.resolve(child);
childFileUrl.isPresent() ? childFileUrl.get() : ""); contentInfo = new FileInfo(
child.getFilename(),
childFileUrl.isPresent() ? childFileUrl.get() : "",
childTokenUrl.isPresent() ? childTokenUrl.get() : ""
);
} }
if (childThumbUrl.isPresent()) { if (childThumbUrl.isPresent()) {
@@ -101,11 +105,12 @@ public class FileMetadataService {
return folderInfo; return folderInfo;
} else { } else {
Optional<String> tokenUrl = this.fileTokenURIResolver.resolve(filePath);
FileInfo fileInfo = new FileInfo( FileInfo fileInfo = new FileInfo(
filePath.getFilename(), filePath.getFilename(),
thumbUrl.isPresent() ? thumbUrl.get() : "", thumbUrl.isPresent() ? thumbUrl.get() : "",
fileUrl.isPresent() ? fileUrl.get() : "", fileUrl.isPresent() ? fileUrl.get() : "",
"" tokenUrl.isPresent() ? tokenUrl.get() : ""
); );
return fileInfo; return fileInfo;

View File

@@ -0,0 +1,36 @@
package sh.rhiobet.lalafin.file.resolver;
import java.util.Optional;
import org.jboss.resteasy.reactive.common.util.Encode;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import sh.rhiobet.lalafin.core.path.model.Path;
import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver;
import sh.rhiobet.lalafin.file.access.FileTokenProvider;
@ApplicationScoped
@Named("file/resolver/token")
public class FileTokenURIResolver implements PathURIResolver {
@Inject
@Named("file/resolver")
PathURIResolver fileURIResolver;
@Inject
FileTokenProvider fileTokenProvider;
@Override
public Optional<String> resolve(Path path) {
Optional<String> fileURI = this.fileURIResolver.resolve(path);
if (fileURI.isPresent()) {
return Optional.of(
"/v1/api/public/file/token/" + this.fileTokenProvider.getFileToken(fileURI.get()) + "/"
+ Encode.encodePathSegment(path.getFilename()));
}
return Optional.empty();
}
}