diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/frontend/FrontendFacade.kt b/reposilite-backend/src/main/kotlin/com/reposilite/frontend/FrontendFacade.kt index a99fce746..ab3be327f 100644 --- a/reposilite-backend/src/main/kotlin/com/reposilite/frontend/FrontendFacade.kt +++ b/reposilite-backend/src/main/kotlin/com/reposilite/frontend/FrontendFacade.kt @@ -29,7 +29,7 @@ class FrontendFacade internal constructor( ) : Facade { private val resources = HashMap(0) - private val formattedBasePath = basePath.computed { BasePathFormatter.formatBasePath(it) } + val formattedBasePath = basePath.computed { BasePathFormatter.formatBasePath(it) } init { computed(basePath, formattedBasePath, frontendSettings) { diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/maven/MavenFacade.kt b/reposilite-backend/src/main/kotlin/com/reposilite/maven/MavenFacade.kt index 2f01ab2db..e789c2d97 100644 --- a/reposilite-backend/src/main/kotlin/com/reposilite/maven/MavenFacade.kt +++ b/reposilite-backend/src/main/kotlin/com/reposilite/maven/MavenFacade.kt @@ -37,6 +37,7 @@ import com.reposilite.storage.api.FileDetails import com.reposilite.storage.api.Location import com.reposilite.token.AccessTokenIdentifier import panda.std.Result +import java.io.InputStream class MavenFacade internal constructor( private val journalist: Journalist, @@ -54,6 +55,9 @@ class MavenFacade internal constructor( fun findFile(lookupRequest: LookupRequest): Result = repositoryService.findFile(lookupRequest) + fun findData(lookupRequest: LookupRequest): Result = + repositoryService.findInputStream(lookupRequest) + fun deployFile(deployRequest: DeployRequest): Result = repositoryService.deployFile(deployRequest) @@ -84,10 +88,24 @@ class MavenFacade internal constructor( handler = handler ) + fun getAvailableFiles(request: LookupRequest, directoryInfo: DirectoryInfo): List = + getRepository(request.repository)!!.let { repository -> + directoryInfo.files.filter { + repositorySecurityProvider.canBrowseResource( + accessToken = request.accessToken, + repository = repository, + gav = request.gav.resolve(it.name) + ).isOk + } + } + fun createLatestBadge(lookupRequest: LatestBadgeRequest): Result = findLatestVersion(lookupRequest.toVersionLookupRequest()) .flatMap { latestService.createLatestBadge(lookupRequest, it.version) } + fun acceptsCachingOf(request: LookupRequest): Boolean = + getRepository(request.repository)?.acceptsCachingOf(request.gav) ?: false + fun canAccessResource(accessToken: AccessTokenIdentifier?, repository: Repository, gav: Location): Result = repositorySecurityProvider.canAccessResource(accessToken, repository, gav) diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/maven/RepositoryService.kt b/reposilite-backend/src/main/kotlin/com/reposilite/maven/RepositoryService.kt index 4b5fd64c7..4293dba4b 100644 --- a/reposilite-backend/src/main/kotlin/com/reposilite/maven/RepositoryService.kt +++ b/reposilite-backend/src/main/kotlin/com/reposilite/maven/RepositoryService.kt @@ -27,7 +27,6 @@ import com.reposilite.maven.api.ResolvedDocument import com.reposilite.maven.api.ResolvedFileEvent import com.reposilite.plugin.Extensions import com.reposilite.shared.ErrorResponse -import com.reposilite.shared.badRequestError import com.reposilite.shared.errorResponse import com.reposilite.shared.notFound import com.reposilite.shared.notFoundError @@ -114,8 +113,7 @@ internal class RepositoryService( fun findFile(lookupRequest: LookupRequest): Result = resolve(lookupRequest) { repository, gav -> - findFile(lookupRequest.accessToken, repository, gav).map { - val (details, stream) = it + findFile(lookupRequest.accessToken, repository, gav).map { (details, stream) -> ResolvedDocument( document = details, cachable = repository.acceptsCachingOf(gav), @@ -144,6 +142,9 @@ internal class RepositoryService( .flatMap { details -> findInputStream(repository, gav).map { details to it } } .let { extensions.emitEvent(ResolvedFileEvent(accessToken, repository, gav, it)).result } + fun findInputStream(lookupRequest: LookupRequest): Result = + resolve(lookupRequest) { repository, gav -> findInputStream(repository, gav) } + private fun findInputStream(repository: Repository, gav: Location): Result = when { mirrorService.shouldPrioritizeMirrorRepository(repository, gav) -> { diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/maven/infrastructure/DirectoryIndexPage.kt b/reposilite-backend/src/main/kotlin/com/reposilite/maven/infrastructure/DirectoryIndexPage.kt new file mode 100644 index 000000000..43a5682fd --- /dev/null +++ b/reposilite-backend/src/main/kotlin/com/reposilite/maven/infrastructure/DirectoryIndexPage.kt @@ -0,0 +1,48 @@ +package com.reposilite.maven.infrastructure + +import com.reposilite.storage.api.FileDetails +import com.reposilite.storage.api.FileType + +internal fun createDirectoryIndexPage(basePath: String, uri: String, authenticatedFiles: List): String { + val formattedUri = basePath + uri.removePrefix("/") + + // language=html + return """ + + + + Index of $formattedUri + + + + +

Index of $formattedUri

+ + + + """.trimIndent() +} \ No newline at end of file diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/maven/infrastructure/MavenEndpoints.kt b/reposilite-backend/src/main/kotlin/com/reposilite/maven/infrastructure/MavenEndpoints.kt index 8ff3e7c92..047d7564d 100644 --- a/reposilite-backend/src/main/kotlin/com/reposilite/maven/infrastructure/MavenEndpoints.kt +++ b/reposilite-backend/src/main/kotlin/com/reposilite/maven/infrastructure/MavenEndpoints.kt @@ -21,8 +21,12 @@ import com.reposilite.maven.MavenFacade import com.reposilite.maven.api.DeleteRequest import com.reposilite.maven.api.DeployRequest import com.reposilite.maven.api.LookupRequest +import com.reposilite.shared.ErrorResponse import com.reposilite.shared.extensions.resultAttachment import com.reposilite.shared.extensions.uri +import com.reposilite.storage.api.DirectoryInfo +import com.reposilite.storage.api.DocumentInfo +import com.reposilite.storage.api.FileType import com.reposilite.storage.api.Location import com.reposilite.token.AccessTokenIdentifier import com.reposilite.web.api.ReposiliteRoute @@ -31,6 +35,7 @@ import io.javalin.community.routing.Route.GET import io.javalin.community.routing.Route.HEAD import io.javalin.community.routing.Route.POST import io.javalin.community.routing.Route.PUT +import io.javalin.http.ContentType import io.javalin.http.Context import io.javalin.openapi.ContentType.FORM_DATA_MULTIPART import io.javalin.openapi.HttpMethod @@ -38,6 +43,7 @@ import io.javalin.openapi.OpenApi import io.javalin.openapi.OpenApiContent import io.javalin.openapi.OpenApiParam import io.javalin.openapi.OpenApiResponse +import panda.std.Result const val X_GENERATE_CHECKSUMS = "X-Generate-Checksums" @@ -70,25 +76,43 @@ internal class MavenEndpoints( } } - fun findFile(ctx: Context, identifier: AccessTokenIdentifier?, repository: String, gav: Location) { - LookupRequest(identifier, repository, gav) - .let { request -> mavenFacade.findFile(request) } - .peek { - ctx.resultAttachment( - name = it.document.name, - contentType = it.document.contentType, - contentLength = it.document.contentLength, - lastTimeModified = it.document.lastModifiedTime, - compressionStrategy = compressionStrategy, - cache = it.cachable, - data = it.content - ) - } - .onError { - ctx.status(it.status).html(frontendFacade.createNotFoundPage(ctx.uri(), it.message)) - mavenFacade.logger.debug("FIND | Could not find file due to $it") - } - } + fun findFile(ctx: Context, identifier: AccessTokenIdentifier?, repository: String, gav: Location): Result = + LookupRequest(accessToken = identifier, repository = repository, gav = gav).let { request -> + mavenFacade + .findDetails(request) + .map { details -> + when (details) { + is DocumentInfo -> + mavenFacade + .findData(request) + .peek { + ctx.resultAttachment( + name = details.name, + contentType = details.contentType, + contentLength = details.contentLength, + lastTimeModified = details.lastModifiedTime, + compressionStrategy = compressionStrategy, + cache = mavenFacade.acceptsCachingOf(request), + data = it, + ) + } + is DirectoryInfo -> + ctx.html( + createDirectoryIndexPage( + basePath = frontendFacade.formattedBasePath.get(), + uri = ctx.uri(), + authenticatedFiles = mavenFacade.getAvailableFiles(request, details), + ) + ) + else -> + throw IllegalStateException("Expected file details, but got $details") + } + } + .onError { + ctx.status(it.status).html(frontendFacade.createNotFoundPage(ctx.uri(), it.message)) + mavenFacade.logger.debug("FIND | Could not find file due to $it") + } + } @OpenApi( tags = [ "Maven" ],