Stuff #1
14
src/main/kotlin/dev/frogmc/Config.kt
Normal file
14
src/main/kotlin/dev/frogmc/Config.kt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package dev.frogmc
|
||||||
|
|
||||||
|
object Config {
|
||||||
|
val POSTGRES_DATABASE = getEnv("DATABASE", "frogmc")
|
||||||
|
val POSTGRES_USER = getEnv("USER", "postgres")
|
||||||
|
val POSTGRES_PASSWORD = getEnv("PASSWORD", "example")
|
||||||
|
val POSTGRES_HOST = getEnv("HOST", "localhost")
|
||||||
|
val POSTGRES_PORT = getEnv("PORT", "5432")
|
||||||
|
val UPLOAD_SECRET = getEnv("UPLOAD_SECRET", "").toByteArray()
|
||||||
|
|
||||||
|
private fun getEnv(key: String, default: String): String {
|
||||||
|
return System.getenv("FROGMC_META_$key") ?: default
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,18 +14,12 @@ object DB {
|
||||||
fun init(): Boolean {
|
fun init(): Boolean {
|
||||||
// use postgresql
|
// use postgresql
|
||||||
try {
|
try {
|
||||||
val database = getEnv("FROGMC_META_DATABASE", "frogmc")
|
|
||||||
val user = getEnv("FROGMC_META_USER", "postgres")
|
|
||||||
val password = getEnv("FROGMC_META_PASSWORD", "example")
|
|
||||||
val host = getEnv("FROGMC_META_HOST", "localhost")
|
|
||||||
val port = getEnv("FROGMC_META_PORT", "5432")
|
|
||||||
|
|
||||||
logger.info("Connecting to the database...")
|
logger.info("Connecting to the database...")
|
||||||
val d = Database.connect(
|
val d = Database.connect(
|
||||||
url = "jdbc:postgresql://$host:$port/$database",
|
url = "jdbc:postgresql://${Config.POSTGRES_HOST}:${Config.POSTGRES_PORT}/${Config.POSTGRES_DATABASE}",
|
||||||
driver = "org.postgresql.Driver",
|
driver = "org.postgresql.Driver",
|
||||||
user,
|
Config.POSTGRES_USER,
|
||||||
password
|
Config.POSTGRES_PASSWORD
|
||||||
)
|
)
|
||||||
db = d
|
db = d
|
||||||
transaction(db) {
|
transaction(db) {
|
||||||
|
@ -45,10 +39,6 @@ object DB {
|
||||||
logger.error(e.stackTraceToString())
|
logger.error(e.stackTraceToString())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (db == null) {
|
|
||||||
logger.error("Failed to connect to the database.")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
logger.info(db!!.name)
|
logger.info(db!!.name)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
16
src/main/kotlin/dev/frogmc/plugins/Auth.kt
Normal file
16
src/main/kotlin/dev/frogmc/plugins/Auth.kt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.frogmc.plugins
|
||||||
|
|
||||||
|
import dev.frogmc.Config
|
||||||
|
import io.ktor.http.*
|
||||||
|
import io.ktor.server.application.*
|
||||||
|
import io.ktor.server.response.*
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
|
val authPlugin = createRouteScopedPlugin("auth") {
|
||||||
|
onCall {
|
||||||
|
val authorization = it.request.headers["Authorization"]
|
||||||
|
if (authorization.isNullOrEmpty() || !MessageDigest.isEqual(authorization.toByteArray(), Config.UPLOAD_SECRET))
|
||||||
|
it.respond(HttpStatusCode.Unauthorized);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.frogmc.plugins
|
package dev.frogmc.plugins
|
||||||
|
|
||||||
import dev.frogmc.DB
|
import dev.frogmc.DB
|
||||||
|
import dev.frogmc.types.LoaderVersion
|
||||||
|
import dev.frogmc.types.LoaderVersions
|
||||||
import dev.frogmc.types.ModrinthVersion
|
import dev.frogmc.types.ModrinthVersion
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.call.*
|
import io.ktor.client.call.*
|
||||||
|
@ -9,14 +11,17 @@ import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.html.*
|
import io.ktor.server.html.*
|
||||||
import io.ktor.server.http.content.*
|
import io.ktor.server.http.content.*
|
||||||
|
import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
||||||
fun BODY.route(block: DIV.() -> Unit) =
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
div(classes = "route", block)
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
|
import org.jetbrains.exposed.sql.insert
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
|
||||||
fun Application.configureRouting() {
|
fun Application.configureRouting() {
|
||||||
routing {
|
routing {
|
||||||
|
@ -55,6 +60,16 @@ fun Application.configureRouting() {
|
||||||
p { +"Fetches the download URL of a specific version of FrogMC loader." }
|
p { +"Fetches the download URL of a specific version of FrogMC loader." }
|
||||||
}
|
}
|
||||||
br()
|
br()
|
||||||
|
div(classes = "route") {
|
||||||
|
code { +"POST /v1/loader/versions" }
|
||||||
|
p { +"Uploads a version of the loader. This endpoint requires authorization." }
|
||||||
|
}
|
||||||
|
br()
|
||||||
|
div(classes = "route") {
|
||||||
|
code { +"DELETE /v1/loader/versions/{version}" }
|
||||||
|
p { +"Deletes a version of the loader. This endpoint requires authorization." }
|
||||||
|
}
|
||||||
|
br()
|
||||||
div(classes = "route") {
|
div(classes = "route") {
|
||||||
code { +"GET /v1/library/versions" }
|
code { +"GET /v1/library/versions" }
|
||||||
p { +"Fetches all versions of FrogMC library." }
|
p { +"Fetches all versions of FrogMC library." }
|
||||||
|
@ -89,10 +104,7 @@ fun Application.configureRouting() {
|
||||||
call.respond(versions.first())
|
call.respond(versions.first())
|
||||||
}
|
}
|
||||||
get("/versions/{version}/download") {
|
get("/versions/{version}/download") {
|
||||||
val version = call.parameters["version"] ?: return@get call.respond(
|
val version = call.parameters["version"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
HttpStatusCode.BadRequest,
|
|
||||||
"message" to "Invalid version."
|
|
||||||
)
|
|
||||||
val versions = DB.getLoaderVersions()
|
val versions = DB.getLoaderVersions()
|
||||||
val versionObj = versions.find { it.version == version } ?: return@get call.respond(
|
val versionObj = versions.find { it.version == version } ?: return@get call.respond(
|
||||||
HttpStatusCode.NotFound,
|
HttpStatusCode.NotFound,
|
||||||
|
@ -101,17 +113,45 @@ fun Application.configureRouting() {
|
||||||
call.respond("url" to versionObj.downloadUrl)
|
call.respond("url" to versionObj.downloadUrl)
|
||||||
}
|
}
|
||||||
get("/versions/{version}") {
|
get("/versions/{version}") {
|
||||||
val version = call.parameters["version"] ?: return@get call.respond(
|
val version = call.parameters["version"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
HttpStatusCode.BadRequest,
|
|
||||||
"message" to "Invalid version."
|
|
||||||
)
|
|
||||||
val versions = DB.getLoaderVersions()
|
val versions = DB.getLoaderVersions()
|
||||||
val versionObj = versions.find { it.version == version } ?: return@get call.respond(
|
val versionObj =
|
||||||
HttpStatusCode.NotFound,
|
versions.find { it.version == version } ?: return@get call.respond(HttpStatusCode.NotFound)
|
||||||
"message" to "Version not found."
|
|
||||||
)
|
|
||||||
call.respond(versionObj)
|
call.respond(versionObj)
|
||||||
}
|
}
|
||||||
|
route("/versions") {
|
||||||
|
install(authPlugin)
|
||||||
|
post {
|
||||||
|
val versionObj = call.receive<LoaderVersion>()
|
||||||
|
|
||||||
|
try {
|
||||||
|
transaction {
|
||||||
|
LoaderVersions.insert {
|
||||||
|
it[version] = versionObj.version
|
||||||
|
it[releaseDate] = versionObj.releaseDate
|
||||||
|
it[downloadUrl] = versionObj.downloadUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: ExposedSQLException) { // TODO: this catches EVERYTHING
|
||||||
|
call.respond(HttpStatusCode.Conflict)
|
||||||
|
return@post
|
||||||
|
}
|
||||||
|
call.respond(HttpStatusCode.OK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route("/versions/{version}") {
|
||||||
|
install(authPlugin)
|
||||||
|
delete {
|
||||||
|
val version =
|
||||||
|
call.parameters["version"] ?: return@delete call.respond(HttpStatusCode.BadRequest)
|
||||||
|
transaction {
|
||||||
|
LoaderVersions.deleteWhere {
|
||||||
|
LoaderVersions.version eq version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
call.respond(HttpStatusCode.OK)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
route("/library") {
|
route("/library") {
|
||||||
get("/versions") {
|
get("/versions") {
|
||||||
|
|
Loading…
Reference in a new issue