Skip to content

Commit

Permalink
GH-458 Simplify 'web' domain and move infrastructure to the dedicated…
Browse files Browse the repository at this point in the history
… layer
  • Loading branch information
dzikoysk committed Jun 26, 2021
1 parent 21896b9 commit ab45483
Show file tree
Hide file tree
Showing 32 changed files with 274 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import org.panda_lang.reposilite.shared.CachedLogger
import org.panda_lang.reposilite.shared.TimeUtils
import org.panda_lang.reposilite.statistics.StatisticsFacade
import org.panda_lang.reposilite.token.AccessTokenFacade
import org.panda_lang.reposilite.web.application.HttpServerConfiguration
import org.panda_lang.reposilite.web.ReposiliteContextFactory
import org.panda_lang.reposilite.web.WebServer
import org.panda_lang.utilities.commons.console.Effect
import java.nio.file.Path
import java.util.concurrent.atomic.AtomicBoolean
Expand All @@ -42,18 +42,17 @@ class Reposilite(
val configuration: Configuration,
val workingDirectory: Path,
val testEnv: Boolean,
val webServer: WebServer,
val contextFactory: ReposiliteContextFactory,
val failureFacade: FailureFacade,
val authenticationFacade: AuthenticationFacade,
val mavenFacade: MavenFacade,
val consoleFacade: ConsoleFacade,
val accessTokenFacade: AccessTokenFacade,
val frontendFacade: FrontendFacade,
val statisitcsFacade: StatisticsFacade,
val statisticsFacade: StatisticsFacade,
) : Journalist {

internal val httpServer = HttpServerConfiguration(this, false)

val cachedLogger = CachedLogger(Channel.ALL, configuration.cachedLogSize)
private val logger = AggregatedLogger(logger, cachedLogger)

Expand Down Expand Up @@ -96,7 +95,7 @@ class Reposilite(

try {
logger.info("Binding server at ${configuration.hostname}::${configuration.port}")
httpServer.start(configuration)
webServer.start(this)
Runtime.getRuntime().addShutdownHook(shutdownHook)

logger.info("Done (" + TimeUtils.format(getUptime() / 1000.0) + "s)!")
Expand Down Expand Up @@ -125,7 +124,7 @@ class Reposilite(

logger.info("Shutting down ${configuration.hostname}::${configuration.port} ...")
ReposiliteWebConfiguration.dispose(this)
httpServer.stop()
webServer.stop()
}

fun getUptime(): Long =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.panda_lang.reposilite

import io.javalin.Javalin
import net.dzikoysk.dynamiclogger.Journalist
import org.panda_lang.reposilite.auth.application.AuthenticationWebConfiguration
import org.panda_lang.reposilite.config.Configuration
Expand All @@ -26,14 +27,16 @@ import org.panda_lang.reposilite.maven.application.MavenWebConfiguration
import org.panda_lang.reposilite.statistics.application.StatisticsWebConfiguration
import org.panda_lang.reposilite.token.application.AccessTokenWebConfiguration
import org.panda_lang.reposilite.web.ReposiliteContextFactory
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.application.WebConfiguration
import java.nio.file.Path

object ReposiliteWebConfiguration {

fun createReposilite(journalist: Journalist, configuration: Configuration, workingDirectory: Path, testEnv: Boolean): Reposilite {
val logger = journalist.logger

val webServer = WebConfiguration.createWebServer()
val failureFacade = FailureWebConfiguration.createFacade(logger)
val consoleFacade = ConsoleWebConfiguration.createFacade(logger, failureFacade)
val mavenFacade = MavenWebConfiguration.createFacade(logger, failureFacade, configuration.repositories)
Expand All @@ -48,14 +51,15 @@ object ReposiliteWebConfiguration {
configuration = configuration,
workingDirectory = workingDirectory,
testEnv = testEnv,
webServer = webServer,
failureFacade = failureFacade,
contextFactory = contextFactory,
authenticationFacade = authenticationFacade,
mavenFacade = mavenFacade,
consoleFacade = consoleFacade,
accessTokenFacade = accessTokenFacade,
frontendFacade = frontendFacade,
statisitcsFacade = statisticFacade
statisticsFacade = statisticFacade
)
}

Expand All @@ -66,22 +70,28 @@ object ReposiliteWebConfiguration {
// MavenWebConfiguration.initialize()
// FrontendWebConfiguration.initialize()
// MavenWebConfiguration.initialize()
StatisticsWebConfiguration.initialize(reposilite.statisitcsFacade, reposilite.consoleFacade)
StatisticsWebConfiguration.initialize(reposilite.statisticsFacade, reposilite.consoleFacade)
AccessTokenWebConfiguration.initialize(reposilite.accessTokenFacade, reposilite.consoleFacade)
}

fun routing(reposilite: Reposilite): Collection<RouteHandler> =
setOf(
AuthenticationWebConfiguration.routing(reposilite.authenticationFacade),
ConsoleWebConfiguration.routing(reposilite.httpServer.javalin!!, reposilite),
FailureWebConfiguration.routing(reposilite.httpServer.javalin!!, reposilite.failureFacade),
ConsoleWebConfiguration.routing(reposilite),
FailureWebConfiguration.routing(),
FrontendWebConfiguration.routing(reposilite.frontendFacade),
MavenWebConfiguration.routing(reposilite.contextFactory, reposilite.mavenFacade),
StatisticsWebConfiguration.routing(reposilite.statisitcsFacade),
StatisticsWebConfiguration.routing(reposilite.statisticsFacade),
// AccessTokenWebConfiguration.routing(),
)
.flatten()

// TOFIX: Remove dependency on infrastructure details
fun javalin(reposilite: Reposilite, javalin: Javalin) {
ConsoleWebConfiguration.javalin(javalin, reposilite)
FailureWebConfiguration.javalin(javalin, reposilite.failureFacade)
}

fun dispose(reposilite: Reposilite) {
ConsoleWebConfiguration.dispose(reposilite.consoleFacade)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.panda_lang.reposilite.auth.infrastructure.AuthenticationEndpoint
import org.panda_lang.reposilite.auth.infrastructure.PostAuthHandler
import org.panda_lang.reposilite.maven.MavenFacade
import org.panda_lang.reposilite.token.AccessTokenFacade
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.api.RouteHandler

internal object AuthenticationWebConfiguration {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import io.javalin.http.Context
import org.panda_lang.reposilite.auth.AuthenticationFacade
import org.panda_lang.reposilite.auth.api.AuthenticationResponse
import org.panda_lang.reposilite.failure.api.ErrorResponse
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.RouteMethod.GET
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.RouteMethod.GET

private const val ROUTE = "/api/auth"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ package org.panda_lang.reposilite.auth.infrastructure

import io.javalin.http.Context
import io.javalin.http.HttpCode
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.RouteMethod.AFTER
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.RouteMethod.AFTER

private const val WWW_AUTHENTICATE = "www-authenticate"
private const val WWW_BASIC_REALM = """Basic realm="Reposilite", charset="UTF-8" """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ internal class StatusCommand(
else getVersion()

output.add("Reposilite $VERSION Status")
output.add(" Active: $GREEN_BOLD${reposilite.httpServer.isAlive()}$RESET")
output.add(" Active: $GREEN_BOLD${reposilite.webServer.isAlive()}$RESET")
output.add(" Uptime: ${format(reposilite.getUptime() / 1000.0 / 60.0)}min")
output.add(" Memory usage of process: ${memoryUsage()}")
output.add(" Exceptions: ${reposilite.failureFacade.getFailures().size}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import org.panda_lang.reposilite.console.VersionCommand
import org.panda_lang.reposilite.console.infrastructure.CliEndpoint
import org.panda_lang.reposilite.console.infrastructure.RemoteExecutionEndpoint
import org.panda_lang.reposilite.failure.FailureFacade
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.api.RouteHandler

private const val REMOTE_VERSION = "https://repo.panda-lang.org/org/panda-lang/reposilite/latest"

Expand All @@ -51,12 +51,13 @@ internal object ConsoleWebConfiguration {
}
}

fun routing(javalin: Javalin, reposilite: Reposilite): List<RouteHandler> {
javalin.ws("/api/cli", CliEndpoint(reposilite.contextFactory, reposilite.authenticationFacade, reposilite.consoleFacade, reposilite.cachedLogger))

return listOf(
fun routing(reposilite: Reposilite): List<RouteHandler> =
listOf(
RemoteExecutionEndpoint(reposilite.contextFactory, reposilite.consoleFacade)
)

fun javalin(javalin: Javalin, reposilite: Reposilite) {
javalin.ws("/api/cli", CliEndpoint(reposilite.contextFactory, reposilite.authenticationFacade, reposilite.consoleFacade, reposilite.cachedLogger))
}

fun dispose(consoleFacade: ConsoleFacade) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import org.panda_lang.reposilite.console.api.ExecutionResponse
import org.panda_lang.reposilite.failure.api.ErrorResponse
import org.panda_lang.reposilite.failure.api.errorResponse
import org.panda_lang.reposilite.web.ReposiliteContextFactory
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.RouteMethod.POST
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.RouteMethod.POST
import org.panda_lang.reposilite.web.context

private const val ROUTE = "/api/execute"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.panda_lang.reposilite.console.ConsoleFacade
import org.panda_lang.reposilite.failure.FailureFacade
import org.panda_lang.reposilite.failure.FailuresCommand
import org.panda_lang.reposilite.failure.infrastructure.FailureHandler
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.api.RouteHandler

internal object FailureWebConfiguration {

Expand All @@ -33,9 +33,11 @@ internal object FailureWebConfiguration {
consoleFacade.registerCommand(FailuresCommand(failureFacade))
}

fun routing(javalin: Javalin, failureFacade: FailureFacade): List<RouteHandler> {
fun routing(): List<RouteHandler> =
listOf()

fun javalin(javalin: Javalin, failureFacade: FailureFacade) {
javalin.exception(Exception::class.java, FailureHandler(failureFacade))
return emptyList()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package org.panda_lang.reposilite.frontend.application
import org.panda_lang.reposilite.config.Configuration
import org.panda_lang.reposilite.frontend.FrontendFacade
import org.panda_lang.reposilite.frontend.infrastructure.FrontendHandler
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.api.RouteHandler

internal object FrontendWebConfiguration {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import com.dzikoysk.openapi.annotations.OpenApi
import com.dzikoysk.openapi.annotations.OpenApiResponse
import io.javalin.http.Context
import org.panda_lang.reposilite.frontend.FrontendFacade
import org.panda_lang.reposilite.web.RouteHandler
import org.panda_lang.reposilite.web.RouteMethod.GET
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.RouteMethod.GET

internal class FrontendHandler(private val frontendFacade: FrontendFacade) : RouteHandler {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,34 @@
package org.panda_lang.reposilite.maven

import io.javalin.http.HttpCode.NOT_FOUND
import io.javalin.http.HttpCode.UNAUTHORIZED
import org.panda_lang.reposilite.failure.api.ErrorResponse
import org.panda_lang.reposilite.failure.api.errorResponse
import org.panda_lang.reposilite.maven.api.LookupRequest
import org.panda_lang.reposilite.maven.api.LookupResponse
import org.panda_lang.reposilite.maven.api.Repository
import org.panda_lang.reposilite.web.orNull
import org.panda_lang.utilities.commons.function.Result
import java.nio.file.Path

internal class LookupService(
private val repositoryService: RepositoryService
private val repositoryService: RepositoryService,
private val repositorySecurityProvider: RepositorySecurityProvider
) {

fun lookup(lookupRequest: LookupRequest): Result<LookupResponse, ErrorResponse> {
val repository = repositoryService.getRepository(lookupRequest.repository) ?: return errorResponse(NOT_FOUND, "Repository not found")
val gav = Path.of(lookupRequest.gav)

return repository.getFileDetails(lookupRequest.gav)
.flatMap {
repository.getFile(lookupRequest.gav)
.map { data -> Pair(it, data) }
}
.map { LookupResponse(it.first, it.second) }
if (repository.isDirectory(gav) && repositorySecurityProvider.canBrowseResource(lookupRequest.accessToken, repository, gav).not()) {
return errorResponse(UNAUTHORIZED, "Unauthorized indexing request")
}
else if (repositorySecurityProvider.canAccessResource(lookupRequest.accessToken, repository, gav).not()) {
return errorResponse(UNAUTHORIZED, "Unauthorized access request")
}

return repository.getFileDetails(gav)
.map { LookupResponse(it, repository.getFile(lookupRequest.gav).orNull()) }
}

fun findAllRepositories(): Collection<Repository> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.panda_lang.reposilite.failure.FailureFacade
import org.panda_lang.reposilite.failure.api.ErrorResponse
import org.panda_lang.reposilite.failure.api.errorResponse
import org.panda_lang.reposilite.maven.api.FileDetails
import org.panda_lang.reposilite.maven.api.FileType
import org.panda_lang.reposilite.maven.api.LookupResponse
import org.panda_lang.reposilite.maven.api.Repository
import org.panda_lang.reposilite.maven.api.RepositoryVisibility.PRIVATE
Expand Down Expand Up @@ -123,7 +124,7 @@ internal class ProxyService(

val contentLength = Option.of(remoteResponse.headers.contentLength).orElseGet(0L)
val path = remoteUri.split("/").toTypedArray()
val fileDetails = FileDetails(FileDetails.FILE, path.last(), "", remoteResponse.contentType, contentLength)
val fileDetails = FileDetails(FileType.FILE, path.last(), remoteResponse.contentType, contentLength)
val lookupResponse = LookupResponse(fileDetails, remoteResponse.content)

Result.ok(lookupResponse)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.panda_lang.reposilite.maven

import org.panda_lang.reposilite.maven.api.Repository
import org.panda_lang.reposilite.maven.api.RepositoryVisibility.HIDDEN
import org.panda_lang.reposilite.maven.api.RepositoryVisibility.PRIVATE
import org.panda_lang.reposilite.maven.api.RepositoryVisibility.PUBLIC
import org.panda_lang.reposilite.token.api.AccessToken
import org.panda_lang.reposilite.token.api.Permission.READ
import java.nio.file.Path

internal class RepositorySecurityProvider {

fun canAccessResource(accessToken: AccessToken?, repository: Repository, gav: Path): Boolean =
when (repository.visibility) {
PUBLIC -> true
HIDDEN -> true
PRIVATE -> hasPermissionTo(accessToken, gav)
}

fun canBrowseResource(accessToken: AccessToken?, repository: Repository, gav: Path): Boolean =
when (repository.visibility) {
PUBLIC -> true
HIDDEN -> hasPermissionTo(accessToken, gav)
PRIVATE -> hasPermissionTo(accessToken, gav)
}

private fun hasPermissionTo(accessToken: AccessToken?, gav: Path): Boolean =
accessToken?.hasPermissionTo(gav.toString(), READ) ?: false

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,25 @@
*/
package org.panda_lang.reposilite.maven.api

import com.fasterxml.jackson.annotation.JsonIgnore
import org.panda_lang.reposilite.shared.FilesUtils
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Locale

enum class FileType {
FILE,
DIRECTORY
}

data class FileListResponse(
val files: List<FileDetails>
)

data class FileDetails(
val type: String,
val type: FileType,
val name: String,
val date: String,
val contentType: String,
val contentLength: Long
val contentType: String? = null,
val contentLength: Long? = null
) : Comparable<FileDetails> {

companion object {
const val FILE = "file"
const val DIRECTORY = "directory"

val DATE_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
.withLocale(Locale.getDefault())
.withZone(ZoneId.systemDefault())
}

override fun compareTo(other: FileDetails): Int {
var result = type.compareTo(other.type)

Expand All @@ -51,10 +44,8 @@ data class FileDetails(
return result
}

@JsonIgnore
fun isReadable(): Boolean =
FilesUtils.isReadable(name)

fun isDirectory(): Boolean =
DIRECTORY == type

}
Loading

0 comments on commit ab45483

Please sign in to comment.