diff --git a/src/main/java/lc/captchas/FontFunCaptcha.java b/src/main/java/lc/captchas/FontFunCaptcha.java
index 8dbea52..6cf533c 100644
--- a/src/main/java/lc/captchas/FontFunCaptcha.java
+++ b/src/main/java/lc/captchas/FontFunCaptcha.java
@@ -81,7 +81,7 @@ public class FontFunCaptcha implements ChallengeProvider {
return baos.toByteArray();
}
- public Challenge returnChallenge() {
+ public Challenge returnChallenge(String level, String size) {
String secret = HelperFunctions.randomString(7);
String path = "./lib/fonts/";
return new Challenge(fontFun(secret, "medium", path), "image/png", secret.toLowerCase());
diff --git a/src/main/java/lc/captchas/PoppingCharactersCaptcha.java b/src/main/java/lc/captchas/PoppingCharactersCaptcha.java
index 0ffa4df..5027891 100644
--- a/src/main/java/lc/captchas/PoppingCharactersCaptcha.java
+++ b/src/main/java/lc/captchas/PoppingCharactersCaptcha.java
@@ -100,7 +100,7 @@ public class PoppingCharactersCaptcha implements ChallengeProvider {
"supportedInputType", List.of("text"));
}
- public Challenge returnChallenge() {
+ public Challenge returnChallenge(String level, String size) {
final var secret = HelperFunctions.randomString(6);
return new Challenge(gifCaptcha(secret), "image/gif", secret.toLowerCase());
}
diff --git a/src/main/java/lc/captchas/ShadowTextCaptcha.java b/src/main/java/lc/captchas/ShadowTextCaptcha.java
index a797c50..7e9b71b 100644
--- a/src/main/java/lc/captchas/ShadowTextCaptcha.java
+++ b/src/main/java/lc/captchas/ShadowTextCaptcha.java
@@ -74,7 +74,7 @@ public class ShadowTextCaptcha implements ChallengeProvider {
return baos.toByteArray();
}
- public Challenge returnChallenge() {
+ public Challenge returnChallenge(String level, String size) {
String secret = HelperFunctions.randomString(6);
return new Challenge(shadowText(secret), "image/png", secret.toLowerCase());
}
diff --git a/src/main/java/lc/captchas/interfaces/ChallengeProvider.java b/src/main/java/lc/captchas/interfaces/ChallengeProvider.java
index a3a70e2..f445a7d 100644
--- a/src/main/java/lc/captchas/interfaces/ChallengeProvider.java
+++ b/src/main/java/lc/captchas/interfaces/ChallengeProvider.java
@@ -6,7 +6,7 @@ import java.util.List;
public interface ChallengeProvider {
public String getId();
- public Challenge returnChallenge();
+ public Challenge returnChallenge(String level, String size);
public boolean checkAnswer(String secret, String answer);
diff --git a/src/main/resources/index.html b/src/main/resources/index.html
index db1a33b..9321607 100644
--- a/src/main/resources/index.html
+++ b/src/main/resources/index.html
@@ -20,9 +20,10 @@
const levelInput = document.getElementById("levelInput").value
const mediaInput = document.getElementById("mediaInput").value
const typeInput = document.getElementById("typeInput").value
- fetch("/v1/captcha", {
+ const sizeInput = document.getElementById("sizeInput").value
+ fetch("/v2/captcha", {
method: 'POST',
- body: JSON.stringify({level: levelInput, media: mediaInput, "input_type" : typeInput})
+ body: JSON.stringify({level: levelInput, media: mediaInput, "input_type" : typeInput, "size": sizeInput})
}).then(async function(resp) {
const respJson = await resp.json()
if (resp.ok) {
@@ -30,7 +31,7 @@
const resultDiv = document.getElementById("result")
const result = `
Id: ${id}
-
+
@@ -43,7 +44,7 @@
}
async function submitAnswer(id) {
const ans = document.getElementById("answerInput").value;
- const resp = await fetch("/v1/answer", {
+ const resp = await fetch("/v2/answer", {
method: 'POST',
body: JSON.stringify({id: id, answer: ans})
})
@@ -70,6 +71,10 @@
Input Type
+
+ Input Size
+
+
diff --git a/src/main/scala/lc/background/taskThread.scala b/src/main/scala/lc/background/taskThread.scala
index 431c93e..98b05b9 100644
--- a/src/main/scala/lc/background/taskThread.scala
+++ b/src/main/scala/lc/background/taskThread.scala
@@ -45,8 +45,10 @@ class BackgroundTask(config: Config, captchaManager: CaptchaManager) {
(config.captchaConfig).flatMap {captcha =>
(captcha.allowedLevels).flatMap {level =>
(captcha.allowedMedia).flatMap {media =>
- (captcha.allowedInputType).map {inputType =>
- Parameters(level, media, inputType, Some(Size(0, 0)))
+ (captcha.allowedInputType).flatMap {inputType =>
+ (captcha.allowedSizes).map {size =>
+ Parameters(level, media, inputType, size)
+ }
}
}
}
@@ -58,8 +60,9 @@ class BackgroundTask(config: Config, captchaManager: CaptchaManager) {
val level = pickRandom(captcha.allowedLevels)
val media = pickRandom(captcha.allowedMedia)
val inputType = pickRandom(captcha.allowedInputType)
+ val size = pickRandom(captcha.allowedSizes)
- Parameters(level, media, inputType, Some(Size(0, 0)))
+ Parameters(level, media, inputType, size)
}
private def pickRandom[T](list: List[T]): T = {
diff --git a/src/main/scala/lc/captchas/DebugCaptcha.scala b/src/main/scala/lc/captchas/DebugCaptcha.scala
index b0ca809..4f2bbb0 100644
--- a/src/main/scala/lc/captchas/DebugCaptcha.scala
+++ b/src/main/scala/lc/captchas/DebugCaptcha.scala
@@ -66,7 +66,7 @@ class DebugCaptcha extends ChallengeProvider {
baos.toByteArray()
}
- def returnChallenge(): Challenge = {
+ def returnChallenge(level: String, size: String): Challenge = {
val secret = HelperFunctions.randomString(6, HelperFunctions.safeAlphabets)
new Challenge(simpleText(secret), "image/png", secret.toLowerCase())
}
diff --git a/src/main/scala/lc/captchas/FilterChallenge.scala b/src/main/scala/lc/captchas/FilterChallenge.scala
index 5f83ff6..ef3bbc2 100644
--- a/src/main/scala/lc/captchas/FilterChallenge.scala
+++ b/src/main/scala/lc/captchas/FilterChallenge.scala
@@ -29,7 +29,7 @@ class FilterChallenge extends ChallengeProvider {
)
}
- def returnChallenge(): Challenge = {
+ def returnChallenge(level: String, size: String): Challenge = {
val filterTypes = List(new FilterType1, new FilterType2)
val r = new scala.util.Random
val alphabet = "abcdefghijklmnopqrstuvwxyz"
diff --git a/src/main/scala/lc/captchas/LabelCaptcha.scala b/src/main/scala/lc/captchas/LabelCaptcha.scala
index 5173346..3a02770 100644
--- a/src/main/scala/lc/captchas/LabelCaptcha.scala
+++ b/src/main/scala/lc/captchas/LabelCaptcha.scala
@@ -40,7 +40,7 @@ class LabelCaptcha extends ChallengeProvider {
)
}
- def returnChallenge(): Challenge =
+ def returnChallenge(level: String, size: String): Challenge =
synchronized {
val r = scala.util.Random.nextInt(knownFiles.length)
val s = scala.util.Random.nextInt(unknownFiles.length)
diff --git a/src/main/scala/lc/captchas/RainDropsCaptcha.scala b/src/main/scala/lc/captchas/RainDropsCaptcha.scala
index 9e8f6f3..02dfd88 100644
--- a/src/main/scala/lc/captchas/RainDropsCaptcha.scala
+++ b/src/main/scala/lc/captchas/RainDropsCaptcha.scala
@@ -56,7 +56,7 @@ class RainDropsCP extends ChallengeProvider {
})
}
- def returnChallenge(): Challenge = {
+ def returnChallenge(level: String, size: String): Challenge = {
val r = new scala.util.Random
val secret = LazyList.continually(r.nextInt(alphabet.size)).map(alphabet).take(n).mkString
val width = 450
diff --git a/src/main/scala/lc/core/captchaFields.scala b/src/main/scala/lc/core/captchaFields.scala
index acc9f00..ee0285c 100644
--- a/src/main/scala/lc/core/captchaFields.scala
+++ b/src/main/scala/lc/core/captchaFields.scala
@@ -10,7 +10,7 @@ object ParametersEnum extends Enumeration {
val ALLOWEDLEVELS: Value = Value("allowedLevels")
val ALLOWEDMEDIA: Value = Value("allowedMedia")
val ALLOWEDINPUTTYPE: Value = Value("allowedInputType")
-
+ val ALLOWEDSIZES: Value = Value("allowedSizes")
}
object AttributesEnum extends Enumeration {
diff --git a/src/main/scala/lc/core/captchaManager.scala b/src/main/scala/lc/core/captchaManager.scala
index 96620bf..2df9c42 100644
--- a/src/main/scala/lc/core/captchaManager.scala
+++ b/src/main/scala/lc/core/captchaManager.scala
@@ -36,11 +36,11 @@ class CaptchaManager(config: Config, captchaProviders: CaptchaProviders) {
def generateChallenge(param: Parameters): Option[Int] = {
captchaProviders.getProvider(param).flatMap { provider =>
val providerId = provider.getId()
- val challenge = provider.returnChallenge()
- val blob = new ByteArrayInputStream(challenge.content)
+ val challenge = provider.returnChallenge(param.level, param.size)
+ val blob = new ByteArrayInputStream(challenge.content)
val token = insertCaptcha(provider, challenge, providerId, param, blob)
- // println("Added new challenge: " + token.toString)
- token.map(_.toInt)
+ // println("Added new challenge: " + token.toString)
+ token.map(_.toInt)
}
}
@@ -58,7 +58,8 @@ class CaptchaManager(config: Config, captchaProviders: CaptchaProviders) {
insertPstmt.setString(4, challenge.contentType)
insertPstmt.setString(5, param.level)
insertPstmt.setString(6, param.input_type)
- insertPstmt.setBlob(7, blob)
+ insertPstmt.setString(7, param.size)
+ insertPstmt.setBlob(8, blob)
insertPstmt.executeUpdate()
val rs: ResultSet = insertPstmt.getGeneratedKeys()
if (rs.next()) {
@@ -106,6 +107,7 @@ class CaptchaManager(config: Config, captchaProviders: CaptchaProviders) {
countPstmt.setString(1, param.level)
countPstmt.setString(2, param.media)
countPstmt.setString(3, param.input_type)
+ countPstmt.setString(4, param.size.toString())
val rs = countPstmt.executeQuery()
if (rs.next()) {
Some(rs.getInt("count"))
@@ -123,7 +125,8 @@ class CaptchaManager(config: Config, captchaProviders: CaptchaProviders) {
tokenPstmt.setString(1, param.level)
tokenPstmt.setString(2, param.media)
tokenPstmt.setString(3, param.input_type)
- tokenPstmt.setInt(4, count)
+ tokenPstmt.setString(4, param.size)
+ tokenPstmt.setInt(5, count)
val rs = tokenPstmt.executeQuery()
if (rs.next()) {
Some(rs.getInt("token"))
diff --git a/src/main/scala/lc/core/captchaProviders.scala b/src/main/scala/lc/core/captchaProviders.scala
index e2ed404..058d535 100644
--- a/src/main/scala/lc/core/captchaProviders.scala
+++ b/src/main/scala/lc/core/captchaProviders.scala
@@ -19,7 +19,7 @@ class CaptchaProviders(config: Config) {
def generateChallengeSamples(): Map[String, Challenge] = {
providers.map { case (key, provider) =>
- (key, provider.returnChallenge())
+ (key, provider.returnChallenge("easy", "350x100"))
}
}
@@ -35,6 +35,7 @@ class CaptchaProviders(config: Config) {
if configValue.allowedLevels.contains(param.level)
if configValue.allowedMedia.contains(param.media)
if configValue.allowedInputType.contains(param.input_type)
+ if configValue.allowedSizes.contains(param.size)
} yield (configValue.name, configValue.config)
val providerFilter = for {
diff --git a/src/main/scala/lc/core/config.scala b/src/main/scala/lc/core/config.scala
index 04241ba..dfbab88 100644
--- a/src/main/scala/lc/core/config.scala
+++ b/src/main/scala/lc/core/config.scala
@@ -81,6 +81,7 @@ class Config(configFilePath: String) {
(ParametersEnum.ALLOWEDLEVELS.toString -> List("medium", "hard")) ~
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/png")) ~
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
+ (ParametersEnum.ALLOWEDSIZES.toString -> List("350x100")) ~
(AttributesEnum.CONFIG.toString -> JObject())
),
(
@@ -88,6 +89,7 @@ class Config(configFilePath: String) {
(ParametersEnum.ALLOWEDLEVELS.toString -> List("hard")) ~
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/gif")) ~
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
+ (ParametersEnum.ALLOWEDSIZES.toString -> List("350x100")) ~
(AttributesEnum.CONFIG.toString -> JObject())
),
(
@@ -95,6 +97,7 @@ class Config(configFilePath: String) {
(ParametersEnum.ALLOWEDLEVELS.toString -> List("easy")) ~
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/png")) ~
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
+ (ParametersEnum.ALLOWEDSIZES.toString -> List("350x100")) ~
(AttributesEnum.CONFIG.toString -> JObject())
),
(
@@ -102,6 +105,7 @@ class Config(configFilePath: String) {
(ParametersEnum.ALLOWEDLEVELS.toString -> List("easy", "medium")) ~
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/gif")) ~
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
+ (ParametersEnum.ALLOWEDSIZES.toString -> List("350x100")) ~
(AttributesEnum.CONFIG.toString -> JObject())
)
))
diff --git a/src/main/scala/lc/core/models.scala b/src/main/scala/lc/core/models.scala
index d2941d7..f496d57 100644
--- a/src/main/scala/lc/core/models.scala
+++ b/src/main/scala/lc/core/models.scala
@@ -4,8 +4,9 @@ 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: String)
case class Id(id: String) extends ByteConvert { def toBytes(): Array[Byte] = { write(this).getBytes } }
case class Image(image: Array[Byte]) extends ByteConvert { def toBytes(): Array[Byte] = { image } }
case class Answer(answer: String, id: String)
@@ -16,6 +17,7 @@ case class CaptchaConfig(
allowedLevels: List[String],
allowedMedia: List[String],
allowedInputType: List[String],
+ allowedSizes: List[String],
config: String
)
case class ConfigField(
diff --git a/src/main/scala/lc/database/DB.scala b/src/main/scala/lc/database/DB.scala
index ee6532f..3acc3ce 100644
--- a/src/main/scala/lc/database/DB.scala
+++ b/src/main/scala/lc/database/DB.scala
@@ -3,7 +3,7 @@ package lc.database
import java.sql.{Connection, DriverManager, Statement}
class DBConn() {
- val con: Connection = DriverManager.getConnection("jdbc:h2:./data/H2/captcha2;MAX_COMPACT_TIME=8000;DB_CLOSE_ON_EXIT=FALSE", "sa", "")
+ val con: Connection = DriverManager.getConnection("jdbc:h2:./data/H2/captcha3;MAX_COMPACT_TIME=8000;DB_CLOSE_ON_EXIT=FALSE", "sa", "")
def getStatement(): Statement = {
con.createStatement()
diff --git a/src/main/scala/lc/database/statements.scala b/src/main/scala/lc/database/statements.scala
index bc89fb4..599e876 100644
--- a/src/main/scala/lc/database/statements.scala
+++ b/src/main/scala/lc/database/statements.scala
@@ -17,6 +17,7 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
"contentType varchar, " +
"contentLevel varchar, " +
"contentInput varchar, " +
+ "size varchar, " +
"image blob, " +
"attempted int default 0, " +
"PRIMARY KEY(token));" +
@@ -37,8 +38,8 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
val insertPstmt: PreparedStatement = dbConn.con.prepareStatement(
"INSERT INTO " +
- "challenge(id, secret, provider, contentType, contentLevel, contentInput, image) " +
- "VALUES (?, ?, ?, ?, ?, ?, ?)",
+ "challenge(id, secret, provider, contentType, contentLevel, contentInput, size, image) " +
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS
)
@@ -77,7 +78,8 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
WHERE attempted < $maxAttempts AND
contentLevel = ? AND
contentType = ? AND
- contentInput = ?
+ contentInput = ? AND
+ size = ?
"""
)
@@ -88,7 +90,8 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
WHERE attempted < $maxAttempts AND
contentLevel = ? AND
contentType = ? AND
- contentInput = ?
+ contentInput = ? AND
+ size = ?
LIMIT 1
OFFSET FLOOR(RAND()*?)
"""
diff --git a/src/main/scala/lc/server/Server.scala b/src/main/scala/lc/server/Server.scala
index da8f3cf..12cc416 100644
--- a/src/main/scala/lc/server/Server.scala
+++ b/src/main/scala/lc/server/Server.scala
@@ -23,7 +23,7 @@ class Server(address: String, port: Int, captchaManager: CaptchaManager, playgro
.address(new InetSocketAddress(address, port))
.backlog(32)
.POST(
- "/v1/captcha",
+ "/v2/captcha",
(request) => {
val json = parse(request.getBodyString())
val param = json.extract[Parameters]
@@ -32,7 +32,7 @@ class Server(address: String, port: Int, captchaManager: CaptchaManager, playgro
}
)
.GET(
- "/v1/media",
+ "/v2/media",
(request) => {
val params = request.getQueryParams()
val result = if (params.containsKey("id")) {
@@ -46,7 +46,7 @@ class Server(address: String, port: Int, captchaManager: CaptchaManager, playgro
}
)
.POST(
- "/v1/answer",
+ "/v2/answer",
(request) => {
val json = parse(request.getBodyString())
val answer = json.extract[Answer]
@@ -70,7 +70,7 @@ class Server(address: String, port: Int, captchaManager: CaptchaManager, playgro
Welcome to LibreCaptcha server
- API is served at /v1/
+ API is served at /v2/
"""
new StringResponse(200, str)