mirror of
https://github.com/librecaptcha/lc-core.git
synced 2025-02-13 03:38:06 -05:00
Initial commit for the framework
The ChallengeProvider trait provides the methods to be implemented by the challenge providers. The framework gets a challenge from a challenge provider, inserts the details of the challenge into the database, and gives the challenge to the user. It then gets the answer from the user, and sends it to the challenge provider for verification. This commit includes the implementation only for FilterChallenge provider.
This commit is contained in:
parent
758eb4d9b9
commit
f73f2a762f
@ -16,3 +16,5 @@ lazy val root = (project in file(".")).
|
||||
libraryDependencies += "com.sksamuel.scrimage" %% "scrimage-filters" % "2.1.8"
|
||||
|
||||
)
|
||||
|
||||
fork in run := true
|
||||
|
BIN
lib/h2-1.4.197.jar
Executable file
BIN
lib/h2-1.4.197.jar
Executable file
Binary file not shown.
@ -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
|
||||
}
|
||||
}
|
@ -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)
|
@ -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")
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
79
src/main/scala/lc/Main.scala
Normal file
79
src/main/scala/lc/Main.scala
Normal file
@ -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()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user