package space.anity import com.fizzed.rocker.* import com.fizzed.rocker.runtime.* import io.javalin.* import io.javalin.Handler import io.javalin.apibuilder.ApiBuilder.* import io.javalin.rendering.* import io.javalin.rendering.template.TemplateUtil.model import io.javalin.security.* import io.javalin.security.SecurityUtil.roles import java.net.* import java.util.logging.* import kotlin.system.* const val fileHome = "files" val databaseController = DatabaseController() val userHandler = UserHandler() val fileController = FileController() private val log = Logger.getLogger("App.kt") fun main(args: Array) { val app = startServer(args) // Set up templating RockerRuntime.getInstance().isReloading = false JavalinRenderer.register( FileRenderer { filepath, model -> Rocker.template(filepath).bind(model).render().toString() }, ".rocker.html" ) databaseController.initDatabase() app.routes { /** * Normalizes and cleans the requested url */ before("/*") { ctx -> if (URI(ctx.url()).normalize().toString() != ctx.url()) ctx.redirect(URI(ctx.url()).normalize().toString()) } /** * Renders the static resources (important for deployed jar files) */ get( "/css/*", { ctx -> ctx.contentType("text/css") ctx.result(Thread.currentThread().contextClassLoader.getResourceAsStream("css/" + ctx.splat(0))) }, roles(Roles.GUEST) ) get( "/js/*", { ctx -> ctx.contentType("text/js") ctx.result(Thread.currentThread().contextClassLoader.getResourceAsStream("js/" + ctx.splat(0))) }, roles(Roles.GUEST) ) get( "/fonts/*", { ctx -> ctx.result(Thread.currentThread().contextClassLoader.getResourceAsStream("fonts/" + ctx.splat(0))) }, roles(Roles.GUEST) ) /** * Main page */ get( "/", { ctx -> ctx.render( "index.rocker.html", model("username", databaseController.getUsername(userHandler.getVerifiedUserId(ctx))) ) }, roles(Roles.GUEST) ) /** * Renders the login page */ get("/user/login", { ctx -> if (userHandler.getVerifiedUserId(ctx) > 0 || !databaseController.isSetup()) ctx.redirect("/") else ctx.render( "login.rocker.html", model("message", "", "counter", 0) ) }, roles(Roles.GUEST)) /** * Endpoint for user authentication */ post("/user/login", userHandler::login, roles(Roles.GUEST)) /** * Logs the user out */ get("/user/logout", userHandler::logout, roles(Roles.USER)) /** * Renders the registration page */ get("/user/register", userHandler::renderRegistration, roles(Roles.GUEST)) // use setup page with additional parameter? /** * Registers new user */ post("/user/register", userHandler::register, roles(Roles.GUEST)) /** * Adds part of a new user (username) to database */ get("/user/add", databaseController::indexUserRegistration, roles(Roles.ADMIN)) // TODO: Create post request with admin interface /** * Renders the setup page (only on initial use) */ get("/setup", { ctx -> if (databaseController.isSetup()) ctx.redirect("/user/login") else ctx.render( "setup.rocker.html", model("message", "") ) }, roles(Roles.GUEST)) /** * Endpoint for setup (only on initial use) */ post("/setup", userHandler::setup, roles(Roles.GUEST)) /** * Renders the file list view */ get("/files/*", fileController::crawl, roles(Roles.USER)) /** * Receives and saves multipart media data */ post("/upload/*", fileController::upload, roles(Roles.USER)) /** * Deletes file */ post("/delete/*", fileController::delete, roles(Roles.USER)) /** * Shares file */ post("/share/*", fileController::share, roles(Roles.USER)) /** * Shares file in directory */ post("/share", fileController::handleSharedFile, roles(Roles.GUEST)) /** * Shows the shared file */ get("/shared", fileController::renderShared, roles(Roles.GUEST)) } } /** * Sets up the roles with the database and declares the handling of roles */ fun roleManager(handler: Handler, ctx: Context, permittedRoles: Set) { when { userHandler.getVerifiedUserId(ctx) == ctx.cookieStore("userId") ?: "userId" -> handler.handle(ctx) databaseController.getRoles(userHandler.getVerifiedUserId(ctx)).any { it in permittedRoles } -> handler.handle( ctx ) // ctx.host()!!.contains("localhost") -> handler.handle(ctx) // DEBUG else -> ctx.status(401).redirect("/user/login") } } /** * Starts the server and parses the command line arguments */ fun startServer(args: Array): Javalin { var runServer = true var port = 7000 args.forEachIndexed { index, element -> run { val wantsPort = element.startsWith("-p") || element.startsWith("--port") val wantsHelp = element.startsWith("-h") || element.startsWith("--help") if (wantsPort) { val portArgument = args[index + 1].toInt() if (portArgument in 1..65535) port = portArgument } else if (wantsHelp) { runServer = false log.info("Help:\nUse -p or --port to specify a port.") } } } return if (runServer) { try { Javalin.create().apply { port(port) accessManager { handler, ctx, permittedRoles -> roleManager(handler, ctx, permittedRoles) } disableStartupBanner() }.start() } catch (_: Exception) { log.warning("Port already in use!") exitProcess(1) } } else exitProcess(1) } /** * Declares the roles in which a user can be in */ enum class Roles : Role { ADMIN, USER, GUEST }