mirror of
https://github.com/librecaptcha/lc-core.git
synced 2025-11-29 05:18:50 -05:00
Linter and Formatter support (#58)
* Add scala linter and formatter Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Add java formatter Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Add linter support Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Increase maxColumn limit Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Reformat and lint Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Minor reformatting Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Add scala formatter on compile option Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com> * Enable scala linter for CI Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
This commit is contained in:
committed by
GitHub
parent
6d04cdc3b4
commit
de50d8123e
@@ -1,17 +1,12 @@
|
||||
package lc
|
||||
|
||||
import org.json4s.DefaultFormats
|
||||
import org.json4s.jackson.JsonMethods._
|
||||
import scala.io.Source.fromFile
|
||||
import lc.database.Statements
|
||||
import lc.core.{Captcha, CaptchaProviders}
|
||||
import lc.server.Server
|
||||
import lc.background.BackgroundTask
|
||||
|
||||
|
||||
object LCFramework{
|
||||
def main(args: scala.Array[String]) {
|
||||
val captcha = new Captcha()
|
||||
object LCFramework {
|
||||
def main(args: scala.Array[String]): Unit = {
|
||||
val captcha = new Captcha()
|
||||
val server = new Server(8888, captcha)
|
||||
val backgroudTask = new BackgroundTask(captcha, 10)
|
||||
backgroudTask.beginThread(2)
|
||||
@@ -20,15 +15,16 @@ object LCFramework{
|
||||
}
|
||||
|
||||
object MakeSamples {
|
||||
def main(args: scala.Array[String]) {
|
||||
def main(args: scala.Array[String]): Unit = {
|
||||
val samples = CaptchaProviders.generateChallengeSamples()
|
||||
samples.foreach {case (key, sample) =>
|
||||
val extensionMap = Map("image/png" -> "png", "image/gif" -> "gif")
|
||||
println(key + ": " + sample)
|
||||
samples.foreach {
|
||||
case (key, sample) =>
|
||||
val extensionMap = Map("image/png" -> "png", "image/gif" -> "gif")
|
||||
println(key + ": " + sample)
|
||||
|
||||
val outStream = new java.io.FileOutputStream("samples/"+key+"."+extensionMap(sample.contentType))
|
||||
outStream.write(sample.content)
|
||||
outStream.close
|
||||
val outStream = new java.io.FileOutputStream("samples/" + key + "." + extensionMap(sample.contentType))
|
||||
outStream.write(sample.content)
|
||||
outStream.close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,34 +5,33 @@ import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
|
||||
import lc.core.Captcha
|
||||
import lc.core.{Parameters, Size}
|
||||
|
||||
|
||||
class BackgroundTask(captcha: Captcha, throttle: Int) {
|
||||
|
||||
private val task = new Runnable {
|
||||
def run(): Unit = {
|
||||
try {
|
||||
private val task = new Runnable {
|
||||
def run(): Unit = {
|
||||
try {
|
||||
|
||||
val mapIdGCPstmt = Statements.tlStmts.get.mapIdGCPstmt
|
||||
mapIdGCPstmt.executeUpdate()
|
||||
val mapIdGCPstmt = Statements.tlStmts.get.mapIdGCPstmt
|
||||
mapIdGCPstmt.executeUpdate()
|
||||
|
||||
val challengeGCPstmt = Statements.tlStmts.get.challengeGCPstmt
|
||||
challengeGCPstmt.executeUpdate()
|
||||
val challengeGCPstmt = Statements.tlStmts.get.challengeGCPstmt
|
||||
challengeGCPstmt.executeUpdate()
|
||||
|
||||
val imageNum = Statements.tlStmts.get.getCountChallengeTable.executeQuery()
|
||||
var throttleIn = (throttle*1.1).toInt
|
||||
if(imageNum.next())
|
||||
throttleIn = (throttleIn-imageNum.getInt("total"))
|
||||
while(0 < throttleIn){
|
||||
captcha.generateChallenge(Parameters("","","",Option(Size(0,0))))
|
||||
throttleIn -= 1
|
||||
}
|
||||
} catch { case e: Exception => println(e) }
|
||||
val imageNum = Statements.tlStmts.get.getCountChallengeTable.executeQuery()
|
||||
var throttleIn = (throttle * 1.1).toInt
|
||||
if (imageNum.next())
|
||||
throttleIn = (throttleIn - imageNum.getInt("total"))
|
||||
while (0 < throttleIn) {
|
||||
captcha.generateChallenge(Parameters("", "", "", Option(Size(0, 0))))
|
||||
throttleIn -= 1
|
||||
}
|
||||
} catch { case e: Exception => println(e) }
|
||||
}
|
||||
|
||||
def beginThread(delay: Int) : Unit = {
|
||||
val ex = new ScheduledThreadPoolExecutor(1)
|
||||
val thread = ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
}
|
||||
def beginThread(delay: Int): Unit = {
|
||||
val ex = new ScheduledThreadPoolExecutor(1)
|
||||
ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.awt.Color
|
||||
import lc.captchas.interfaces.ChallengeProvider
|
||||
import lc.captchas.interfaces.Challenge
|
||||
|
||||
|
||||
class FilterChallenge extends ChallengeProvider {
|
||||
def getId = "FilterChallenge"
|
||||
def returnChallenge(): Challenge = {
|
||||
@@ -62,4 +61,3 @@ class FilterType2 extends FilterType {
|
||||
image
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,45 +4,45 @@ import java.io.File
|
||||
import java.io.ByteArrayOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
import scala.collection.mutable.Map
|
||||
import java.nio.file.{Files,Path,StandardCopyOption}
|
||||
import java.nio.file.{Files, StandardCopyOption}
|
||||
import java.awt.image.BufferedImage
|
||||
import java.awt.{Graphics2D,Color}
|
||||
import java.awt.Color
|
||||
import lc.captchas.interfaces.ChallengeProvider
|
||||
import lc.captchas.interfaces.Challenge
|
||||
|
||||
class LabelCaptcha extends ChallengeProvider {
|
||||
private var knownFiles = new File("known").list.toList
|
||||
private var unknownFiles = new File("unknown").list.toList
|
||||
private var unknownAnswers = Map[String, Map[String, Int]]()
|
||||
private var total = Map[String, Int]()
|
||||
private val unknownAnswers = Map[String, Map[String, Int]]()
|
||||
private val total = Map[String, Int]()
|
||||
|
||||
for(file <- unknownFiles) {
|
||||
unknownAnswers += file -> Map[String, Int]()
|
||||
total += file -> 0
|
||||
for (file <- unknownFiles) {
|
||||
unknownAnswers += file -> Map[String, Int]()
|
||||
total += file -> 0
|
||||
}
|
||||
|
||||
def getId = "LabelCaptcha"
|
||||
|
||||
def returnChallenge(): Challenge = synchronized {
|
||||
val r = scala.util.Random.nextInt(knownFiles.length)
|
||||
val s = scala.util.Random.nextInt(unknownFiles.length)
|
||||
val knownImageFile = knownFiles(r)
|
||||
val unknownImageFile = unknownFiles(s)
|
||||
val ip = new ImagePair(knownImageFile, unknownImageFile)
|
||||
def returnChallenge(): Challenge =
|
||||
synchronized {
|
||||
val r = scala.util.Random.nextInt(knownFiles.length)
|
||||
val s = scala.util.Random.nextInt(unknownFiles.length)
|
||||
val knownImageFile = knownFiles(r)
|
||||
val unknownImageFile = unknownFiles(s)
|
||||
|
||||
var knownImage = ImageIO.read(new File("known/"+knownImageFile))
|
||||
var unknownImage = ImageIO.read(new File("unknown/"+unknownImageFile))
|
||||
val mergedImage = merge(knownImage, unknownImage)
|
||||
val knownImage = ImageIO.read(new File("known/" + knownImageFile))
|
||||
val unknownImage = ImageIO.read(new File("unknown/" + unknownImageFile))
|
||||
val mergedImage = merge(knownImage, unknownImage)
|
||||
|
||||
val token = encrypt(knownImageFile + "," + unknownImageFile)
|
||||
val baos = new ByteArrayOutputStream()
|
||||
ImageIO.write(mergedImage,"png",baos)
|
||||
val token = encrypt(knownImageFile + "," + unknownImageFile)
|
||||
val baos = new ByteArrayOutputStream()
|
||||
ImageIO.write(mergedImage, "png", baos)
|
||||
|
||||
new Challenge(baos.toByteArray(), "image/png", token)
|
||||
}
|
||||
new Challenge(baos.toByteArray(), "image/png", token)
|
||||
}
|
||||
|
||||
private def merge(knownImage: BufferedImage, unknownImage: BufferedImage) = {
|
||||
val width = knownImage.getWidth()+unknownImage.getWidth()
|
||||
val width = knownImage.getWidth() + unknownImage.getWidth()
|
||||
val height = List(knownImage.getHeight(), unknownImage.getHeight()).max
|
||||
val imageType = knownImage.getType()
|
||||
val finalImage = new BufferedImage(width, height, imageType)
|
||||
@@ -55,34 +55,39 @@ class LabelCaptcha extends ChallengeProvider {
|
||||
finalImage
|
||||
}
|
||||
|
||||
def checkAnswer(token: String, input: String): Boolean = synchronized {
|
||||
val parts = decrypt(token).split(",")
|
||||
val knownImage = parts(0)
|
||||
val unknownImage = parts(1)
|
||||
val expectedAnswer = knownImage.split('.')(0)
|
||||
val userAnswer = input.split(' ')
|
||||
if(userAnswer(0)==expectedAnswer) {
|
||||
val unknownFile = unknownImage
|
||||
if((unknownAnswers(unknownFile)).contains(userAnswer(1))) {
|
||||
unknownAnswers(unknownFile)(userAnswer(1)) += 1
|
||||
total(unknownFile) += 1
|
||||
} else {
|
||||
unknownAnswers(unknownFile)+=(userAnswer(1)) -> 1
|
||||
total(unknownFile) += 1
|
||||
}
|
||||
if(total(unknownFile)>=3) {
|
||||
if((unknownAnswers(unknownFile)(userAnswer(1))/total(unknownFile))>=0.9) {
|
||||
unknownAnswers -= unknownFile
|
||||
Files.move(new File("unknown/"+unknownFile).toPath, new File("known/"+userAnswer(1)+".png").toPath, StandardCopyOption.REPLACE_EXISTING)
|
||||
knownFiles = new File("known").list.toList
|
||||
unknownFiles = new File("unknown").list.toList
|
||||
def checkAnswer(token: String, input: String): Boolean =
|
||||
synchronized {
|
||||
val parts = decrypt(token).split(",")
|
||||
val knownImage = parts(0)
|
||||
val unknownImage = parts(1)
|
||||
val expectedAnswer = knownImage.split('.')(0)
|
||||
val userAnswer = input.split(' ')
|
||||
if (userAnswer(0) == expectedAnswer) {
|
||||
val unknownFile = unknownImage
|
||||
if ((unknownAnswers(unknownFile)).contains(userAnswer(1))) {
|
||||
unknownAnswers(unknownFile)(userAnswer(1)) += 1
|
||||
total(unknownFile) += 1
|
||||
} else {
|
||||
unknownAnswers(unknownFile) += (userAnswer(1)) -> 1
|
||||
total(unknownFile) += 1
|
||||
}
|
||||
if (total(unknownFile) >= 3) {
|
||||
if ((unknownAnswers(unknownFile)(userAnswer(1)) / total(unknownFile)) >= 0.9) {
|
||||
unknownAnswers -= unknownFile
|
||||
Files.move(
|
||||
new File("unknown/" + unknownFile).toPath,
|
||||
new File("known/" + userAnswer(1) + ".png").toPath,
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
knownFiles = new File("known").list.toList
|
||||
unknownFiles = new File("unknown").list.toList
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Encryption is not implemented for the POC, since the API re-maps the tokens anyway.
|
||||
// But we need to encrypt after POC, to avoid leaking file-names.
|
||||
|
||||
@@ -5,9 +5,7 @@ import java.awt.RenderingHints
|
||||
import java.awt.Font
|
||||
import java.awt.font.TextAttribute
|
||||
import java.awt.Color
|
||||
import java.io.ByteArrayOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
||||
import lc.captchas.interfaces.ChallengeProvider
|
||||
import lc.captchas.interfaces.Challenge
|
||||
@@ -19,8 +17,8 @@ class Drop {
|
||||
var yOffset = 0
|
||||
var color = 0
|
||||
var colorChange = 10
|
||||
def mkColor = {
|
||||
new Color(color, color, math.min(200, color+100))
|
||||
def mkColor: Color = {
|
||||
new Color(color, color, math.min(200, color + 100))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +34,8 @@ class RainDropsCP extends ChallengeProvider {
|
||||
private def extendDrops(drops: Array[Drop], steps: Int, xOffset: Int) = {
|
||||
drops.map(d => {
|
||||
val nd = new Drop()
|
||||
nd.x + xOffset*steps
|
||||
nd.y + d.yOffset*steps
|
||||
nd.x + xOffset * steps
|
||||
nd.y + d.yOffset * steps
|
||||
nd
|
||||
})
|
||||
}
|
||||
@@ -48,20 +46,23 @@ class RainDropsCP extends ChallengeProvider {
|
||||
val width = 450
|
||||
val height = 100
|
||||
val imgType = BufferedImage.TYPE_INT_RGB
|
||||
val xOffset = 2+r.nextInt(3)
|
||||
val xOffset = 2 + r.nextInt(3)
|
||||
val xBias = (height / 10) - 2
|
||||
val dropsOrig = Array.fill[Drop](2000)( new Drop())
|
||||
val dropsOrig = Array.fill[Drop](2000)(new Drop())
|
||||
for (d <- dropsOrig) {
|
||||
d.x = r.nextInt(width) - (xBias/2)*xOffset
|
||||
d.yOffset = 6+r.nextInt(6)
|
||||
d.x = r.nextInt(width) - (xBias / 2) * xOffset
|
||||
d.yOffset = 6 + r.nextInt(6)
|
||||
d.y = r.nextInt(height)
|
||||
d.color = r.nextInt(240)
|
||||
if (d.color > 128) {
|
||||
d.colorChange *= -1
|
||||
}
|
||||
}
|
||||
val drops = dropsOrig ++ extendDrops(dropsOrig, 1, xOffset) ++ extendDrops(dropsOrig, 2, xOffset) ++ extendDrops(dropsOrig, 3, xOffset)
|
||||
|
||||
val drops = dropsOrig ++ extendDrops(dropsOrig, 1, xOffset) ++ extendDrops(dropsOrig, 2, xOffset) ++ extendDrops(
|
||||
dropsOrig,
|
||||
3,
|
||||
xOffset
|
||||
)
|
||||
|
||||
val baseFont = new Font(Font.MONOSPACED, Font.BOLD, 80)
|
||||
val attributes = new java.util.HashMap[TextAttribute, Object]()
|
||||
@@ -72,7 +73,7 @@ class RainDropsCP extends ChallengeProvider {
|
||||
val baos = new ByteArrayOutputStream();
|
||||
val ios = new MemoryCacheImageOutputStream(baos);
|
||||
val writer = new GifSequenceWriter(ios, imgType, 60, true);
|
||||
for(i <- 0 until 60){
|
||||
for (_ <- 0 until 60) {
|
||||
// val yOffset = 5+r.nextInt(5)
|
||||
val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
|
||||
val g = canvas.createGraphics()
|
||||
@@ -85,14 +86,14 @@ class RainDropsCP extends ChallengeProvider {
|
||||
// paint the rain
|
||||
for (d <- drops) {
|
||||
g.setColor(d.mkColor)
|
||||
g.drawLine(d.x, d.y, d.x+xOffset, d.y+d.yOffset)
|
||||
d.x += xOffset/2
|
||||
d.y += d.yOffset/2
|
||||
g.drawLine(d.x, d.y, d.x + xOffset, d.y + d.yOffset)
|
||||
d.x += xOffset / 2
|
||||
d.y += d.yOffset / 2
|
||||
d.color += d.colorChange
|
||||
if (d.x > width || d.y > height) {
|
||||
val ySteps = (height / d.yOffset) + 1
|
||||
d.x -= xOffset*ySteps
|
||||
d.y -= d.yOffset*ySteps
|
||||
val ySteps = (height / d.yOffset) + 1
|
||||
d.x -= xOffset * ySteps
|
||||
d.y -= d.yOffset * ySteps
|
||||
|
||||
}
|
||||
if (d.color > 200 || d.color < 21) {
|
||||
@@ -103,7 +104,7 @@ class RainDropsCP extends ChallengeProvider {
|
||||
// center the text
|
||||
g.setFont(spacedFont)
|
||||
val textWidth = g.getFontMetrics().charsWidth(secret.toCharArray, 0, secret.toCharArray.length)
|
||||
val textX = (width - textWidth)/2
|
||||
val textX = (width - textWidth) / 2
|
||||
|
||||
// paint the top outline
|
||||
g.setColor(textHighlightColor)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package lc.core
|
||||
|
||||
import org.json4s.JsonAST.JValue
|
||||
import java.sql.{Blob, ResultSet}
|
||||
import java.util.UUID
|
||||
import java.io.ByteArrayInputStream
|
||||
@@ -10,29 +9,30 @@ import lc.core.CaptchaProviders
|
||||
class Captcha {
|
||||
|
||||
def getCaptcha(id: Id): Array[Byte] = {
|
||||
var image :Array[Byte] = null
|
||||
var image: Array[Byte] = null
|
||||
var blob: Blob = null
|
||||
try {
|
||||
val imagePstmt = Statements.tlStmts.get.imagePstmt
|
||||
imagePstmt.setString(1, id.id)
|
||||
val rs: ResultSet = imagePstmt.executeQuery()
|
||||
if(rs.next()){
|
||||
imagePstmt.setString(1, id.id)
|
||||
val rs: ResultSet = imagePstmt.executeQuery()
|
||||
if (rs.next()) {
|
||||
blob = rs.getBlob("image")
|
||||
if(blob != null){
|
||||
image = blob.getBytes(1, blob.length().toInt)
|
||||
if (blob != null) {
|
||||
image = blob.getBytes(1, blob.length().toInt)
|
||||
}
|
||||
}
|
||||
image
|
||||
} catch { case e: Exception =>
|
||||
println(e)
|
||||
image
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
println(e)
|
||||
image
|
||||
}
|
||||
}
|
||||
|
||||
def generateChallenge(param: Parameters): Int = {
|
||||
//TODO: eval params to choose a provider
|
||||
val provider = CaptchaProviders.getProvider()
|
||||
val providerId = provider.getId()
|
||||
//TODO: eval params to choose a provider
|
||||
val provider = CaptchaProviders.getProvider()
|
||||
val providerId = provider.getId()
|
||||
val challenge = provider.returnChallenge()
|
||||
val blob = new ByteArrayInputStream(challenge.content)
|
||||
val insertPstmt = Statements.tlStmts.get.insertPstmt
|
||||
@@ -43,10 +43,10 @@ class Captcha {
|
||||
insertPstmt.setBlob(5, blob)
|
||||
insertPstmt.executeUpdate()
|
||||
val rs: ResultSet = insertPstmt.getGeneratedKeys()
|
||||
val token = if(rs.next()){
|
||||
val token = if (rs.next()) {
|
||||
rs.getInt("token")
|
||||
}
|
||||
println("Added new challenge: "+ token.toString)
|
||||
println("Added new challenge: " + token.toString)
|
||||
token.asInstanceOf[Int]
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ class Captcha {
|
||||
try {
|
||||
val tokenPstmt = Statements.tlStmts.get.tokenPstmt
|
||||
val rs = tokenPstmt.executeQuery()
|
||||
val tokenOpt = if(rs.next()) {
|
||||
val tokenOpt = if (rs.next()) {
|
||||
Some(rs.getInt("token"))
|
||||
} else {
|
||||
None
|
||||
@@ -64,44 +64,45 @@ class Captcha {
|
||||
updateAttemptedPstmt.setString(1, uuid)
|
||||
updateAttemptedPstmt.executeUpdate()
|
||||
Id(uuid)
|
||||
} catch {case e: Exception =>
|
||||
println(e)
|
||||
Id(getUUID(-1))
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
println(e)
|
||||
Id(getUUID(-1))
|
||||
}
|
||||
}
|
||||
|
||||
private def getUUID(id: Int): String = {
|
||||
val uuid = UUID.randomUUID().toString
|
||||
val mapPstmt = Statements.tlStmts.get.mapPstmt
|
||||
mapPstmt.setString(1,uuid)
|
||||
mapPstmt.setInt(2,id)
|
||||
mapPstmt.setString(1, uuid)
|
||||
mapPstmt.setInt(2, id)
|
||||
mapPstmt.executeUpdate()
|
||||
uuid
|
||||
}
|
||||
|
||||
def checkAnswer(answer: Answer): Result = {
|
||||
val selectPstmt = Statements.tlStmts.get.selectPstmt
|
||||
selectPstmt.setString(1, answer.id)
|
||||
val rs: ResultSet = selectPstmt.executeQuery()
|
||||
val psOpt = if (rs.first()) {
|
||||
val secret = rs.getString("secret")
|
||||
val provider = rs.getString("provider")
|
||||
val check = CaptchaProviders.getProviderById(provider).checkAnswer(secret, answer.answer)
|
||||
val result = if(check) "TRUE" else "FALSE"
|
||||
result
|
||||
} else {
|
||||
"EXPIRED"
|
||||
}
|
||||
val deleteAnswerPstmt = Statements.tlStmts.get.deleteAnswerPstmt
|
||||
deleteAnswerPstmt.setString(1, answer.id)
|
||||
deleteAnswerPstmt.executeUpdate()
|
||||
Result(psOpt)
|
||||
val selectPstmt = Statements.tlStmts.get.selectPstmt
|
||||
selectPstmt.setString(1, answer.id)
|
||||
val rs: ResultSet = selectPstmt.executeQuery()
|
||||
val psOpt = if (rs.first()) {
|
||||
val secret = rs.getString("secret")
|
||||
val provider = rs.getString("provider")
|
||||
val check = CaptchaProviders.getProviderById(provider).checkAnswer(secret, answer.answer)
|
||||
val result = if (check) "TRUE" else "FALSE"
|
||||
result
|
||||
} else {
|
||||
"EXPIRED"
|
||||
}
|
||||
val deleteAnswerPstmt = Statements.tlStmts.get.deleteAnswerPstmt
|
||||
deleteAnswerPstmt.setString(1, answer.id)
|
||||
deleteAnswerPstmt.executeUpdate()
|
||||
Result(psOpt)
|
||||
}
|
||||
|
||||
def display(): Unit = {
|
||||
val rs: ResultSet = Statements.tlStmts.get.getChallengeTable.executeQuery()
|
||||
println("token\t\tid\t\tsecret\t\tattempted")
|
||||
while(rs.next()) {
|
||||
while (rs.next()) {
|
||||
val token = rs.getInt("token")
|
||||
val id = rs.getString("id")
|
||||
val secret = rs.getString("secret")
|
||||
@@ -111,11 +112,11 @@ class Captcha {
|
||||
|
||||
val rss: ResultSet = Statements.tlStmts.get.getMapIdTable.executeQuery()
|
||||
println("uuid\t\ttoken\t\tlastServed")
|
||||
while(rss.next()){
|
||||
while (rss.next()) {
|
||||
val uuid = rss.getString("uuid")
|
||||
val token = rss.getInt("token")
|
||||
val lastServed = rss.getTimestamp("lastServed")
|
||||
println(s"${uuid}\t\t${token}\t\t${lastServed}\n\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package lc.core
|
||||
|
||||
import lc.captchas._
|
||||
import lc.captchas.interfaces.ChallengeProvider
|
||||
import lc.captchas.interfaces.Challenge
|
||||
|
||||
object CaptchaProviders {
|
||||
private val providers = Map(
|
||||
@@ -9,30 +10,32 @@ object CaptchaProviders {
|
||||
//"FontFunCaptcha" -> new FontFunCaptcha,
|
||||
"GifCaptcha" -> new GifCaptcha,
|
||||
"ShadowTextCaptcha" -> new ShadowTextCaptcha,
|
||||
"RainDropsCaptcha" -> new RainDropsCP,
|
||||
"RainDropsCaptcha" -> new RainDropsCP
|
||||
//"LabelCaptcha" -> new LabelCaptcha
|
||||
)
|
||||
)
|
||||
|
||||
def generateChallengeSamples() = {
|
||||
providers.map {case (key, provider) =>
|
||||
(key, provider.returnChallenge())
|
||||
def generateChallengeSamples(): Map[String, Challenge] = {
|
||||
providers.map {
|
||||
case (key, provider) =>
|
||||
(key, provider.returnChallenge())
|
||||
}
|
||||
}
|
||||
|
||||
private val seed = System.currentTimeMillis.toString.substring(2,6).toInt
|
||||
private val seed = System.currentTimeMillis.toString.substring(2, 6).toInt
|
||||
private val random = new scala.util.Random(seed)
|
||||
|
||||
private def getNextRandomInt(max: Int) = random.synchronized {
|
||||
random.nextInt(max)
|
||||
}
|
||||
private def getNextRandomInt(max: Int) =
|
||||
random.synchronized {
|
||||
random.nextInt(max)
|
||||
}
|
||||
|
||||
def getProviderById(id: String): ChallengeProvider = {
|
||||
return providers(id)
|
||||
}
|
||||
|
||||
|
||||
def getProvider(): ChallengeProvider = {
|
||||
val keys = providers.keys
|
||||
val providerIndex = keys.toVector(getNextRandomInt(keys.size))
|
||||
providers(providerIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ case class Size(height: Int, width: Int)
|
||||
case class Parameters(level: String, media: String, input_type: String, size: Option[Size])
|
||||
case class Id(id: String)
|
||||
case class Answer(answer: String, id: String)
|
||||
case class Result(result: String)
|
||||
case class Result(result: String)
|
||||
|
||||
@@ -2,7 +2,7 @@ package lc.database
|
||||
|
||||
import java.sql._
|
||||
|
||||
class DBConn(){
|
||||
class DBConn() {
|
||||
val con: Connection = DriverManager.getConnection("jdbc:h2:./data/H2/captcha", "sa", "")
|
||||
|
||||
def getStatement(): Statement = {
|
||||
@@ -10,6 +10,6 @@ class DBConn(){
|
||||
}
|
||||
|
||||
def closeConnection(): Unit = {
|
||||
con.close()
|
||||
con.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,30 +2,108 @@ package lc.database
|
||||
|
||||
import lc.database.DBConn
|
||||
import java.sql.Statement
|
||||
import java.sql.PreparedStatement
|
||||
|
||||
class Statements(dbConn: DBConn) {
|
||||
|
||||
private val stmt = dbConn.getStatement()
|
||||
|
||||
stmt.execute("CREATE TABLE IF NOT EXISTS challenge(token int auto_increment, id varchar, secret varchar, provider varchar, contentType varchar, image blob, attempted int default 0, PRIMARY KEY(token))")
|
||||
stmt.execute("CREATE TABLE IF NOT EXISTS mapId(uuid varchar, token int, lastServed timestamp, PRIMARY KEY(uuid), FOREIGN KEY(token) REFERENCES challenge(token) ON DELETE CASCADE)")
|
||||
stmt.execute(
|
||||
"CREATE TABLE IF NOT EXISTS challenge" +
|
||||
"(token int auto_increment, " +
|
||||
"id varchar, " +
|
||||
"secret varchar, " +
|
||||
"provider varchar, " +
|
||||
"contentType varchar, " +
|
||||
"image blob, " +
|
||||
"attempted int default 0, " +
|
||||
"PRIMARY KEY(token))"
|
||||
)
|
||||
stmt.execute(
|
||||
"CREATE TABLE IF NOT EXISTS mapId" +
|
||||
"(uuid varchar, " +
|
||||
"token int, " +
|
||||
"lastServed timestamp, " +
|
||||
"PRIMARY KEY(uuid), " +
|
||||
"FOREIGN KEY(token) " +
|
||||
"REFERENCES challenge(token) " +
|
||||
"ON DELETE CASCADE)"
|
||||
)
|
||||
|
||||
val insertPstmt = dbConn.con.prepareStatement("INSERT INTO challenge(id, secret, provider, contentType, image) VALUES (?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS )
|
||||
val mapPstmt = dbConn.con.prepareStatement("INSERT INTO mapId(uuid, token, lastServed) VALUES (?, ?, CURRENT_TIMESTAMP)")
|
||||
val selectPstmt = dbConn.con.prepareStatement("SELECT c.secret, c.provider FROM challenge c, mapId m WHERE m.token=c.token AND DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, m.lastServed)) > 0 AND m.uuid = ?")
|
||||
val imagePstmt = dbConn.con.prepareStatement("SELECT image FROM challenge c, mapId m WHERE c.token=m.token AND m.uuid = ?")
|
||||
val updateAttemptedPstmt = dbConn.con.prepareStatement("UPDATE challenge SET attempted = attempted+1 WHERE token = (SELECT m.token FROM mapId m, challenge c WHERE m.token=c.token AND m.uuid = ?)")
|
||||
val tokenPstmt = dbConn.con.prepareStatement("SELECT token FROM challenge WHERE attempted < 10 ORDER BY RAND() LIMIT 1")
|
||||
val deleteAnswerPstmt = dbConn.con.prepareStatement("DELETE FROM mapId WHERE uuid = ?")
|
||||
val challengeGCPstmt = dbConn.con.prepareStatement("DELETE FROM challenge WHERE attempted >= 10 AND token NOT IN (SELECT token FROM mapId)")
|
||||
val mapIdGCPstmt = dbConn.con.prepareStatement("DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, lastServed)) < 0")
|
||||
val insertPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"INSERT INTO " +
|
||||
"challenge(id, secret, provider, contentType, image) " +
|
||||
"VALUES (?, ?, ?, ?, ?)",
|
||||
Statement.RETURN_GENERATED_KEYS
|
||||
)
|
||||
|
||||
val mapPstmt: PreparedStatement =
|
||||
dbConn.con.prepareStatement(
|
||||
"INSERT INTO " +
|
||||
"mapId(uuid, token, lastServed) " +
|
||||
"VALUES (?, ?, CURRENT_TIMESTAMP)"
|
||||
)
|
||||
|
||||
val selectPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"SELECT c.secret, c.provider " +
|
||||
"FROM challenge c, mapId m " +
|
||||
"WHERE m.token=c.token AND " +
|
||||
"DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, m.lastServed)) > 0 AND " +
|
||||
"m.uuid = ?"
|
||||
)
|
||||
|
||||
val imagePstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"SELECT image " +
|
||||
"FROM challenge c, mapId m " +
|
||||
"WHERE c.token=m.token AND " +
|
||||
"m.uuid = ?"
|
||||
)
|
||||
|
||||
val updateAttemptedPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"UPDATE challenge " +
|
||||
"SET attempted = attempted+1 " +
|
||||
"WHERE token = (SELECT m.token " +
|
||||
"FROM mapId m, challenge c " +
|
||||
"WHERE m.token=c.token AND " +
|
||||
"m.uuid = ?)"
|
||||
)
|
||||
|
||||
val tokenPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"SELECT token " +
|
||||
"FROM challenge " +
|
||||
"WHERE attempted < 10 " +
|
||||
"ORDER BY RAND() LIMIT 1"
|
||||
)
|
||||
|
||||
val deleteAnswerPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"DELETE FROM mapId WHERE uuid = ?"
|
||||
)
|
||||
|
||||
val challengeGCPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"DELETE FROM challenge " +
|
||||
"WHERE attempted >= 10 AND " +
|
||||
"token NOT IN (SELECT token FROM mapId)"
|
||||
)
|
||||
|
||||
val mapIdGCPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, lastServed)) < 0"
|
||||
)
|
||||
|
||||
val getCountChallengeTable: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"SELECT COUNT(*) AS total FROM challenge"
|
||||
)
|
||||
|
||||
val getChallengeTable: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"SELECT * FROM challenge"
|
||||
)
|
||||
|
||||
val getMapIdTable: PreparedStatement = dbConn.con.prepareStatement(
|
||||
"SELECT * FROM mapId"
|
||||
)
|
||||
|
||||
val getCountChallengeTable = dbConn.con.prepareStatement("SELECT COUNT(*) AS total FROM challenge")
|
||||
val getChallengeTable = dbConn.con.prepareStatement("SELECT * FROM challenge")
|
||||
val getMapIdTable = dbConn.con.prepareStatement("SELECT * FROM mapId")
|
||||
}
|
||||
|
||||
object Statements {
|
||||
private val dbConn: DBConn = new DBConn()
|
||||
val tlStmts = ThreadLocal.withInitial(() => new Statements(dbConn))
|
||||
}
|
||||
val tlStmts: ThreadLocal[Statements] = ThreadLocal.withInitial(() => new Statements(dbConn))
|
||||
}
|
||||
|
||||
@@ -7,46 +7,56 @@ import lc.core.Captcha
|
||||
import lc.core.{Parameters, Id, Answer}
|
||||
import lc.server.HTTPServer
|
||||
|
||||
class Server(port: Int, captcha: Captcha) {
|
||||
val server = new HTTPServer(port)
|
||||
val host: HTTPServer.VirtualHost = server.getVirtualHost(null)
|
||||
|
||||
class Server(port: Int, captcha: Captcha){
|
||||
val server = new HTTPServer(port)
|
||||
val host = server.getVirtualHost(null)
|
||||
implicit val formats: DefaultFormats.type = DefaultFormats
|
||||
|
||||
implicit val formats = DefaultFormats
|
||||
host.addContext(
|
||||
"/v1/captcha",
|
||||
(req, resp) => {
|
||||
val body = req.getJson()
|
||||
val json = parse(body)
|
||||
val param = json.extract[Parameters]
|
||||
val id = captcha.getChallenge(param)
|
||||
resp.getHeaders().add("Content-Type", "application/json")
|
||||
resp.send(200, write(id))
|
||||
0
|
||||
},
|
||||
"POST"
|
||||
)
|
||||
|
||||
host.addContext("/v1/captcha",(req, resp) => {
|
||||
val body = req.getJson()
|
||||
val json = parse(body)
|
||||
val param = json.extract[Parameters]
|
||||
val id = captcha.getChallenge(param)
|
||||
resp.getHeaders().add("Content-Type","application/json")
|
||||
resp.send(200, write(id))
|
||||
0
|
||||
},"POST")
|
||||
host.addContext(
|
||||
"/v1/media",
|
||||
(req, resp) => {
|
||||
val params = req.getParams()
|
||||
val id = Id(params.get("id"))
|
||||
val image = captcha.getCaptcha(id)
|
||||
resp.getHeaders().add("Content-Type", "image/png")
|
||||
resp.send(200, image)
|
||||
0
|
||||
},
|
||||
"GET"
|
||||
)
|
||||
|
||||
host.addContext("/v1/media",(req, resp) => {
|
||||
val params = req.getParams()
|
||||
val id = Id(params.get("id"))
|
||||
val image = captcha.getCaptcha(id)
|
||||
resp.getHeaders().add("Content-Type","image/png")
|
||||
resp.send(200, image)
|
||||
0
|
||||
},"GET")
|
||||
host.addContext(
|
||||
"/v1/answer",
|
||||
(req, resp) => {
|
||||
val body = req.getJson()
|
||||
val json = parse(body)
|
||||
val answer = json.extract[Answer]
|
||||
val result = captcha.checkAnswer(answer)
|
||||
resp.getHeaders().add("Content-Type", "application/json")
|
||||
resp.send(200, write(result))
|
||||
0
|
||||
},
|
||||
"POST"
|
||||
)
|
||||
|
||||
host.addContext("/v1/answer",(req, resp) => {
|
||||
val body = req.getJson()
|
||||
val json = parse(body)
|
||||
val answer = json.extract[Answer]
|
||||
val result = captcha.checkAnswer(answer)
|
||||
resp.getHeaders().add("Content-Type","application/json")
|
||||
resp.send(200, write(result))
|
||||
0
|
||||
},"POST")
|
||||
|
||||
|
||||
def start(): Unit = {
|
||||
println("Starting server on port:" + port)
|
||||
server.start()
|
||||
}
|
||||
def start(): Unit = {
|
||||
println("Starting server on port:" + port)
|
||||
server.start()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user