diff --git a/build.sbt b/build.sbt index 40c8e58..35db712 100644 --- a/build.sbt +++ b/build.sbt @@ -16,3 +16,5 @@ lazy val root = (project in file(".")). libraryDependencies += "com.sksamuel.scrimage" %% "scrimage-filters" % "2.1.8" ) + +fork in run := true diff --git a/lib/h2-1.4.197.jar b/lib/h2-1.4.197.jar new file mode 100755 index 0000000..5f311db Binary files /dev/null and b/lib/h2-1.4.197.jar differ diff --git a/src/main/scala/BlurCaptcha.scala b/src/main/scala/BlurCaptcha.scala deleted file mode 100644 index e753250..0000000 --- a/src/main/scala/BlurCaptcha.scala +++ /dev/null @@ -1,24 +0,0 @@ -import com.sksamuel.scrimage._ -import com.sksamuel.scrimage.filter.GaussianBlurFilter -import java.io._ - -class BlurCaptcha extends CaptchaProvider { - val tokenAnswer = scala.collection.mutable.Map[String, String]() - val imageFiles = new File("known").listFiles.toList - def getChallenge(): (Challenge) = { - val r = scala.util.Random.nextInt(imageFiles.length) - val chosenImage = imageFiles(r) - var image = Image.fromStream(new FileInputStream(chosenImage)) - val blur = new GaussianBlurFilter(5) - blur.apply(image) - val s = scala.util.Random - val token = s.nextInt(10000).toString - val challenge = new Challenge(token, image) - val answer = "about" - tokenAnswer += token -> answer - challenge - } - def checkAnswer(token: String, input: String): Boolean = { - tokenAnswer(token) == input - } -} diff --git a/src/main/scala/LabelCaptcha.scala b/src/main/scala/LabelCaptcha.scala deleted file mode 100644 index bcfab82..0000000 --- a/src/main/scala/LabelCaptcha.scala +++ /dev/null @@ -1,68 +0,0 @@ -import java.io.File -import javax.imageio.ImageIO -import scala.collection.mutable.Map -import java.nio.file.{Files,Path,StandardCopyOption} -import java.awt.image.BufferedImage -import java.awt.{Graphics2D,Color} - -class LabelCaptcha extends CaptchaProvider { - var knownFiles = new File("known").list.toList - var unknownFiles = new File("unknown").list.toList - val tokenImagePair = Map[String, ImagePair]() - val unknownAnswers = Map[String, Map[String, Int]]() - val total = Map[String, Int]() - for(file <- unknownFiles) { - unknownAnswers += file -> Map[String, Int]() - total += file -> 0 - } - def getChallenge(): 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) - val token = scala.util.Random.nextInt(10000).toString - tokenImagePair += token -> ip - var knownImage = ImageIO.read(new File("known/"+knownImageFile)) - var unknownImage = ImageIO.read(new File("unknown/"+unknownImageFile)) - 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) - val g = finalImage.createGraphics() - g.setColor(Color.WHITE) - g.fillRect(0, 0, finalImage.getWidth(), finalImage.getHeight()) - g.drawImage(knownImage, null, 0, 0) - g.drawImage(unknownImage, null, knownImage.getWidth(), 0) - g.dispose() - val challenge = new Challenge(token, finalImage) - challenge - } - def checkAnswer(token: String, input: String): Boolean = synchronized { - val expectedAnswer = tokenImagePair(token).known.split('.')(0) - val userAnswer = input.split(' ') - if(userAnswer(0)==expectedAnswer) { - val unknownFile = tokenImagePair(token).unknown - 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 - } - } -} - -class ImagePair(val known: String, val unknown: String) diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala deleted file mode 100644 index a684bd6..0000000 --- a/src/main/scala/Main.scala +++ /dev/null @@ -1,43 +0,0 @@ -import com.sksamuel.scrimage._ -import java.io._ - -class CaptchaLibrary { - val captchas = List(new BlurCaptcha, new LabelCaptcha, new FilterCaptcha) - var tokenCaptcha = scala.collection.mutable.Map[String, CaptchaProvider]() - def init = {} - def shutdown = {} - def getChallenge(): Challenge = { - //choose a captcha provider randomly - val r = scala.util.Random.nextInt(2) - val captchaInstance = captchas(r) - val challenge = captchaInstance.getChallenge() - tokenCaptcha += challenge.token -> captchaInstance - challenge - } - def checkAnswer(token: String, input: String): Boolean = { - val result = tokenCaptcha(token).checkAnswer(token, input) - result - } -} - -trait CaptchaProvider { - def getChallenge(): (Challenge) - def checkAnswer(token: String, input: String): Boolean -} - -class Challenge(val token: String, val image: Image) - -class Answer(val token: String, val input: String) - -object LibreCaptcha { - def main(args: Array[String]) { - val captcha = new CaptchaLibrary - val challenge = captcha.getChallenge() - println(s"Token: ${challenge.token}") - challenge.image.output(new File("Captcha.png")) - println("Enter your answer: ") - val input = scala.io.StdIn.readLine() - val result = captcha.checkAnswer(challenge.token, input) - println(s"Result: $result") - } -} diff --git a/src/main/scala/FilterCaptcha.scala b/src/main/scala/lc/FilterChallenge.scala similarity index 73% rename from src/main/scala/FilterCaptcha.scala rename to src/main/scala/lc/FilterChallenge.scala index 3ae2c86..7cd6f89 100644 --- a/src/main/scala/FilterCaptcha.scala +++ b/src/main/scala/lc/FilterChallenge.scala @@ -1,36 +1,34 @@ +package lc + import com.sksamuel.scrimage._ import com.sksamuel.scrimage.filter._ import java.awt.image.BufferedImage -import java.awt.{Graphics2D,Color,Font} +import java.awt.Font +import java.awt.Color -class FilterCaptcha extends CaptchaProvider { - val tokenAnswer = scala.collection.mutable.Map[String, String]() - def getChallenge(): Challenge = { +class FilterChallenge extends ChallengeProvider { + val id = "filter" + def returnChallenge(): (Image, String) = { val filterTypes = List(new FilterType1, new FilterType2) val r = new scala.util.Random val alphabet = "abcdefghijklmnopqrstuvwxyz" val n = 8 - val answer = Stream.continually(r.nextInt(alphabet.size)).map(alphabet).take(n).mkString - val token = scala.util.Random.nextInt(10000).toString - synchronized { - tokenAnswer += token -> answer - } + val secret = Stream.continually(r.nextInt(alphabet.size)).map(alphabet).take(n).mkString val canvas = new BufferedImage(225, 50, BufferedImage.TYPE_INT_RGB) val g = canvas.createGraphics() g.setColor(Color.WHITE) g.fillRect(0, 0, canvas.getWidth, canvas.getHeight) g.setColor(Color.BLACK) g.setFont(new Font("Serif", Font.PLAIN, 30)) - g.drawString(answer, 5, 30) + g.drawString(secret, 5, 30) g.dispose() var image = new Image(canvas, ImageMetadata.empty) val s = scala.util.Random.nextInt(2) image = filterTypes(s).applyFilter(image) - val challenge = new Challenge(token, image) - challenge + (image, secret) } - def checkAnswer(token: String, input: String): Boolean = { - tokenAnswer(token) == input + def checkAnswer(secret: String, answer: String): Boolean = { + secret == answer } } @@ -61,3 +59,4 @@ class FilterType2 extends FilterType { image } } + diff --git a/src/main/scala/lc/Main.scala b/src/main/scala/lc/Main.scala new file mode 100644 index 0000000..8b65960 --- /dev/null +++ b/src/main/scala/lc/Main.scala @@ -0,0 +1,79 @@ +package lc + +import com.sksamuel.scrimage._ +import java.sql._ +import java.io._ + +trait ChallengeProvider { + val id: String + def returnChallenge(): (Image, String) + def checkAnswer(secret: String, answer: String): Boolean + //TODO: def configure(): Unit +} + +class Captcha { + val con: Connection = DriverManager.getConnection("jdbc:h2:./captcha", "sa", "") + val stmt: Statement = con.createStatement(); + stmt.execute("CREATE TABLE IF NOT EXISTS challenge(token varchar, id varchar, secret varchar, image blob)"); + + def getCaptcha(): Boolean = { + val provider = new FilterChallenge + val (token, image) = this.getChallenge(provider) + val stmt: Statement = con.createStatement(); + image.output(new File("Captcha.png")) + println(s"Token: ${token}") + println("Enter your answer: ") + val answer = scala.io.StdIn.readLine() + this.getAnswer(token, answer, provider) + } + + def getChallenge(provider: ChallengeProvider): (String, Image) = { + val (image, secret) = provider.returnChallenge() + val token = scala.util.Random.nextInt(10000).toString + var pstmt: PreparedStatement = null + pstmt = con.prepareStatement("INSERT INTO challenge(token, id, secret) VALUES (?, ?, ?)") + pstmt.setString(1, token) + pstmt.setString(2, provider.id) + pstmt.setString(3, secret) + //TODO: insert image into database + pstmt.executeUpdate() + (token, image) + } + + def getAnswer(token: String, answer: String, provider: ChallengeProvider): Boolean = { + val stmt: Statement = con.createStatement(); + val rs: ResultSet = stmt.executeQuery("SELECT secret FROM challenge WHERE token = "+token); + rs.next() + val secret = rs.getString("secret") + provider.checkAnswer(secret, answer) + } + + def display(): Unit = { + val stmt: Statement = con.createStatement(); + val rs: ResultSet = stmt.executeQuery("SELECT * FROM challenge"); + + println("token\t\tid\t\tsecret\t\timage"); + while(rs.next()) { + val token = rs.getString("token"); + val id = rs.getString("id"); + val secret = rs.getString("secret"); + val image = rs.getString("image"); + println(s"${token}\t\t${id}\t\t${secret}\t\t${image}") + } + } + + def closeConnection(): Unit = { + con.close() + } +} + +object LCFramework{ + def main(args: scala.Array[String]) { + val captcha = new Captcha + val result = captcha.getCaptcha() + println(result) + captcha.display() + captcha.closeConnection() + } +} +