mirror of
https://github.com/librecaptcha/lc-core.git
synced 2025-01-13 06:53:19 -05:00
Improve Error handling/messages (#82)
* Add image error fields Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Update models Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Improve error handling/messages Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Minor reformat Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Improve error handling Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Add base trait Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Decouple data access methods Improve error handling Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Minor reformat Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Add pattern matching to handle error Remove try except blocks Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
This commit is contained in:
parent
3a1b01688a
commit
43331f8dd7
@ -25,7 +25,7 @@ class BackgroundTask(throttle: Int, timeLimit: Int) {
|
|||||||
Captcha.generateChallenge(Parameters("medium", "image/png", "text", Option(Size(0, 0))))
|
Captcha.generateChallenge(Parameters("medium", "image/png", "text", Option(Size(0, 0))))
|
||||||
throttleIn -= 1
|
throttleIn -= 1
|
||||||
}
|
}
|
||||||
} catch { case exception: Exception => println(exception.getStackTrace()) }
|
} catch { case exception: Exception => println(exception) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,34 +5,59 @@ import java.util.UUID
|
|||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import lc.database.Statements
|
import lc.database.Statements
|
||||||
import lc.core.CaptchaProviders
|
import lc.core.CaptchaProviders
|
||||||
|
import lc.captchas.interfaces.ChallengeProvider
|
||||||
|
import lc.captchas.interfaces.Challenge
|
||||||
|
import java.sql.Blob
|
||||||
|
|
||||||
object Captcha {
|
object Captcha {
|
||||||
|
|
||||||
def getCaptcha(id: Id): Array[Byte] = {
|
def getCaptcha(id: Id): Either[Error, Image] = {
|
||||||
var image: Array[Byte] = null
|
val blob = getImage(id.id)
|
||||||
try {
|
blob match {
|
||||||
val imagePstmt = Statements.tlStmts.get.imagePstmt
|
case Some(value) => {
|
||||||
imagePstmt.setString(1, id.id)
|
|
||||||
val rs: ResultSet = imagePstmt.executeQuery()
|
|
||||||
if (rs.next()) {
|
|
||||||
val blob = rs.getBlob("image")
|
|
||||||
if (blob != null) {
|
if (blob != null) {
|
||||||
image = blob.getBytes(1, blob.length().toInt)
|
Right(Image(value.getBytes(1, value.length().toInt)))
|
||||||
|
} else {
|
||||||
|
Left(Error(ErrorMessageEnum.IMG_MISSING.toString))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
image
|
case None => Left(Error(ErrorMessageEnum.IMG_NOT_FOUND.toString))
|
||||||
} catch {
|
|
||||||
case e: Exception =>
|
|
||||||
println(e)
|
|
||||||
image
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateChallenge(param: Parameters): Int = {
|
private def getImage(id: String): Option[Blob] = {
|
||||||
|
val imagePstmt = Statements.tlStmts.get.imagePstmt
|
||||||
|
imagePstmt.setString(1, id)
|
||||||
|
val rs: ResultSet = imagePstmt.executeQuery()
|
||||||
|
if (rs.next()) {
|
||||||
|
Some(rs.getBlob("image"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def generateChallenge(param: Parameters): Option[Int] = {
|
||||||
val provider = CaptchaProviders.getProvider(param)
|
val provider = CaptchaProviders.getProvider(param)
|
||||||
val providerId = provider.getId()
|
provider match {
|
||||||
val challenge = provider.returnChallenge()
|
case Some(value) => {
|
||||||
val blob = new ByteArrayInputStream(challenge.content)
|
val providerId = value.getId()
|
||||||
|
val challenge = value.returnChallenge()
|
||||||
|
val blob = new ByteArrayInputStream(challenge.content)
|
||||||
|
val token = insertCaptcha(value, challenge, providerId, param, blob)
|
||||||
|
// println("Added new challenge: " + token.toString)
|
||||||
|
token.map(_.toInt)
|
||||||
|
}
|
||||||
|
case None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def insertCaptcha(
|
||||||
|
provider: ChallengeProvider,
|
||||||
|
challenge: Challenge,
|
||||||
|
providerId: String,
|
||||||
|
param: Parameters,
|
||||||
|
blob: ByteArrayInputStream
|
||||||
|
): Option[Int] = {
|
||||||
val insertPstmt = Statements.tlStmts.get.insertPstmt
|
val insertPstmt = Statements.tlStmts.get.insertPstmt
|
||||||
insertPstmt.setString(1, provider.getId)
|
insertPstmt.setString(1, provider.getId)
|
||||||
insertPstmt.setString(2, challenge.secret)
|
insertPstmt.setString(2, challenge.secret)
|
||||||
@ -43,63 +68,65 @@ object Captcha {
|
|||||||
insertPstmt.setBlob(7, blob)
|
insertPstmt.setBlob(7, blob)
|
||||||
insertPstmt.executeUpdate()
|
insertPstmt.executeUpdate()
|
||||||
val rs: ResultSet = insertPstmt.getGeneratedKeys()
|
val rs: ResultSet = insertPstmt.getGeneratedKeys()
|
||||||
val token = if (rs.next()) {
|
if (rs.next()) {
|
||||||
rs.getInt("token")
|
Some(rs.getInt("token"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
// println("Added new challenge: " + token.toString)
|
|
||||||
token.asInstanceOf[Int]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val allowedInputType = Config.allowedInputType
|
val allowedInputType = Config.allowedInputType
|
||||||
val allowedLevels = Config.allowedLevels
|
val allowedLevels = Config.allowedLevels
|
||||||
val allowedMedia = Config.allowedMedia
|
val allowedMedia = Config.allowedMedia
|
||||||
|
|
||||||
private def validateParam(param: Parameters): Boolean = {
|
private def validateParam(param: Parameters): Array[String] = {
|
||||||
if (
|
var invalid_params = Array[String]()
|
||||||
allowedLevels.contains(param.level) &&
|
if (!allowedLevels.contains(param.level)) invalid_params :+= "level"
|
||||||
allowedMedia.contains(param.media) &&
|
if (!allowedMedia.contains(param.media)) invalid_params :+= "media"
|
||||||
allowedInputType.contains(param.input_type)
|
if (!allowedInputType.contains(param.input_type)) invalid_params :+= "input_type"
|
||||||
)
|
|
||||||
return true
|
invalid_params
|
||||||
else
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def getChallenge(param: Parameters): ChallengeResult = {
|
def getChallenge(param: Parameters): Either[Error, Id] = {
|
||||||
try {
|
val validParam = validateParam(param)
|
||||||
val validParam = validateParam(param)
|
if (validParam.isEmpty) {
|
||||||
if (validParam) {
|
val tokenOpt = getToken(param)
|
||||||
val tokenPstmt = Statements.tlStmts.get.tokenPstmt
|
val token = tokenOpt.orElse(generateChallenge(param))
|
||||||
tokenPstmt.setString(1, param.level)
|
token match {
|
||||||
tokenPstmt.setString(2, param.media)
|
case Some(value) => {
|
||||||
tokenPstmt.setString(3, param.input_type)
|
val uuid = getUUID(value)
|
||||||
val rs = tokenPstmt.executeQuery()
|
updateAttempted(uuid)
|
||||||
val tokenOpt = if (rs.next()) {
|
Right(Id(uuid))
|
||||||
Some(rs.getInt("token"))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
val updateAttemptedPstmt = Statements.tlStmts.get.updateAttemptedPstmt
|
case None => {
|
||||||
val token = tokenOpt.getOrElse(generateChallenge(param))
|
Left(Error(ErrorMessageEnum.NO_CAPTCHA.toString))
|
||||||
val result = if (token != -1) {
|
|
||||||
val uuid = getUUID(token)
|
|
||||||
updateAttemptedPstmt.setString(1, uuid)
|
|
||||||
updateAttemptedPstmt.executeUpdate()
|
|
||||||
Id(uuid)
|
|
||||||
} else {
|
|
||||||
Error(ErrorMessageEnum.NO_CAPTCHA.toString)
|
|
||||||
}
|
}
|
||||||
result
|
|
||||||
} else {
|
|
||||||
Error(ErrorMessageEnum.INVALID_PARAM.toString)
|
|
||||||
}
|
}
|
||||||
} catch {
|
} else {
|
||||||
case e: Exception =>
|
Left(Error(ErrorMessageEnum.INVALID_PARAM.toString + " => " + validParam.mkString(", ")))
|
||||||
println(e)
|
|
||||||
Error(ErrorMessageEnum.SMW.toString)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def getToken(param: Parameters): Option[Int] = {
|
||||||
|
val tokenPstmt = Statements.tlStmts.get.tokenPstmt
|
||||||
|
tokenPstmt.setString(1, param.level)
|
||||||
|
tokenPstmt.setString(2, param.media)
|
||||||
|
tokenPstmt.setString(3, param.input_type)
|
||||||
|
val rs = tokenPstmt.executeQuery()
|
||||||
|
if (rs.next()) {
|
||||||
|
Some(rs.getInt("token"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def updateAttempted(uuid: String): Unit = {
|
||||||
|
val updateAttemptedPstmt = Statements.tlStmts.get.updateAttemptedPstmt
|
||||||
|
updateAttemptedPstmt.setString(1, uuid)
|
||||||
|
updateAttemptedPstmt.executeUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
private def getUUID(id: Int): String = {
|
private def getUUID(id: Int): String = {
|
||||||
val uuid = UUID.randomUUID().toString
|
val uuid = UUID.randomUUID().toString
|
||||||
val mapPstmt = Statements.tlStmts.get.mapPstmt
|
val mapPstmt = Statements.tlStmts.get.mapPstmt
|
||||||
@ -109,24 +136,38 @@ object Captcha {
|
|||||||
uuid
|
uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkAnswer(answer: Answer): Result = {
|
def checkAnswer(answer: Answer): Either[Error, Success] = {
|
||||||
|
val challenge = getSecret(answer.id)
|
||||||
|
challenge match {
|
||||||
|
case None => Right(Success(ResultEnum.EXPIRED.toString))
|
||||||
|
case Some(value) => {
|
||||||
|
val (provider, secret) = value
|
||||||
|
val check = CaptchaProviders.getProviderById(provider).checkAnswer(secret, answer.answer)
|
||||||
|
deleteCaptcha(answer.id)
|
||||||
|
val result = if (check) ResultEnum.TRUE.toString else ResultEnum.FALSE.toString
|
||||||
|
Right(Success(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def getSecret(id: String): Option[(String, String)] = {
|
||||||
val selectPstmt = Statements.tlStmts.get.selectPstmt
|
val selectPstmt = Statements.tlStmts.get.selectPstmt
|
||||||
selectPstmt.setInt(1, Config.captchaExpiryTimeLimit)
|
selectPstmt.setInt(1, Config.captchaExpiryTimeLimit)
|
||||||
selectPstmt.setString(2, answer.id)
|
selectPstmt.setString(2, id)
|
||||||
val rs: ResultSet = selectPstmt.executeQuery()
|
val rs: ResultSet = selectPstmt.executeQuery()
|
||||||
val psOpt = if (rs.first()) {
|
if (rs.first()) {
|
||||||
val secret = rs.getString("secret")
|
val secret = rs.getString("secret")
|
||||||
val provider = rs.getString("provider")
|
val provider = rs.getString("provider")
|
||||||
val check = CaptchaProviders.getProviderById(provider).checkAnswer(secret, answer.answer)
|
Some(provider, secret)
|
||||||
val result = if (check) ResultEnum.TRUE.toString else ResultEnum.FALSE.toString
|
|
||||||
result
|
|
||||||
} else {
|
} else {
|
||||||
ResultEnum.EXPIRED.toString
|
None
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def deleteCaptcha(id: String): Unit = {
|
||||||
val deleteAnswerPstmt = Statements.tlStmts.get.deleteAnswerPstmt
|
val deleteAnswerPstmt = Statements.tlStmts.get.deleteAnswerPstmt
|
||||||
deleteAnswerPstmt.setString(1, answer.id)
|
deleteAnswerPstmt.setString(1, id)
|
||||||
deleteAnswerPstmt.executeUpdate()
|
deleteAnswerPstmt.executeUpdate()
|
||||||
Result(psOpt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def display(): Unit = {
|
def display(): Unit = {
|
||||||
|
@ -38,6 +38,8 @@ object ErrorMessageEnum extends Enumeration {
|
|||||||
|
|
||||||
val SMW: Value = Value("Oops, something went worng!")
|
val SMW: Value = Value("Oops, something went worng!")
|
||||||
val INVALID_PARAM: Value = Value("Parameters invalid or missing")
|
val INVALID_PARAM: Value = Value("Parameters invalid or missing")
|
||||||
val NO_CAPTCHA: Value = Value("No captcha for the provided parameters")
|
val IMG_MISSING: Value = Value("Image missing")
|
||||||
|
val IMG_NOT_FOUND: Value = Value("Image not found")
|
||||||
|
val NO_CAPTCHA: Value = Value("No captcha for the provided parameters. Change config options.")
|
||||||
val BAD_METHOD: Value = Value("Bad request method")
|
val BAD_METHOD: Value = Value("Bad request method")
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ object CaptchaProviders {
|
|||||||
"GifCaptcha" -> new GifCaptcha,
|
"GifCaptcha" -> new GifCaptcha,
|
||||||
"ShadowTextCaptcha" -> new ShadowTextCaptcha,
|
"ShadowTextCaptcha" -> new ShadowTextCaptcha,
|
||||||
"RainDropsCaptcha" -> new RainDropsCP,
|
"RainDropsCaptcha" -> new RainDropsCP,
|
||||||
"DebugCaptcha" -> new DebugCaptcha,
|
"DebugCaptcha" -> new DebugCaptcha
|
||||||
//"LabelCaptcha" -> new LabelCaptcha
|
//"LabelCaptcha" -> new LabelCaptcha
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -55,13 +55,16 @@ object CaptchaProviders {
|
|||||||
providerFilter
|
providerFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
def getProvider(param: Parameters): ChallengeProvider = {
|
def getProvider(param: Parameters): Option[ChallengeProvider] = {
|
||||||
val providerConfig = filterProviderByParam(param).toList
|
val providerConfig = filterProviderByParam(param).toList
|
||||||
if (providerConfig.length == 0) throw new NoSuchElementException(ErrorMessageEnum.NO_CAPTCHA.toString)
|
if (providerConfig.length > 0) {
|
||||||
val randomIndex = getNextRandomInt(providerConfig.length)
|
val randomIndex = getNextRandomInt(providerConfig.length)
|
||||||
val providerIndex = providerConfig(randomIndex)._1
|
val providerIndex = providerConfig(randomIndex)._1
|
||||||
val selectedProvider = providers(providerIndex)
|
val selectedProvider = providers(providerIndex)
|
||||||
selectedProvider.configure(providerConfig(randomIndex)._2)
|
selectedProvider.configure(providerConfig(randomIndex)._2)
|
||||||
selectedProvider
|
Some(selectedProvider)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,42 +49,42 @@ object Config {
|
|||||||
val allowedInputType: Set[String] = captchaConfig.flatMap(_.allowedInputType).toSet
|
val allowedInputType: Set[String] = captchaConfig.flatMap(_.allowedInputType).toSet
|
||||||
|
|
||||||
private def getDefaultConfig(): String = {
|
private def getDefaultConfig(): String = {
|
||||||
val defaultConfigMap =
|
val defaultConfigMap =
|
||||||
(AttributesEnum.RANDOM_SEED.toString -> 20) ~
|
(AttributesEnum.RANDOM_SEED.toString -> 20) ~
|
||||||
(AttributesEnum.PORT.toString -> 8888) ~
|
(AttributesEnum.PORT.toString -> 8888) ~
|
||||||
(AttributesEnum.CAPTCHA_EXPIRY_TIME_LIMIT.toString -> 5) ~
|
(AttributesEnum.CAPTCHA_EXPIRY_TIME_LIMIT.toString -> 5) ~
|
||||||
(AttributesEnum.THROTTLE.toString -> 10) ~
|
(AttributesEnum.THROTTLE.toString -> 10) ~
|
||||||
(AttributesEnum.THREAD_DELAY.toString -> 2) ~
|
(AttributesEnum.THREAD_DELAY.toString -> 2) ~
|
||||||
("captchas" -> List(
|
("captchas" -> List(
|
||||||
(
|
(
|
||||||
(AttributesEnum.NAME.toString -> "FilterChallenge") ~
|
(AttributesEnum.NAME.toString -> "FilterChallenge") ~
|
||||||
(ParametersEnum.ALLOWEDLEVELS.toString -> List("medium", "hard")) ~
|
(ParametersEnum.ALLOWEDLEVELS.toString -> List("medium", "hard")) ~
|
||||||
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/png")) ~
|
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/png")) ~
|
||||||
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
|
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
|
||||||
(AttributesEnum.CONFIG.toString -> JObject())
|
(AttributesEnum.CONFIG.toString -> JObject())
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
(AttributesEnum.NAME.toString -> "GifCaptcha") ~
|
(AttributesEnum.NAME.toString -> "GifCaptcha") ~
|
||||||
(ParametersEnum.ALLOWEDLEVELS.toString -> List("hard")) ~
|
(ParametersEnum.ALLOWEDLEVELS.toString -> List("hard")) ~
|
||||||
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/gif")) ~
|
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/gif")) ~
|
||||||
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
|
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
|
||||||
(AttributesEnum.CONFIG.toString -> JObject())
|
(AttributesEnum.CONFIG.toString -> JObject())
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
(AttributesEnum.NAME.toString -> "ShadowTextCaptcha") ~
|
(AttributesEnum.NAME.toString -> "ShadowTextCaptcha") ~
|
||||||
(ParametersEnum.ALLOWEDLEVELS.toString -> List("easy")) ~
|
(ParametersEnum.ALLOWEDLEVELS.toString -> List("easy")) ~
|
||||||
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/png")) ~
|
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/png")) ~
|
||||||
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
|
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
|
||||||
(AttributesEnum.CONFIG.toString -> JObject())
|
(AttributesEnum.CONFIG.toString -> JObject())
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
(AttributesEnum.NAME.toString -> "RainDropsCaptcha") ~
|
(AttributesEnum.NAME.toString -> "RainDropsCaptcha") ~
|
||||||
(ParametersEnum.ALLOWEDLEVELS.toString -> List("easy", "medium")) ~
|
(ParametersEnum.ALLOWEDLEVELS.toString -> List("easy", "medium")) ~
|
||||||
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/gif")) ~
|
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/gif")) ~
|
||||||
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
|
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
|
||||||
(AttributesEnum.CONFIG.toString -> JObject())
|
(AttributesEnum.CONFIG.toString -> JObject())
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
pretty(render(defaultConfigMap))
|
pretty(render(defaultConfigMap))
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package lc.core
|
package lc.core
|
||||||
|
|
||||||
sealed trait ChallengeResult
|
import org.json4s.jackson.Serialization.write
|
||||||
|
import lc.core.Config.formats
|
||||||
|
|
||||||
|
trait ByteConvert { def toBytes(): Array[Byte] }
|
||||||
case class Size(height: Int, width: Int)
|
case class Size(height: Int, width: Int)
|
||||||
case class Parameters(level: String, media: String, input_type: String, size: Option[Size])
|
case class Parameters(level: String, media: String, input_type: String, size: Option[Size])
|
||||||
case class Id(id: String) extends ChallengeResult
|
case class Id(id: String) extends ByteConvert { def toBytes(): Array[Byte] = { write(this).getBytes } }
|
||||||
case class Image(image: Array[Byte]) extends ChallengeResult
|
case class Image(image: Array[Byte]) extends ByteConvert { def toBytes(): Array[Byte] = { image } }
|
||||||
case class Answer(answer: String, id: String)
|
case class Answer(answer: String, id: String)
|
||||||
case class Result(result: String)
|
case class Success(result: String) extends ByteConvert { def toBytes(): Array[Byte] = { write(this).getBytes } }
|
||||||
case class Error(message: String) extends ChallengeResult
|
case class Error(message: String) extends ByteConvert { def toBytes(): Array[Byte] = { write(this).getBytes } }
|
||||||
case class Response(statusCode: Int, message: Array[Byte])
|
case class Response(statusCode: Int, message: Array[Byte])
|
||||||
case class CaptchaConfig(
|
case class CaptchaConfig(
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
package lc.server
|
package lc.server
|
||||||
|
|
||||||
import org.json4s.DefaultFormats
|
|
||||||
import org.json4s.jackson.JsonMethods.parse
|
import org.json4s.jackson.JsonMethods.parse
|
||||||
import org.json4s.jackson.Serialization.write
|
|
||||||
import lc.core.Captcha
|
import lc.core.Captcha
|
||||||
import lc.core.ErrorMessageEnum
|
import lc.core.ErrorMessageEnum
|
||||||
import lc.core.{Parameters, Id, Answer, Response}
|
import lc.core.{Parameters, Id, Answer, Response, Error, ByteConvert}
|
||||||
import org.json4s.JsonAST.JValue
|
import org.json4s.JsonAST.JValue
|
||||||
import com.sun.net.httpserver.{HttpServer, HttpExchange}
|
import com.sun.net.httpserver.{HttpServer, HttpExchange}
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
|
import lc.core.Config.formats
|
||||||
|
|
||||||
class Server(port: Int) {
|
class Server(port: Int) {
|
||||||
|
|
||||||
implicit val formats: DefaultFormats.type = DefaultFormats
|
|
||||||
val server: HttpServer = HttpServer.create(new InetSocketAddress(port), 32)
|
val server: HttpServer = HttpServer.create(new InetSocketAddress(port), 32)
|
||||||
server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool())
|
server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool())
|
||||||
|
|
||||||
@ -24,14 +22,19 @@ class Server(port: Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val eqPattern = java.util.regex.Pattern.compile("=")
|
private val eqPattern = java.util.regex.Pattern.compile("=")
|
||||||
private def getPathParameter(ex: HttpExchange): String = {
|
private def getPathParameter(ex: HttpExchange): Either[String, String] = {
|
||||||
try {
|
try {
|
||||||
val query = ex.getRequestURI.getQuery
|
val query = ex.getRequestURI.getQuery
|
||||||
eqPattern.split(query)(1)
|
val param = eqPattern.split(query)
|
||||||
|
if (param(0) == "id") {
|
||||||
|
Right(param(1))
|
||||||
|
} else {
|
||||||
|
Left(ErrorMessageEnum.INVALID_PARAM.toString + "=> id")
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
case exception: ArrayIndexOutOfBoundsException => {
|
case exception: ArrayIndexOutOfBoundsException => {
|
||||||
println(exception.getStackTrace)
|
println(exception)
|
||||||
throw new Exception(ErrorMessageEnum.INVALID_PARAM.toString)
|
Left(ErrorMessageEnum.INVALID_PARAM.toString + "=> id")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,15 +47,25 @@ class Server(port: Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def getException(exception: Exception): Response = {
|
private def getException(exception: Exception): Response = {
|
||||||
println(exception.printStackTrace)
|
println(exception)
|
||||||
val message = ("message" -> exception.getMessage)
|
val message = Error(exception.getMessage)
|
||||||
val messageByte = write(message).getBytes
|
Response(500, message.toBytes())
|
||||||
Response(500, messageByte)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def getBadRequestError(): Response = {
|
private def getBadRequestError(): Response = {
|
||||||
val message = ("message" -> ErrorMessageEnum.BAD_METHOD.toString)
|
val message = Error(ErrorMessageEnum.BAD_METHOD.toString)
|
||||||
Response(405, write(message).getBytes)
|
Response(405, message.toBytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
private def getResponse(response: Either[Error, ByteConvert]): Response = {
|
||||||
|
response match {
|
||||||
|
case Right(value) => {
|
||||||
|
Response(200, value.toBytes())
|
||||||
|
}
|
||||||
|
case Left(value) => {
|
||||||
|
Response(500, value.toBytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def makeApiWorker(path: String, f: (String, HttpExchange) => Response): Unit = {
|
private def makeApiWorker(path: String, f: (String, HttpExchange) => Response): Unit = {
|
||||||
@ -85,7 +98,7 @@ class Server(port: Int) {
|
|||||||
val json = getRequestJson(ex)
|
val json = getRequestJson(ex)
|
||||||
val param = json.extract[Parameters]
|
val param = json.extract[Parameters]
|
||||||
val id = Captcha.getChallenge(param)
|
val id = Captcha.getChallenge(param)
|
||||||
Response(200, write(id).getBytes)
|
getResponse(id)
|
||||||
} else {
|
} else {
|
||||||
getBadRequestError()
|
getBadRequestError()
|
||||||
}
|
}
|
||||||
@ -97,9 +110,14 @@ class Server(port: Int) {
|
|||||||
(method: String, ex: HttpExchange) => {
|
(method: String, ex: HttpExchange) => {
|
||||||
if (method == "GET") {
|
if (method == "GET") {
|
||||||
val param = getPathParameter(ex)
|
val param = getPathParameter(ex)
|
||||||
val id = Id(param)
|
val result = param match {
|
||||||
val image = Captcha.getCaptcha(id)
|
case Right(value) => {
|
||||||
Response(200, image)
|
val id = Id(value)
|
||||||
|
Captcha.getCaptcha(id)
|
||||||
|
}
|
||||||
|
case Left(value) => Left(Error(value))
|
||||||
|
}
|
||||||
|
getResponse(result)
|
||||||
} else {
|
} else {
|
||||||
getBadRequestError()
|
getBadRequestError()
|
||||||
}
|
}
|
||||||
@ -113,7 +131,7 @@ class Server(port: Int) {
|
|||||||
val json = getRequestJson(ex)
|
val json = getRequestJson(ex)
|
||||||
val answer = json.extract[Answer]
|
val answer = json.extract[Answer]
|
||||||
val result = Captcha.checkAnswer(answer)
|
val result = Captcha.checkAnswer(answer)
|
||||||
Response(200, write(result).getBytes)
|
getResponse(result)
|
||||||
} else {
|
} else {
|
||||||
getBadRequestError()
|
getBadRequestError()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user