Skip to content

Commit

Permalink
Merge pull request #90 from rr83019/BT-captcha
Browse files Browse the repository at this point in the history
Background Thread - Random Captcha Generation
  • Loading branch information
hrj authored Apr 24, 2021
2 parents 9e7efc1 + 1708347 commit 6196a34
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 42 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ scalacOptions ++= List(
)
javacOptions += "-g:none"
compileOrder := CompileOrder.JavaThenScala
javafmtOnCompile := false
assembly / mainClass := Some("lc.LCFramework")
Compile / run / mainClass := Some("lc.LCFramework")
assembly / assemblyJarName := "LibreCaptcha.jar"
Expand Down
18 changes: 15 additions & 3 deletions src/main/java/lc/misc/HelperFunctions.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package lc.misc;

import java.awt.*;
import java.util.Random;

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) {
g2d.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Expand All @@ -25,13 +32,18 @@ public static String randomString(final int n) {
public static String randomString(final int n, final String characters) {
final StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < n; i++) {
int index = (int) (characters.length() * Math.random());
int index = randomNumber(characters.length());
stringBuilder.append(characters.charAt(index));
}
return stringBuilder.toString();
}

public static int randomNumber(int min, int max) {
return (int) (Math.random() * ((max - min) + 1)) + min;
synchronized public static int randomNumber(int min, int max) {
return (random.nextInt() * ((max - min) + 1)) + min;
}

synchronized public static int randomNumber(int bound) {
return random.nextInt(bound);
}

}
18 changes: 16 additions & 2 deletions src/main/scala/lc/background/taskThread.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package lc.background

import lc.database.Statements
import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
import lc.core.Captcha
import lc.core.{Captcha, Config}
import lc.core.{Parameters, Size}
import lc.misc.HelperFunctions

class BackgroundTask(throttle: Int, timeLimit: Int) {

Expand All @@ -22,13 +23,26 @@ class BackgroundTask(throttle: Int, timeLimit: Int) {
if (imageNum.next())
throttleIn = (throttleIn - imageNum.getInt("total"))
while (0 < throttleIn) {
Captcha.generateChallenge(Parameters("medium", "image/png", "text", Option(Size(0, 0))))
Captcha.generateChallenge(getRandomParam())
throttleIn -= 1
}
} 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 = {
val ex = new ScheduledThreadPoolExecutor(1)
ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
Expand Down
10 changes: 2 additions & 8 deletions src/main/scala/lc/core/captchaProviders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import lc.captchas._
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
import scala.collection.mutable.Map
import lc.misc.HelperFunctions

object CaptchaProviders {
private val providers = Map(
Expand All @@ -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 def getNextRandomInt(max: Int): Int =
random.synchronized {
random.nextInt(max)
}

def getProviderById(id: String): ChallengeProvider = {
return providers(id)
}
Expand All @@ -58,7 +52,7 @@ object CaptchaProviders {
def getProvider(param: Parameters): Option[ChallengeProvider] = {
val providerConfig = filterProviderByParam(param).toList
if (providerConfig.length > 0) {
val randomIndex = getNextRandomInt(providerConfig.length)
val randomIndex = HelperFunctions.randomNumber(providerConfig.length)
val providerIndex = providerConfig(randomIndex)._1
val selectedProvider = providers(providerIndex)
selectedProvider.configure(providerConfig(randomIndex)._2)
Expand Down
3 changes: 3 additions & 0 deletions src/main/scala/lc/core/config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.json4s.jackson.JsonMethods.{parse, render, pretty}
import org.json4s.JsonDSL._
import java.io.{FileNotFoundException, File, PrintWriter}
import java.{util => ju}
import lc.misc.HelperFunctions

object Config {

Expand Down Expand Up @@ -49,6 +50,8 @@ object Config {
val allowedMedia: Set[String] = captchaConfig.flatMap(_.allowedMedia).toSet
val allowedInputType: Set[String] = captchaConfig.flatMap(_.allowedInputType).toSet

HelperFunctions.setSeed(seed)

private def getDefaultConfig(): String = {
val defaultConfigMap =
(AttributesEnum.RANDOM_SEED.toString -> new ju.Random().nextInt()) ~
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/lc/database/statements.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ object Statements {
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]
```
*/
*/
private val dbConn: DBConn = new DBConn()
private val maxAttempts = 10
val tlStmts: ThreadLocal[Statements] = ThreadLocal.withInitial(() => new Statements(dbConn, maxAttempts))
Expand Down
69 changes: 41 additions & 28 deletions src/main/scala/lc/server/Server.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,50 @@ import scala.io.Source
import org.limium.picoserve.Server.StringResponse

class Server(port: Int) {
val server: picoserve.Server = picoserve.Server.builder()
val server: picoserve.Server = picoserve.Server
.builder()
.port(port)
.backlog(32)
.POST("/v1/captcha", (request) => {
val json = parse(request.getBodyString())
val param = json.extract[Parameters]
val id = Captcha.getChallenge(param)
getResponse(id)
})
.GET("/v1/media", (request) => {
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"))
.POST(
"/v1/captcha",
(request) => {
val json = parse(request.getBodyString())
val param = json.extract[Parameters]
val id = Captcha.getChallenge(param)
getResponse(id)
}
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)
})
)
.GET(
"/v1/media",
(request) => {
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)
}
)
.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()

private def getResponse(response: Either[Error, ByteConvert]): ByteResponse = {
Expand Down

0 comments on commit 6196a34

Please sign in to comment.