Skip to content

Commit

Permalink
fix(model-server): /history /content /diff and /repos always returned…
Browse files Browse the repository at this point in the history
… 401
  • Loading branch information
slisson committed Dec 11, 2024
1 parent 5aeb53b commit 693f3bd
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import kotlinx.html.tr
import kotlinx.html.ul
import kotlinx.html.unsafe
import org.modelix.authorization.checkPermission
import org.modelix.authorization.requiresLogin
import org.modelix.model.api.BuiltinLanguages
import org.modelix.model.api.INodeResolutionScope
import org.modelix.model.api.ITree
Expand All @@ -69,127 +70,129 @@ class ContentExplorer(private val repoManager: IRepositoriesManager) {
get("/content") {
call.respondRedirect("../repos/")
}
get("/content/repositories/{repository}/branches/{branch}/latest") {
val repository = call.parameters["repository"]
val branch = call.parameters["branch"]
if (repository.isNullOrEmpty()) {
call.respondText("repository not found", status = HttpStatusCode.BadRequest)
return@get
}
if (branch.isNullOrEmpty()) {
call.respondText("branch not found", status = HttpStatusCode.BadRequest)
return@get
}
call.checkPermission(ModelServerPermissionSchema.repository(repository).branch(branch).pull)
requiresLogin {
get("/content/repositories/{repository}/branches/{branch}/latest") {
val repository = call.parameters["repository"]
val branch = call.parameters["branch"]
if (repository.isNullOrEmpty()) {
call.respondText("repository not found", status = HttpStatusCode.BadRequest)
return@get
}
if (branch.isNullOrEmpty()) {
call.respondText("branch not found", status = HttpStatusCode.BadRequest)
return@get
}
call.checkPermission(ModelServerPermissionSchema.repository(repository).branch(branch).pull)

val latestVersion = repoManager.getVersion(BranchReference(RepositoryId(repository), branch))
if (latestVersion == null) {
call.respondText("unable to find latest version", status = HttpStatusCode.InternalServerError)
return@get
} else {
call.respondRedirect("../../../versions/${latestVersion.getContentHash()}/")
}
}
get("/content/repositories/{repository}/versions/{versionHash}") {
val repositoryId = call.parameters["repository"]?.let { RepositoryId(it) }
if (repositoryId == null) {
call.respondText("repository parameter missing", status = HttpStatusCode.BadRequest)
return@get
}
call.checkPermission(ModelServerPermissionSchema.repository(repositoryId).objects.read)
val versionHash = call.parameters["versionHash"]
if (versionHash.isNullOrEmpty()) {
call.respondText("version parameter missing", status = HttpStatusCode.BadRequest)
return@get
val latestVersion = repoManager.getVersion(BranchReference(RepositoryId(repository), branch))
if (latestVersion == null) {
call.respondText("unable to find latest version", status = HttpStatusCode.InternalServerError)
return@get
} else {
call.respondRedirect("../../../versions/${latestVersion.getContentHash()}/")
}
}
get("/content/repositories/{repository}/versions/{versionHash}") {
val repositoryId = call.parameters["repository"]?.let { RepositoryId(it) }
if (repositoryId == null) {
call.respondText("repository parameter missing", status = HttpStatusCode.BadRequest)
return@get
}
call.checkPermission(ModelServerPermissionSchema.repository(repositoryId).objects.read)
val versionHash = call.parameters["versionHash"]
if (versionHash.isNullOrEmpty()) {
call.respondText("version parameter missing", status = HttpStatusCode.BadRequest)
return@get
}

// IMPORTANT Do not let `expandTo` be an arbitrary string to avoid code injection.
// The value of `expandTo` is expanded into JavaScript.
val expandTo = call.request.queryParameters["expandTo"]?.let {
it.toLongOrNull() ?: return@get call.respondText("Invalid expandTo value. Provide a node id.", status = HttpStatusCode.BadRequest)
}
// IMPORTANT Do not let `expandTo` be an arbitrary string to avoid code injection.
// The value of `expandTo` is expanded into JavaScript.
val expandTo = call.request.queryParameters["expandTo"]?.let {
it.toLongOrNull() ?: return@get call.respondText("Invalid expandTo value. Provide a node id.", status = HttpStatusCode.BadRequest)
}

val tree = CLVersion.loadFromHash(versionHash, repoManager.getLegacyObjectStore(repositoryId)).getTree()
val rootNode = PNodeAdapter(ITree.ROOT_ID, TreePointer(tree))
val tree = CLVersion.loadFromHash(versionHash, repoManager.getLegacyObjectStore(repositoryId)).getTree()
val rootNode = PNodeAdapter(ITree.ROOT_ID, TreePointer(tree))

val expandedNodes = expandTo?.let { nodeId -> getAncestorsAndSelf(nodeId, tree) }.orEmpty()
val expandedNodes = expandTo?.let { nodeId -> getAncestorsAndSelf(nodeId, tree) }.orEmpty()

call.respondHtmlTemplate(PageWithMenuBar("repos/", "../../../../..")) {
headContent {
title("Content Explorer")
link("../../../../../public/content-explorer.css", rel = "stylesheet")
script("text/javascript", src = "../../../../../public/content-explorer.js") {}
if (expandTo != null) {
script("text/javascript") {
unsafe {
+"""
call.respondHtmlTemplate(PageWithMenuBar("repos/", "../../../../..")) {
headContent {
title("Content Explorer")
link("../../../../../public/content-explorer.css", rel = "stylesheet")
script("text/javascript", src = "../../../../../public/content-explorer.js") {}
if (expandTo != null) {
script("text/javascript") {
unsafe {
+"""
document.addEventListener("DOMContentLoaded", function(event) {
scrollToElement('$expandTo');
});
""".trimIndent()
""".trimIndent()
}
}
}
}
bodyContent { contentPageBody(rootNode, versionHash, expandedNodes, expandTo) }
}
bodyContent { contentPageBody(rootNode, versionHash, expandedNodes, expandTo) }
}
}
post("/content/repositories/{repository}/versions/{versionHash}") {
val repositoryId = call.parameters["repository"]?.let { RepositoryId(it) }
if (repositoryId == null) {
call.respondText("repository parameter missing", status = HttpStatusCode.BadRequest)
return@post
}
val versionHash = call.parameters["versionHash"]
if (versionHash.isNullOrEmpty()) {
call.respondText("version parameter missing", status = HttpStatusCode.BadRequest)
return@post
}
post("/content/repositories/{repository}/versions/{versionHash}") {
val repositoryId = call.parameters["repository"]?.let { RepositoryId(it) }
if (repositoryId == null) {
call.respondText("repository parameter missing", status = HttpStatusCode.BadRequest)
return@post
}
val versionHash = call.parameters["versionHash"]
if (versionHash.isNullOrEmpty()) {
call.respondText("version parameter missing", status = HttpStatusCode.BadRequest)
return@post
}

call.checkPermission(ModelServerPermissionSchema.repository(repositoryId).objects.read)
call.checkPermission(ModelServerPermissionSchema.repository(repositoryId).objects.read)

val expandedNodes = call.receive<ContentExplorerExpandedNodes>()
val expandedNodes = call.receive<ContentExplorerExpandedNodes>()

val tree = CLVersion.loadFromHash(versionHash, stores.getLegacyObjectStore(repositoryId)).getTree()
val rootNode = PNodeAdapter(ITree.ROOT_ID, TreePointer(tree))
val tree = CLVersion.loadFromHash(versionHash, stores.getLegacyObjectStore(repositoryId)).getTree()
val rootNode = PNodeAdapter(ITree.ROOT_ID, TreePointer(tree))

var expandedNodeIds = expandedNodes.expandedNodeIds
if (expandedNodes.expandAll) {
expandedNodeIds = expandedNodeIds + collectExpandableChildNodes(rootNode, expandedNodes.expandedNodeIds.toSet())
}
var expandedNodeIds = expandedNodes.expandedNodeIds
if (expandedNodes.expandAll) {
expandedNodeIds = expandedNodeIds + collectExpandableChildNodes(rootNode, expandedNodes.expandedNodeIds.toSet())
}

call.respondText(
buildString {
appendHTML().ul("treeRoot") {
nodeItem(rootNode, expandedNodeIds.toSet())
}
},
)
}
get("/content/repositories/{repository}/versions/{versionHash}/{nodeId}") {
val id = call.parameters["nodeId"]?.toLongOrNull()
?: return@get call.respondText("node id not found", status = HttpStatusCode.NotFound)
call.respondText(
buildString {
appendHTML().ul("treeRoot") {
nodeItem(rootNode, expandedNodeIds.toSet())
}
},
)
}
get("/content/repositories/{repository}/versions/{versionHash}/{nodeId}") {
val id = call.parameters["nodeId"]?.toLongOrNull()
?: return@get call.respondText("node id not found", status = HttpStatusCode.NotFound)

val versionHash = call.parameters["versionHash"]
?: return@get call.respondText("version hash not found", status = HttpStatusCode.NotFound)
val versionHash = call.parameters["versionHash"]
?: return@get call.respondText("version hash not found", status = HttpStatusCode.NotFound)

val repositoryId = call.parameters["repository"]
?: return@get call.respondText("repository parameter missing", status = HttpStatusCode.BadRequest)
val repositoryId = call.parameters["repository"]
?: return@get call.respondText("repository parameter missing", status = HttpStatusCode.BadRequest)

call.checkPermission(ModelServerPermissionSchema.repository(repositoryId).objects.read)
call.checkPermission(ModelServerPermissionSchema.repository(repositoryId).objects.read)

val version = try {
CLVersion.loadFromHash(versionHash, stores.getLegacyObjectStore(RepositoryId(repositoryId)))
} catch (ex: RuntimeException) {
return@get call.respondText("version not found", status = HttpStatusCode.NotFound)
}
val version = try {
CLVersion.loadFromHash(versionHash, stores.getLegacyObjectStore(RepositoryId(repositoryId)))
} catch (ex: RuntimeException) {
return@get call.respondText("version not found", status = HttpStatusCode.NotFound)
}

val node = PNodeAdapter(id, TreePointer(version.getTree())).takeIf { it.isValid }
val node = PNodeAdapter(id, TreePointer(version.getTree())).takeIf { it.isValid }

if (node != null) {
call.respondHtml { body { nodeInspector(node) } }
} else {
call.respondText("node id not found", status = HttpStatusCode.NotFound)
if (node != null) {
call.respondHtml { body { nodeInspector(node) } }
} else {
call.respondText("node id not found", status = HttpStatusCode.NotFound)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import kotlinx.html.thead
import kotlinx.html.tr
import org.modelix.authorization.checkPermission
import org.modelix.authorization.hasPermission
import org.modelix.authorization.requiresLogin
import org.modelix.model.api.BuiltinLanguages
import org.modelix.model.api.ITreeChangeVisitorEx
import org.modelix.model.lazy.CLTree
Expand Down Expand Up @@ -67,48 +68,50 @@ class DiffView(private val repositoryManager: RepositoriesManager) {
*/
fun init(application: Application) {
application.routing {
get("/diff") {
val visibleRepositories = repositoryManager.getRepositories().filter {
call.hasPermission(ModelServerPermissionSchema.repository(it).list)
}
call.respondHtmlTemplate(PageWithMenuBar("diff", "..")) {
bodyContent {
buildDiffInputPage(visibleRepositories)
requiresLogin {
get("/diff") {
val visibleRepositories = repositoryManager.getRepositories().filter {
call.hasPermission(ModelServerPermissionSchema.repository(it).list)
}
call.respondHtmlTemplate(PageWithMenuBar("diff", "..")) {
bodyContent {
buildDiffInputPage(visibleRepositories)
}
}
}
}
get("/diff/view") {
val repoId =
(call.request.queryParameters["repository"])?.let { param -> RepositoryId(param) } ?: throw HttpException(
get("/diff/view") {
val repoId =
(call.request.queryParameters["repository"])?.let { param -> RepositoryId(param) } ?: throw HttpException(
HttpStatusCode.BadRequest,
"missing repository",
)
call.checkPermission(ModelServerPermissionSchema.repository(repoId).objects.read)

val oldVersionHash = call.request.queryParameters["oldVersionHash"] ?: throw HttpException(
HttpStatusCode.BadRequest,
"missing oldVersionHash",
)
val newVersionHash = call.request.queryParameters["newVersionHash"] ?: throw HttpException(
HttpStatusCode.BadRequest,
"missing repository",
"missing newVersionHash",
)

val sizeLimit = call.request.queryParameters["sizeLimit"]?.let { param ->
param.toIntOrNull() ?: throw HttpException(HttpStatusCode.BadRequest, "invalid sizeLimit")
} ?: DEFAULT_SIZE_LIMIT

val oldVersion = repositoryManager.getVersion(repoId, oldVersionHash) ?: throw VersionNotFoundException(
oldVersionHash,
)
call.checkPermission(ModelServerPermissionSchema.repository(repoId).objects.read)

val oldVersionHash = call.request.queryParameters["oldVersionHash"] ?: throw HttpException(
HttpStatusCode.BadRequest,
"missing oldVersionHash",
)
val newVersionHash = call.request.queryParameters["newVersionHash"] ?: throw HttpException(
HttpStatusCode.BadRequest,
"missing newVersionHash",
)

val sizeLimit = call.request.queryParameters["sizeLimit"]?.let { param ->
param.toIntOrNull() ?: throw HttpException(HttpStatusCode.BadRequest, "invalid sizeLimit")
} ?: DEFAULT_SIZE_LIMIT

val oldVersion = repositoryManager.getVersion(repoId, oldVersionHash) ?: throw VersionNotFoundException(
oldVersionHash,
)
val newVersion = repositoryManager.getVersion(repoId, newVersionHash) ?: throw VersionNotFoundException(
newVersionHash,
)

val diff = calculateDiff(oldVersion, newVersion, sizeLimit)
call.respondHtmlTemplate(PageWithMenuBar("diff", baseUrl)) {
bodyContent {
buildDiffView(diff, oldVersionHash, newVersionHash, repoId.id, sizeLimit)
val newVersion = repositoryManager.getVersion(repoId, newVersionHash) ?: throw VersionNotFoundException(
newVersionHash,
)

val diff = calculateDiff(oldVersion, newVersion, sizeLimit)
call.respondHtmlTemplate(PageWithMenuBar("diff", baseUrl)) {
bodyContent {
buildDiffView(diff, oldVersionHash, newVersionHash, repoId.id, sizeLimit)
}
}
}
}
Expand Down
Loading

0 comments on commit 693f3bd

Please sign in to comment.