mirror of
https://github.com/librecaptcha/lc-core.git
synced 2025-01-12 22:43:20 -05:00
Merge pull request #148 from librecaptcha/fix145
Fix for #145: frequent repetition of CAPTCHA challenge
This commit is contained in:
commit
226d3bfa74
@ -18,22 +18,37 @@ class BackgroundTask(config: Config, captchaManager: CaptchaManager) {
|
||||
val challengeGCPstmt = Statements.tlStmts.get.challengeGCPstmt
|
||||
challengeGCPstmt.executeUpdate()
|
||||
|
||||
val imageNumResult = Statements.tlStmts.get.getCountChallengeTable.executeQuery()
|
||||
val imageNum = if (imageNumResult.next()) {
|
||||
imageNumResult.getInt("total")
|
||||
} else {
|
||||
0
|
||||
val allCombinations = allParameterCombinations()
|
||||
val requiredCountPerCombination = Math.max(1, (config.throttle * 1.01) / allCombinations.size).toInt
|
||||
|
||||
for (param <- allCombinations) {
|
||||
val countExisting = captchaManager.getCount(param).getOrElse(0)
|
||||
val countRequired = requiredCountPerCombination - countExisting
|
||||
if (countRequired > 0) {
|
||||
val countCreate = Math.min(1.0 + requiredCountPerCombination/10.0, countRequired).toInt
|
||||
println(s"Creating $countCreate of $countRequired captchas for $param")
|
||||
|
||||
for (i <- 0 until countCreate) {
|
||||
captchaManager.generateChallenge(param)
|
||||
}
|
||||
}
|
||||
|
||||
val throttle = (config.throttle * 1.1).toInt - imageNum
|
||||
|
||||
for (i <- 0 until throttle) {
|
||||
captchaManager.generateChallenge(getRandomParam())
|
||||
}
|
||||
} catch { case exception: Exception => println(exception) }
|
||||
}
|
||||
}
|
||||
|
||||
private def allParameterCombinations(): List[Parameters] = {
|
||||
(config.captchaConfig).flatMap {captcha =>
|
||||
(captcha.allowedLevels).flatMap {level =>
|
||||
(captcha.allowedMedia).flatMap {media =>
|
||||
(captcha.allowedInputType).map {inputType =>
|
||||
Parameters(level, media, inputType, Some(Size(0, 0)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def getRandomParam(): Parameters = {
|
||||
val captcha = pickRandom(config.captchaConfig)
|
||||
val level = pickRandom(captcha.allowedLevels)
|
||||
|
@ -105,11 +105,29 @@ class CaptchaManager(config: Config, captchaProviders: CaptchaProviders) {
|
||||
}
|
||||
}
|
||||
|
||||
def getCount(param: Parameters): Option[Int] = {
|
||||
val countPstmt = Statements.tlStmts.get.countForParameterPstmt
|
||||
countPstmt.setString(1, param.level)
|
||||
countPstmt.setString(2, param.media)
|
||||
countPstmt.setString(3, param.input_type)
|
||||
val rs = countPstmt.executeQuery()
|
||||
if (rs.next()) {
|
||||
Some(rs.getInt("count"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
private def getToken(param: Parameters): Option[Int] = {
|
||||
val count = getCount(param).getOrElse(0)
|
||||
if (count == 0) {
|
||||
None
|
||||
} else {
|
||||
val tokenPstmt = Statements.tlStmts.get.tokenPstmt
|
||||
tokenPstmt.setString(1, param.level)
|
||||
tokenPstmt.setString(2, param.media)
|
||||
tokenPstmt.setString(3, param.input_type)
|
||||
tokenPstmt.setInt(4, count)
|
||||
val rs = tokenPstmt.executeQuery()
|
||||
if (rs.next()) {
|
||||
Some(rs.getInt("token"))
|
||||
@ -117,6 +135,7 @@ class CaptchaManager(config: Config, captchaProviders: CaptchaProviders) {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def updateAttempted(token: Int): Unit = {
|
||||
val updateAttemptedPstmt = Statements.tlStmts.get.updateAttemptedPstmt
|
||||
|
@ -70,6 +70,17 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
|
||||
"WHERE token = ?;"
|
||||
)
|
||||
|
||||
val countForParameterPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
s"""
|
||||
SELECT count(*) as count
|
||||
FROM challenge
|
||||
WHERE attempted < $maxAttempts AND
|
||||
contentLevel = ? AND
|
||||
contentType = ? AND
|
||||
contentInput = ?
|
||||
"""
|
||||
)
|
||||
|
||||
val tokenPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
s"""
|
||||
SELECT token, attempted
|
||||
@ -78,7 +89,9 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
|
||||
contentLevel = ? AND
|
||||
contentType = ? AND
|
||||
contentInput = ?
|
||||
ORDER BY attempted ASC LIMIT 1"""
|
||||
LIMIT 1
|
||||
OFFSET FLOOR(RAND()*?)
|
||||
"""
|
||||
)
|
||||
|
||||
val deleteAnswerPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||
|
Loading…
Reference in New Issue
Block a user