mirror of
https://github.com/librecaptcha/lc-core.git
synced 2025-01-27 13:03:12 -05:00
Merge pull request #90 from rr83019/BT-captcha
Background Thread - Random Captcha Generation
This commit is contained in:
commit
6196a34aae
@ -23,6 +23,7 @@ scalacOptions ++= List(
|
|||||||
)
|
)
|
||||||
javacOptions += "-g:none"
|
javacOptions += "-g:none"
|
||||||
compileOrder := CompileOrder.JavaThenScala
|
compileOrder := CompileOrder.JavaThenScala
|
||||||
|
javafmtOnCompile := false
|
||||||
assembly / mainClass := Some("lc.LCFramework")
|
assembly / mainClass := Some("lc.LCFramework")
|
||||||
Compile / run / mainClass := Some("lc.LCFramework")
|
Compile / run / mainClass := Some("lc.LCFramework")
|
||||||
assembly / assemblyJarName := "LibreCaptcha.jar"
|
assembly / assemblyJarName := "LibreCaptcha.jar"
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
package lc.misc;
|
package lc.misc;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class HelperFunctions {
|
public class HelperFunctions {
|
||||||
|
|
||||||
|
private static Random random = new Random();
|
||||||
|
|
||||||
|
synchronized public static void setSeed(long seed){
|
||||||
|
random.setSeed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
public static void setRenderingHints(Graphics2D g2d) {
|
public static void setRenderingHints(Graphics2D g2d) {
|
||||||
g2d.setRenderingHint(
|
g2d.setRenderingHint(
|
||||||
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||||
@ -25,13 +32,18 @@ public class HelperFunctions {
|
|||||||
public static String randomString(final int n, final String characters) {
|
public static String randomString(final int n, final String characters) {
|
||||||
final StringBuilder stringBuilder = new StringBuilder();
|
final StringBuilder stringBuilder = new StringBuilder();
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
int index = (int) (characters.length() * Math.random());
|
int index = randomNumber(characters.length());
|
||||||
stringBuilder.append(characters.charAt(index));
|
stringBuilder.append(characters.charAt(index));
|
||||||
}
|
}
|
||||||
return stringBuilder.toString();
|
return stringBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int randomNumber(int min, int max) {
|
synchronized public static int randomNumber(int min, int max) {
|
||||||
return (int) (Math.random() * ((max - min) + 1)) + min;
|
return (random.nextInt() * ((max - min) + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized public static int randomNumber(int bound) {
|
||||||
|
return random.nextInt(bound);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,9 @@ package lc.background
|
|||||||
|
|
||||||
import lc.database.Statements
|
import lc.database.Statements
|
||||||
import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
|
import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
|
||||||
import lc.core.Captcha
|
import lc.core.{Captcha, Config}
|
||||||
import lc.core.{Parameters, Size}
|
import lc.core.{Parameters, Size}
|
||||||
|
import lc.misc.HelperFunctions
|
||||||
|
|
||||||
class BackgroundTask(throttle: Int, timeLimit: Int) {
|
class BackgroundTask(throttle: Int, timeLimit: Int) {
|
||||||
|
|
||||||
@ -22,13 +23,26 @@ class BackgroundTask(throttle: Int, timeLimit: Int) {
|
|||||||
if (imageNum.next())
|
if (imageNum.next())
|
||||||
throttleIn = (throttleIn - imageNum.getInt("total"))
|
throttleIn = (throttleIn - imageNum.getInt("total"))
|
||||||
while (0 < throttleIn) {
|
while (0 < throttleIn) {
|
||||||
Captcha.generateChallenge(Parameters("medium", "image/png", "text", Option(Size(0, 0))))
|
Captcha.generateChallenge(getRandomParam())
|
||||||
throttleIn -= 1
|
throttleIn -= 1
|
||||||
}
|
}
|
||||||
} catch { case exception: Exception => println(exception) }
|
} catch { case exception: Exception => println(exception) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def getRandomParam(): Parameters = {
|
||||||
|
val captcha = pickRandom(Config.captchaConfig)
|
||||||
|
val level = pickRandom(captcha.allowedLevels)
|
||||||
|
val media = pickRandom(captcha.allowedMedia)
|
||||||
|
val inputType = pickRandom(captcha.allowedInputType)
|
||||||
|
|
||||||
|
Parameters(level, media, inputType, Some(Size(0, 0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def pickRandom[T](list: List[T]): T = {
|
||||||
|
list(HelperFunctions.randomNumber(list.size))
|
||||||
|
}
|
||||||
|
|
||||||
def beginThread(delay: Int): Unit = {
|
def beginThread(delay: Int): Unit = {
|
||||||
val ex = new ScheduledThreadPoolExecutor(1)
|
val ex = new ScheduledThreadPoolExecutor(1)
|
||||||
ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
|
ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
|
||||||
|
@ -4,6 +4,7 @@ import lc.captchas._
|
|||||||
import lc.captchas.interfaces.ChallengeProvider
|
import lc.captchas.interfaces.ChallengeProvider
|
||||||
import lc.captchas.interfaces.Challenge
|
import lc.captchas.interfaces.Challenge
|
||||||
import scala.collection.mutable.Map
|
import scala.collection.mutable.Map
|
||||||
|
import lc.misc.HelperFunctions
|
||||||
|
|
||||||
object CaptchaProviders {
|
object CaptchaProviders {
|
||||||
private val providers = Map(
|
private val providers = Map(
|
||||||
@ -23,15 +24,8 @@ object CaptchaProviders {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val seed = Config.seed
|
|
||||||
private val random = new scala.util.Random(seed)
|
|
||||||
private val config = Config.captchaConfig
|
private val config = Config.captchaConfig
|
||||||
|
|
||||||
private def getNextRandomInt(max: Int): Int =
|
|
||||||
random.synchronized {
|
|
||||||
random.nextInt(max)
|
|
||||||
}
|
|
||||||
|
|
||||||
def getProviderById(id: String): ChallengeProvider = {
|
def getProviderById(id: String): ChallengeProvider = {
|
||||||
return providers(id)
|
return providers(id)
|
||||||
}
|
}
|
||||||
@ -58,7 +52,7 @@ object CaptchaProviders {
|
|||||||
def getProvider(param: Parameters): Option[ChallengeProvider] = {
|
def getProvider(param: Parameters): Option[ChallengeProvider] = {
|
||||||
val providerConfig = filterProviderByParam(param).toList
|
val providerConfig = filterProviderByParam(param).toList
|
||||||
if (providerConfig.length > 0) {
|
if (providerConfig.length > 0) {
|
||||||
val randomIndex = getNextRandomInt(providerConfig.length)
|
val randomIndex = HelperFunctions.randomNumber(providerConfig.length)
|
||||||
val providerIndex = providerConfig(randomIndex)._1
|
val providerIndex = providerConfig(randomIndex)._1
|
||||||
val selectedProvider = providers(providerIndex)
|
val selectedProvider = providers(providerIndex)
|
||||||
selectedProvider.configure(providerConfig(randomIndex)._2)
|
selectedProvider.configure(providerConfig(randomIndex)._2)
|
||||||
|
@ -6,6 +6,7 @@ import org.json4s.jackson.JsonMethods.{parse, render, pretty}
|
|||||||
import org.json4s.JsonDSL._
|
import org.json4s.JsonDSL._
|
||||||
import java.io.{FileNotFoundException, File, PrintWriter}
|
import java.io.{FileNotFoundException, File, PrintWriter}
|
||||||
import java.{util => ju}
|
import java.{util => ju}
|
||||||
|
import lc.misc.HelperFunctions
|
||||||
|
|
||||||
object Config {
|
object Config {
|
||||||
|
|
||||||
@ -49,6 +50,8 @@ object Config {
|
|||||||
val allowedMedia: Set[String] = captchaConfig.flatMap(_.allowedMedia).toSet
|
val allowedMedia: Set[String] = captchaConfig.flatMap(_.allowedMedia).toSet
|
||||||
val allowedInputType: Set[String] = captchaConfig.flatMap(_.allowedInputType).toSet
|
val allowedInputType: Set[String] = captchaConfig.flatMap(_.allowedInputType).toSet
|
||||||
|
|
||||||
|
HelperFunctions.setSeed(seed)
|
||||||
|
|
||||||
private def getDefaultConfig(): String = {
|
private def getDefaultConfig(): String = {
|
||||||
val defaultConfigMap =
|
val defaultConfigMap =
|
||||||
(AttributesEnum.RANDOM_SEED.toString -> new ju.Random().nextInt()) ~
|
(AttributesEnum.RANDOM_SEED.toString -> new ju.Random().nextInt()) ~
|
||||||
|
@ -116,7 +116,7 @@ object Statements {
|
|||||||
org.h2.jdbc.JdbcSQLNonTransientException: General error: "java.lang.NullPointerException"; SQL statement:
|
org.h2.jdbc.JdbcSQLNonTransientException: General error: "java.lang.NullPointerException"; SQL statement:
|
||||||
SELECT image FROM challenge c, mapId m WHERE c.token=m.token AND m.uuid = ? [50000-200]
|
SELECT image FROM challenge c, mapId m WHERE c.token=m.token AND m.uuid = ? [50000-200]
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
private val dbConn: DBConn = new DBConn()
|
private val dbConn: DBConn = new DBConn()
|
||||||
private val maxAttempts = 10
|
private val maxAttempts = 10
|
||||||
val tlStmts: ThreadLocal[Statements] = ThreadLocal.withInitial(() => new Statements(dbConn, maxAttempts))
|
val tlStmts: ThreadLocal[Statements] = ThreadLocal.withInitial(() => new Statements(dbConn, maxAttempts))
|
||||||
|
@ -11,37 +11,50 @@ import scala.io.Source
|
|||||||
import org.limium.picoserve.Server.StringResponse
|
import org.limium.picoserve.Server.StringResponse
|
||||||
|
|
||||||
class Server(port: Int) {
|
class Server(port: Int) {
|
||||||
val server: picoserve.Server = picoserve.Server.builder()
|
val server: picoserve.Server = picoserve.Server
|
||||||
|
.builder()
|
||||||
.port(port)
|
.port(port)
|
||||||
.backlog(32)
|
.backlog(32)
|
||||||
.POST("/v1/captcha", (request) => {
|
.POST(
|
||||||
val json = parse(request.getBodyString())
|
"/v1/captcha",
|
||||||
val param = json.extract[Parameters]
|
(request) => {
|
||||||
val id = Captcha.getChallenge(param)
|
val json = parse(request.getBodyString())
|
||||||
getResponse(id)
|
val param = json.extract[Parameters]
|
||||||
})
|
val id = Captcha.getChallenge(param)
|
||||||
.GET("/v1/media", (request) => {
|
getResponse(id)
|
||||||
val params = request.getQueryParams()
|
|
||||||
val result = if (params.containsKey("id")) {
|
|
||||||
val paramId = params.get("id").get(0)
|
|
||||||
val id = Id(paramId)
|
|
||||||
Captcha.getCaptcha(id)
|
|
||||||
} else {
|
|
||||||
Left(Error(ErrorMessageEnum.INVALID_PARAM.toString + "=> id"))
|
|
||||||
}
|
}
|
||||||
getResponse(result)
|
)
|
||||||
})
|
.GET(
|
||||||
.POST("/v1/answer", (request) => {
|
"/v1/media",
|
||||||
val json = parse(request.getBodyString())
|
(request) => {
|
||||||
val answer = json.extract[Answer]
|
val params = request.getQueryParams()
|
||||||
val result = Captcha.checkAnswer(answer)
|
val result = if (params.containsKey("id")) {
|
||||||
getResponse(result)
|
val paramId = params.get("id").get(0)
|
||||||
})
|
val id = Id(paramId)
|
||||||
.GET("/demo/index.html", (_) => {
|
Captcha.getCaptcha(id)
|
||||||
val resStream = getClass().getResourceAsStream("/index.html")
|
} else {
|
||||||
val str = Source.fromInputStream(resStream).mkString
|
Left(Error(ErrorMessageEnum.INVALID_PARAM.toString + "=> id"))
|
||||||
new StringResponse(200, str)
|
}
|
||||||
})
|
getResponse(result)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.POST(
|
||||||
|
"/v1/answer",
|
||||||
|
(request) => {
|
||||||
|
val json = parse(request.getBodyString())
|
||||||
|
val answer = json.extract[Answer]
|
||||||
|
val result = Captcha.checkAnswer(answer)
|
||||||
|
getResponse(result)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.GET(
|
||||||
|
"/demo/index.html",
|
||||||
|
(_) => {
|
||||||
|
val resStream = getClass().getResourceAsStream("/index.html")
|
||||||
|
val str = Source.fromInputStream(resStream).mkString
|
||||||
|
new StringResponse(200, str)
|
||||||
|
}
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private def getResponse(response: Either[Error, ByteConvert]): ByteResponse = {
|
private def getResponse(response: Either[Error, ByteConvert]): ByteResponse = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user