Skip to content
Permalink
Browse files

Merge pull request #1 from codeoverflow-org/master

Merge master
  • Loading branch information...
derNiklaas committed Jun 11, 2019
2 parents ba3cbc7 + 45dacb8 commit b485e15b798af48189b1830f94e31cce388408f2
@@ -14,9 +14,11 @@ class ScalatraBootstrap extends LifeCycle {
implicit val swagger: CodeOverflowSwagger = new CodeOverflowSwagger(apiVersion)

override def init(context: ServletContext) {

// Allow CORS
context.initParameters("org.scalatra.cors.allowedOrigins") = "*"
context.initParameters("org.scalatra.cors.allowCredentials") = "false"
context.initParameters("org.scalatra.cors.allowedMethods") = "*"

// Add all servlets and controller
context.mount(new TypeController(), "/types/*", "types")
@@ -15,6 +15,7 @@ import scala.collection.mutable.ListBuffer
*/
class PluginManagerImpl(pluginInstanceName: String, logOutputOnConsole: Boolean) extends PluginManager with WithLogger {

// TODO: Add log datetime
private val logMessages = new ListBuffer[String]

/**
@@ -75,7 +75,7 @@ object CLI {
case class Config(pluginFolderPath: String = "plugins/",
configFolderPath: String = "config/",
requirementPackage: String = "org.codeoverflow.chatoverflow.requirement",
ui: UI = UI.BOTH,
ui: UI = UI.GUI,
requirePasswordOnStartup: Boolean = true,
pluginDataPath: String = "data",
webServerPort: Int = 2400,
@@ -5,7 +5,7 @@ import org.codeoverflow.chatoverflow.ui.web.rest.DTOs.ResultMessage
import org.codeoverflow.chatoverflow.{ChatOverflow, Launcher}
import org.json4s.{DefaultFormats, Formats}
import org.scalatra.json.JacksonJsonSupport
import org.scalatra.{CorsSupport, ScalatraServlet}
import org.scalatra.{BadRequest, CorsSupport, ScalatraServlet, Unauthorized}

/**
* A Json Servlet enables implicit json conversion for servlet output.
@@ -19,6 +19,14 @@ abstract class JsonServlet extends ScalatraServlet with JacksonJsonSupport with
contentType = formats("json")
}

// CORS support (preflight requests)
options("/*") {
response.setHeader(
"Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"))
response.setHeader(
"Access-Control-Allow-Methods", request.getHeader("Access-Control-Request-Method"))
}

/**
* Utility function to parse incoming json-body-arguments. Uses a lot of scala magic. Magical!
*
@@ -45,4 +53,23 @@ abstract class JsonServlet extends ScalatraServlet with JacksonJsonSupport with
}
}
}

/**
* Utility function to test the authKey-existence in header first.
*
* @param func the function to execute, if the authorization was successful
* @param request the request, implicitly provided by the scalatra environment
* @return the result of the provided func or an http error if the auth key is wrong
*/
protected def authKeyRequired(func: => Any)(implicit request: HttpServletRequest): Any = {
val authKeyKey = "authKey"

if (request.header(authKeyKey).isEmpty) {
BadRequest()
} else if (request.header(authKeyKey).get != chatOverflow.credentialsService.generateAuthKey()) {
Unauthorized()
} else {
func
}
}
}
@@ -1,8 +1,5 @@
package org.codeoverflow.chatoverflow.ui.web

import java.awt.Desktop
import java.net.URL

import org.codeoverflow.chatoverflow.{ChatOverflow, WithLogger}
import org.eclipse.jetty.servlet.ServletHandler.Default404Servlet
import org.eclipse.jetty.webapp.WebAppContext
@@ -33,13 +30,8 @@ class Server(val chatOverflow: ChatOverflow, val port: Int) extends WithLogger {
// TODO: Enable shutting down the server
new Thread(() => startServer()).start()

// TODO: Replace this with the proper GUI, when available
try {
val petstoreURL = s"http://petstore.swagger.io/?url=http://localhost:$port/api-docs/swagger.json"
Desktop.getDesktop.browse(new URL(petstoreURL).toURI)
} catch {
case _: Exception => logger debug "Unable to open GUI in browser."
}
println(s"You may open now: http://petstore.swagger.io/?url=http://localhost:$port/api-docs/swagger.json")
println("Or try out the new gui: http://localhost:2400")
}

private def startServer(): Unit = {
@@ -0,0 +1,10 @@
package org.codeoverflow.chatoverflow.ui.web.rest

import org.scalatra.swagger.{SwaggerSupport, SwaggerSupportSyntax}

trait AuthSupport extends SwaggerSupport {

protected def authHeader: SwaggerSupportSyntax.ParameterBuilder[String] =
headerParam[String]("authKey").description("connection auth key required")

}
@@ -43,6 +43,4 @@ object DTOs {

case class Password(password: String)

case class AuthKey(authKey: String)

}
@@ -4,7 +4,7 @@ import org.codeoverflow.chatoverflow.Launcher
import org.codeoverflow.chatoverflow.api.APIVersion
import org.codeoverflow.chatoverflow.configuration.CryptoUtil
import org.codeoverflow.chatoverflow.ui.web.JsonServlet
import org.codeoverflow.chatoverflow.ui.web.rest.DTOs.{AuthKey, ConfigInfo, Password, ResultMessage}
import org.codeoverflow.chatoverflow.ui.web.rest.DTOs.{ConfigInfo, Password, ResultMessage}
import org.scalatra.swagger._

class ConfigController(implicit val swagger: Swagger) extends JsonServlet with ConfigControllerDefinition {
@@ -16,29 +16,25 @@ class ConfigController(implicit val swagger: Swagger) extends JsonServlet with C
}

post("/save", operation(postSave)) {
if (!chatOverflow.isLoaded) {
false
} else {
chatOverflow.save()
true
authKeyRequired {
if (!chatOverflow.isLoaded) {
false
} else {
chatOverflow.save()
true
}
}
}

// Is this even a thing?
post("/exit", operation(postExit)) {
parsedAs[AuthKey] {
case AuthKey(authKey) =>
if (authKey != chatOverflow.credentialsService.generateAuthKey()) {
ResultMessage(success = false, "Wrong auth key.")

} else {
// Give enough time to return success. Then bye bye
new Thread(() => {
Thread.sleep(500)
Launcher.exit()
}).start()
ResultMessage(success = true)
}
authKeyRequired {
// Give enough time to return success. Then bye bye
new Thread(() => {
Thread.sleep(500)
Launcher.exit()
}).start()
ResultMessage(success = true)
}
}

@@ -1,11 +1,11 @@
package org.codeoverflow.chatoverflow.ui.web.rest.config

import org.codeoverflow.chatoverflow.ui.web.rest.DTOs.{AuthKey, ConfigInfo, Password, ResultMessage}
import org.codeoverflow.chatoverflow.ui.web.rest.TagSupport
import org.codeoverflow.chatoverflow.ui.web.rest.DTOs.{ConfigInfo, Password, ResultMessage}
import org.codeoverflow.chatoverflow.ui.web.rest.{AuthSupport, TagSupport}
import org.scalatra.swagger.SwaggerSupport
import org.scalatra.swagger.SwaggerSupportSyntax.OperationBuilder

trait ConfigControllerDefinition extends SwaggerSupport with TagSupport {
trait ConfigControllerDefinition extends SwaggerSupport with TagSupport with AuthSupport {

val getConfig: OperationBuilder =
(apiOperation[ConfigInfo]("getConfig")
@@ -16,13 +16,14 @@ trait ConfigControllerDefinition extends SwaggerSupport with TagSupport {
(apiOperation[Boolean]("postSave")
summary "Triggers the saving process of the framework manually (if loaded previously)."
description "Triggers saving of credentials and configuration. Should not be needed manually."
parameter authHeader
tags controllerTag)
val postExit: OperationBuilder =
(apiOperation[ResultMessage]("postExit")
summary "Shuts the framework down."
description "Shutdown the framework in the next second if a correct auth key is supplied."
tags controllerTag
parameter bodyParam[AuthKey]("body").description("Requires the run specific auth key."))
parameter authHeader
tags controllerTag)
val getLogin: OperationBuilder =
(apiOperation[Boolean]("getLogin")
summary "Returns if the framework is already loaded."

0 comments on commit b485e15

Please sign in to comment.
You can’t perform that action at this time.