Merge pull request #2 from SanBlig/init

This adds two additional types of captchas - LabelCaptcha and FilterCaptcha
This commit is contained in:
hrj 2018-01-07 13:38:47 +05:30 committed by GitHub
commit 758eb4d9b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 189 additions and 24 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
*.class
*.log
/bin/

View File

@ -1 +1,13 @@
# lc-core
# lc-core
a Captcha framework
Currently, the following example Captchas are provided by LibreCaptcha:
`BlurCaptcha`
An image of a word is blurred before being shown to the user.
`LabelCaptcha`
An image that has a pair of words is created. The answer to one of the words is known and to that of the other is unknown. The user is tested on the known word, and their answer to the unknown word is recorded. If a sufficient number of users agree on their answer to the unknown word, it is transferred to the list of known words.
`FilterCaptcha`
An image of a random string of alphabets is created. Then a series of image filters that add effecs such as Smear, Diffuse, and Ripple are applied to the image to make it less readable.

View File

@ -0,0 +1,24 @@
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
}
}

View File

@ -0,0 +1,63 @@
import com.sksamuel.scrimage._
import com.sksamuel.scrimage.filter._
import java.awt.image.BufferedImage
import java.awt.{Graphics2D,Color,Font}
class FilterCaptcha extends CaptchaProvider {
val tokenAnswer = scala.collection.mutable.Map[String, String]()
def getChallenge(): Challenge = {
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 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.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
}
def checkAnswer(token: String, input: String): Boolean = {
tokenAnswer(token) == input
}
}
trait FilterType {
def applyFilter(image: Image): Image
}
class FilterType1 extends FilterType {
override def applyFilter(image: Image): Image = {
val blur = new GaussianBlurFilter(2)
val smear = new SmearFilter(com.sksamuel.scrimage.filter.SmearType.Circles, 10, 10, 10, 0, 1)
val diffuse = new DiffuseFilter(2)
blur.apply(image)
diffuse.apply(image)
smear.apply(image)
image
}
}
class FilterType2 extends FilterType {
override def applyFilter(image: Image): Image = {
val smear = new SmearFilter(com.sksamuel.scrimage.filter.SmearType.Circles, 10, 10, 10, 0, 1)
val diffuse = new DiffuseFilter(1)
val ripple = new RippleFilter(com.sksamuel.scrimage.filter.RippleType.Noise, 1, 1, 0.005.toFloat, 0.005.toFloat)
diffuse.apply(image)
ripple.apply(image)
smear.apply(image)
image
}
}

View File

@ -0,0 +1,68 @@
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)

View File

@ -2,45 +2,42 @@ import com.sksamuel.scrimage._
import java.io._
class CaptchaLibrary {
var tokenAnswer = scala.collection.mutable.Map[String, String]()
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 blurCaptcha = new BlurCaptcha
val (challenge, answer) = blurCaptcha.getChallenge()
tokenAnswer += challenge.token->answer
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 = {
if (tokenAnswer(token) == input) {
true
}
else {
false
}
val result = tokenCaptcha(token).checkAnswer(token, input)
result
}
}
trait CaptchaProvider {
def getChallenge(): (Challenge, String)
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)
class BlurCaptcha extends CaptchaProvider {
def getChallenge(): (Challenge, String) = {
val inFileName = "image2.png"
var image = Image.fromStream(new FileInputStream(inFileName))
image = image.filter(com.sksamuel.scrimage.filter.BlurFilter)
image.output(new File("blur.png"))
val r = scala.util.Random
val token = r.nextInt(1000).toString
val challenge = new Challenge(token, image)
val answer = "about"
(challenge, answer)
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")
}
}