From 600c7c5e8f756f772f5bc7ccec09dc3c96316a39 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Tue, 2 Mar 2021 21:31:07 +0530 Subject: [PATCH 01/17] Add config support Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/Main.scala | 11 ++- src/main/scala/lc/core/captchaProviders.scala | 33 ++++++-- src/main/scala/lc/core/config.scala | 80 +++++++++++++++++++ 3 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 src/main/scala/lc/core/config.scala diff --git a/src/main/scala/lc/Main.scala b/src/main/scala/lc/Main.scala index 739bc35..145f939 100644 --- a/src/main/scala/lc/Main.scala +++ b/src/main/scala/lc/Main.scala @@ -3,13 +3,18 @@ package lc import lc.core.{Captcha, CaptchaProviders} import lc.server.Server import lc.background.BackgroundTask +import lc.core.Config object LCFramework { def main(args: scala.Array[String]): Unit = { val captcha = new Captcha() - val server = new Server(8888, captcha) - val backgroudTask = new BackgroundTask(captcha, 10) - backgroudTask.beginThread(2) + val server = new Server(port = Config.getPort, captcha = captcha) + val backgroundTask = new BackgroundTask( + captcha = captcha, + throttle = Config.getThrottle, + timeLimit = Config.getCaptchaExpiryTimeLimit + ) + backgroundTask.beginThread(delay = Config.getThreadDelay) server.start() } } diff --git a/src/main/scala/lc/core/captchaProviders.scala b/src/main/scala/lc/core/captchaProviders.scala index 0277015..1567cd4 100644 --- a/src/main/scala/lc/core/captchaProviders.scala +++ b/src/main/scala/lc/core/captchaProviders.scala @@ -3,6 +3,8 @@ package lc.core import lc.captchas._ import lc.captchas.interfaces.ChallengeProvider import lc.captchas.interfaces.Challenge +import org.json4s.{DefaultFormats, JObject, JField, JArray, JString} +import org.json4s.jackson.Serialization.write object CaptchaProviders { private val providers = Map( @@ -21,10 +23,12 @@ object CaptchaProviders { } } - private val seed = System.currentTimeMillis.toString.substring(2, 6).toInt + implicit val formats: DefaultFormats.type = DefaultFormats + private val seed = Config.getSeed private val random = new scala.util.Random(seed) + private val config = Config.getCaptchaConfig - private def getNextRandomInt(max: Int) = + private def getNextRandomInt(max: Int): Int = random.synchronized { random.nextInt(max) } @@ -33,9 +37,26 @@ object CaptchaProviders { return providers(id) } - def getProvider(): ChallengeProvider = { - val keys = providers.keys - val providerIndex = keys.toVector(getNextRandomInt(keys.size)) - providers(providerIndex) + private def filterProviderByParam(param: Parameters): List[(String, String)] = { + for { + JObject(child) <- config + JField("name", JString(name)) <- child + JField("supportedLevels", JArray(supportedLevels)) <- child + JField("supportedMedia", JArray(supportedMedia)) <- child + JField("supportedinputType", JArray(supportedinputType)) <- child + JField("config", config) <- child + if supportedLevels.contains(JString(param.level)) + if supportedMedia.contains(JString(param.media)) + if supportedinputType.contains(JString(param.input_type)) + } yield (name, write(config)) + } + + def getProvider(param: Parameters): ChallengeProvider = { + val providerConfig = filterProviderByParam(param) + val randomIndex = getNextRandomInt(providerConfig.length) + val providerIndex = providerConfig(randomIndex)._1 + val selectedProvider = providers(providerIndex) + selectedProvider.configure(providerConfig(randomIndex)._2) + selectedProvider } } diff --git a/src/main/scala/lc/core/config.scala b/src/main/scala/lc/core/config.scala new file mode 100644 index 0000000..0321e96 --- /dev/null +++ b/src/main/scala/lc/core/config.scala @@ -0,0 +1,80 @@ +package lc.core + +import scala.io.Source.fromFile +import org.json4s.{DefaultFormats, JValue, JObject, JField} +import org.json4s.jackson.JsonMethods.parse + +object Config { + + implicit val formats: DefaultFormats.type = DefaultFormats + + private val configFile = fromFile("config.json") + private val configString = + try configFile.mkString + finally configFile.close + private val configJson = parse(configString) + + private val port = (configJson \ "port").extract[Int] + private val throttle = (configJson \ "throttle").extract[Int] + private val seed = (configJson \ "randomSeed").extract[Int] + private val captchaExpiryTimeLimit = (configJson \ "captchaExpiryTimeLimit").extract[Int] + private val threadDelay = (configJson \ "threadDelay").extract[Int] + private val capthcaConfig = (configJson \ "captchas") + + private val supportedLevels = getAllValues(configJson, "supportedLevels") + private val supportedMedia = getAllValues(configJson, "supportedMedia") + private val supportedinputType = getAllValues(configJson, "supportedinputType") + + private def getAllValues(config: JValue, param: String): Set[String] = { + val configValues = (config \\ param) + val result = for { + JObject(child) <- configValues + JField(param) <- child + } yield (param) + + var valueSet = Set[String]() + for (valueList <- result) { + for (value <- valueList._2.children) { + valueSet += value.values.toString + } + } + valueSet + } + + def getPort(): Int = { + port + } + + def getThrottle(): Int = { + throttle + } + + def getSeed(): Int = { + seed + } + + def getCaptchaExpiryTimeLimit(): Int = { + captchaExpiryTimeLimit + } + + def getThreadDelay(): Int = { + threadDelay + } + + def getCaptchaConfig(): JValue = { + capthcaConfig + } + + def getSupportedLevels(): Set[String] = { + supportedLevels + } + + def getSupportedMedia(): Set[String] = { + supportedMedia + } + + def getSupportedinputType(): Set[String] = { + supportedinputType + } + +} From c00680f63173fbbe6bd6bb7dc491e03f35159925 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Tue, 2 Mar 2021 21:32:45 +0530 Subject: [PATCH 02/17] Add config method Signed-off-by: Rahul Rudragoudar --- src/main/java/lc/captchas/FontFunCaptcha.java | 4 ++++ src/main/java/lc/captchas/GifCaptcha.java | 4 ++++ src/main/java/lc/captchas/ShadowTextCaptcha.java | 4 ++++ src/main/java/lc/captchas/interfaces/ChallengeProvider.java | 2 +- src/main/scala/lc/captchas/FilterChallenge.scala | 5 +++++ src/main/scala/lc/captchas/LabelCaptcha.scala | 4 ++++ src/main/scala/lc/captchas/RainDropsCaptcha.scala | 4 ++++ 7 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/java/lc/captchas/FontFunCaptcha.java b/src/main/java/lc/captchas/FontFunCaptcha.java index a69998b..e4379fc 100644 --- a/src/main/java/lc/captchas/FontFunCaptcha.java +++ b/src/main/java/lc/captchas/FontFunCaptcha.java @@ -16,6 +16,10 @@ public class FontFunCaptcha implements ChallengeProvider { return "FontFunCaptcha"; } + public void configure(String config) { + // TODO: Add custom config + } + private String getFontName(String path, String level) { File file = new File(path + level + "/"); FilenameFilter txtFileFilter = diff --git a/src/main/java/lc/captchas/GifCaptcha.java b/src/main/java/lc/captchas/GifCaptcha.java index 92a87ec..9352167 100644 --- a/src/main/java/lc/captchas/GifCaptcha.java +++ b/src/main/java/lc/captchas/GifCaptcha.java @@ -48,6 +48,10 @@ public class GifCaptcha implements ChallengeProvider { return null; } + public void configure(String config) { + // TODO: Add custom config + } + public Challenge returnChallenge() { String 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 0128e97..3462df2 100644 --- a/src/main/java/lc/captchas/ShadowTextCaptcha.java +++ b/src/main/java/lc/captchas/ShadowTextCaptcha.java @@ -20,6 +20,10 @@ public class ShadowTextCaptcha implements ChallengeProvider { return "ShadowTextCaptcha"; } + public void configure(String config) { + // TODO: Add custom config + } + public boolean checkAnswer(String secret, String answer) { return answer.toLowerCase().equals(secret); } diff --git a/src/main/java/lc/captchas/interfaces/ChallengeProvider.java b/src/main/java/lc/captchas/interfaces/ChallengeProvider.java index ef8e7d0..09ad8c0 100644 --- a/src/main/java/lc/captchas/interfaces/ChallengeProvider.java +++ b/src/main/java/lc/captchas/interfaces/ChallengeProvider.java @@ -7,5 +7,5 @@ public interface ChallengeProvider { public boolean checkAnswer(String secret, String answer); - // TODO: def configure(): Unit + public void configure(String config); } diff --git a/src/main/scala/lc/captchas/FilterChallenge.scala b/src/main/scala/lc/captchas/FilterChallenge.scala index 0a1ef61..80c8d6f 100644 --- a/src/main/scala/lc/captchas/FilterChallenge.scala +++ b/src/main/scala/lc/captchas/FilterChallenge.scala @@ -10,6 +10,11 @@ import lc.captchas.interfaces.Challenge class FilterChallenge extends ChallengeProvider { def getId = "FilterChallenge" + + def configure(config: String): Unit = { + // TODO: add custom config + } + def returnChallenge(): Challenge = { val filterTypes = List(new FilterType1, new FilterType2) val r = new scala.util.Random diff --git a/src/main/scala/lc/captchas/LabelCaptcha.scala b/src/main/scala/lc/captchas/LabelCaptcha.scala index afbc5e0..9b86568 100644 --- a/src/main/scala/lc/captchas/LabelCaptcha.scala +++ b/src/main/scala/lc/captchas/LabelCaptcha.scala @@ -23,6 +23,10 @@ class LabelCaptcha extends ChallengeProvider { def getId = "LabelCaptcha" + def configure(config: String): Unit = { + // TODO: add custom config + } + def returnChallenge(): Challenge = synchronized { val r = scala.util.Random.nextInt(knownFiles.length) diff --git a/src/main/scala/lc/captchas/RainDropsCaptcha.scala b/src/main/scala/lc/captchas/RainDropsCaptcha.scala index da12829..214a525 100644 --- a/src/main/scala/lc/captchas/RainDropsCaptcha.scala +++ b/src/main/scala/lc/captchas/RainDropsCaptcha.scala @@ -31,6 +31,10 @@ class RainDropsCP extends ChallengeProvider { def getId = "FilterChallenge" + def configure(config: String): Unit = { + // TODO: add custom config + } + private def extendDrops(drops: Array[Drop], steps: Int, xOffset: Int) = { drops.map(d => { val nd = new Drop() From 843367007fec06a0e514cd6f679cbc1064a5c433 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Tue, 2 Mar 2021 21:33:11 +0530 Subject: [PATCH 03/17] Update config json file Signed-off-by: Rahul Rudragoudar --- config.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/config.json b/config.json index ee7ed58..e97d2d9 100644 --- a/config.json +++ b/config.json @@ -1,32 +1,35 @@ { "randomSeed": 20, + "port": 8888, "captchaExpiryTimeLimit": 5, + "threadDelay": 2, + "throttle": 10, "captchas":{ "FilterChallenge":{ "name": "FilterChallenge", "supportedLevels":["medium", "hard"], - "supportedMedia":["image"], + "supportedMedia":["image/png"], "supportedinputType":["text"], "config":{} }, "GifCaptcha":{ "name": "GifCaptcha", "supportedLevels":["hard"], - "supportedMedia":["gif"], + "supportedMedia":["image/gif"], "supportedinputType":["text"], "config":{} }, "ShadowTextCaptcha":{ "name": "ShadowTextCaptcha", "supportedLevels":["easy"], - "supportedMedia":["image"], + "supportedMedia":["image/png"], "supportedinputType":["text"], "config": {} }, "RainDropsCaptcha":{ "name": "RainDropsCaptcha", "supportedLevels":["easy","medium"], - "supportedMedia":["image"], + "supportedMedia":["image/gif"], "supportedinputType":["text"], "config":{} } From ed395350391760460624d6cae77a9d1a50fd8777 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Tue, 2 Mar 2021 21:33:46 +0530 Subject: [PATCH 04/17] Update statements Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/database/statements.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/scala/lc/database/statements.scala b/src/main/scala/lc/database/statements.scala index 24bfe24..f165d9d 100644 --- a/src/main/scala/lc/database/statements.scala +++ b/src/main/scala/lc/database/statements.scala @@ -15,6 +15,8 @@ class Statements(dbConn: DBConn) { "secret varchar, " + "provider varchar, " + "contentType varchar, " + + "contentLevel varchar, " + + "contentInput varchar, " + "image blob, " + "attempted int default 0, " + "PRIMARY KEY(token))" @@ -32,8 +34,8 @@ class Statements(dbConn: DBConn) { val insertPstmt: PreparedStatement = dbConn.con.prepareStatement( "INSERT INTO " + - "challenge(id, secret, provider, contentType, image) " + - "VALUES (?, ?, ?, ?, ?)", + "challenge(id, secret, provider, contentType, contentLevel, contentInput, image) " + + "VALUES (?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS ) @@ -48,7 +50,7 @@ class Statements(dbConn: DBConn) { "SELECT c.secret, c.provider " + "FROM challenge c, mapId m " + "WHERE m.token=c.token AND " + - "DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, m.lastServed)) > 0 AND " + + "DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 5, m.lastServed)) > 0 AND " + "m.uuid = ?" ) @@ -71,7 +73,10 @@ class Statements(dbConn: DBConn) { val tokenPstmt: PreparedStatement = dbConn.con.prepareStatement( "SELECT token " + "FROM challenge " + - "WHERE attempted < 10 " + + "WHERE attempted < 10 AND " + + "contentLevel = ? AND " + + "contentType = ? AND " + + "contentInput = ? " + "ORDER BY RAND() LIMIT 1" ) @@ -86,7 +91,7 @@ class Statements(dbConn: DBConn) { ) val mapIdGCPstmt: PreparedStatement = dbConn.con.prepareStatement( - "DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, lastServed)) < 0" + "DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 5, lastServed)) < 0" ) val getCountChallengeTable: PreparedStatement = dbConn.con.prepareStatement( From 5cafd037d159566cfe83b02fa2ad08887fa5a8d7 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Tue, 2 Mar 2021 21:34:16 +0530 Subject: [PATCH 05/17] Improve error handling Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/core/captcha.scala | 61 +++++++++++++++++++++------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/src/main/scala/lc/core/captcha.scala b/src/main/scala/lc/core/captcha.scala index dfbda96..b0c2b9a 100644 --- a/src/main/scala/lc/core/captcha.scala +++ b/src/main/scala/lc/core/captcha.scala @@ -5,6 +5,7 @@ import java.util.UUID import java.io.ByteArrayInputStream import lc.database.Statements import lc.core.CaptchaProviders +import lc.captchas.interfaces.ChallengeProvider class Captcha { @@ -30,8 +31,8 @@ class Captcha { } def generateChallenge(param: Parameters): Int = { - //TODO: eval params to choose a provider - val provider = CaptchaProviders.getProvider() + val provider = CaptchaProviders.getProvider(param) + if (!provider.isInstanceOf[ChallengeProvider]) return -1 val providerId = provider.getId() val challenge = provider.returnChallenge() val blob = new ByteArrayInputStream(challenge.content) @@ -40,7 +41,9 @@ class Captcha { insertPstmt.setString(2, challenge.secret) insertPstmt.setString(3, providerId) insertPstmt.setString(4, challenge.contentType) - insertPstmt.setBlob(5, blob) + insertPstmt.setString(5, param.level) + insertPstmt.setString(6, param.input_type) + insertPstmt.setBlob(7, blob) insertPstmt.executeUpdate() val rs: ResultSet = insertPstmt.getGeneratedKeys() val token = if (rs.next()) { @@ -50,24 +53,54 @@ class Captcha { token.asInstanceOf[Int] } + val supportedinputType = Config.getSupportedinputType + val supportedLevels = Config.getSupportedLevels + val supportedMedia = Config.getSupportedMedia + + private def validateParam(param: Parameters): Boolean = { + if ( + supportedLevels.contains(param.level) && + supportedMedia.contains(param.media) && + supportedinputType.contains(param.input_type) + ) + return true + else + return false + } + def getChallenge(param: Parameters): Id = { try { - val tokenPstmt = Statements.tlStmts.get.tokenPstmt - val rs = tokenPstmt.executeQuery() - val tokenOpt = if (rs.next()) { - Some(rs.getInt("token")) + val validParam = validateParam(param) + val result = if (validParam) { + val tokenPstmt = Statements.tlStmts.get.tokenPstmt + tokenPstmt.setString(1, param.level) + tokenPstmt.setString(2, param.media) + tokenPstmt.setString(3, param.input_type) + val rs = tokenPstmt.executeQuery() + val tokenOpt = if (rs.next()) { + Some(rs.getInt("token")) + } else { + None + } + val updateAttemptedPstmt = Statements.tlStmts.get.updateAttemptedPstmt + val token = tokenOpt.getOrElse(generateChallenge(param)) + val uuidResult = if (token != -1) { + val uuid = getUUID(token) + updateAttemptedPstmt.setString(1, uuid) + updateAttemptedPstmt.executeUpdate() + uuid + } else { + "No Captcha for the provided parameters" + } + uuidResult } else { - None + "Invalid Parameters" } - val updateAttemptedPstmt = Statements.tlStmts.get.updateAttemptedPstmt - val uuid = getUUID(tokenOpt.getOrElse(generateChallenge(param))) - updateAttemptedPstmt.setString(1, uuid) - updateAttemptedPstmt.executeUpdate() - Id(uuid) + Id(result) } catch { case e: Exception => println(e) - Id(getUUID(-1)) + Id("Something went wrong") } } From 0906d6b906b910a8dfa4f893133469e39cadc103 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Tue, 2 Mar 2021 21:34:38 +0530 Subject: [PATCH 06/17] Minor updates Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/background/taskThread.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/lc/background/taskThread.scala b/src/main/scala/lc/background/taskThread.scala index fe3cbbc..e48276a 100644 --- a/src/main/scala/lc/background/taskThread.scala +++ b/src/main/scala/lc/background/taskThread.scala @@ -5,7 +5,7 @@ import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit} import lc.core.Captcha import lc.core.{Parameters, Size} -class BackgroundTask(captcha: Captcha, throttle: Int) { +class BackgroundTask(captcha: Captcha, throttle: Int, timeLimit: Int) { private val task = new Runnable { def run(): Unit = { @@ -22,7 +22,7 @@ class BackgroundTask(captcha: Captcha, throttle: Int) { if (imageNum.next()) throttleIn = (throttleIn - imageNum.getInt("total")) while (0 < throttleIn) { - captcha.generateChallenge(Parameters("", "", "", Option(Size(0, 0)))) + captcha.generateChallenge(Parameters("medium", "image/png", "text", Option(Size(0, 0)))) throttleIn -= 1 } } catch { case e: Exception => println(e) } From d9ff3a14b9fece9d4ad208a250c9b0d193cf8a57 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Tue, 2 Mar 2021 21:34:58 +0530 Subject: [PATCH 07/17] Update locustfile Signed-off-by: Rahul Rudragoudar --- tests/locustfile.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/locustfile.py b/tests/locustfile.py index d3a72b0..54774e0 100644 --- a/tests/locustfile.py +++ b/tests/locustfile.py @@ -7,31 +7,32 @@ class QuickStartUser(SequentialTaskSet): @task def captcha(self): - captcha_params = {"level":"some","media":"some","input_type":"some"} + # TODO: Iterate over parameters for a more comprehensive test + captcha_params = {"level":"easy","media":"image/png","input_type":"text"} resp = self.client.post(path="/v1/captcha", json=captcha_params, name="/captcha") if resp.status_code != 200: print("\nError on /captcha endpoint: ") print(resp) print(resp.text) - print("----------------END.C-------------------\n\n") + print("----------------END.CAPTCHA-------------------\n\n") uuid = json.loads(resp.text).get("id") answerBody = {"answer": "qwer123","id": uuid} resp = self.client.get(path="/v1/media?id=%s" % uuid, name="/media") if resp.status_code != 200: - print("\nError on /captcha endpoint: ") + print("\nError on /media endpoint: ") print(resp) print(resp.text) - print("----------------END.C-------------------\n\n") + print("----------------END.MEDIA-------------------\n\n") resp = self.client.post(path='/v1/answer', json=answerBody, name="/answer") if resp.status_code != 200: - print("\nError on /captcha endpoint: ") + print("\nError on /answer endpoint: ") print(resp) print(resp.text) - print("----------------END.C-------------------\n\n") + print("----------------END.ANSWER-------------------\n\n") class User(FastHttpUser): From 6c4a3d0152f4edcadd9bf808fd1f0031731a734f Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Tue, 2 Mar 2021 21:52:30 +0530 Subject: [PATCH 08/17] Add config time support to captcha expiry Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/background/taskThread.scala | 1 + src/main/scala/lc/core/captcha.scala | 3 ++- src/main/scala/lc/database/statements.scala | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/lc/background/taskThread.scala b/src/main/scala/lc/background/taskThread.scala index e48276a..c6cfe7e 100644 --- a/src/main/scala/lc/background/taskThread.scala +++ b/src/main/scala/lc/background/taskThread.scala @@ -12,6 +12,7 @@ class BackgroundTask(captcha: Captcha, throttle: Int, timeLimit: Int) { try { val mapIdGCPstmt = Statements.tlStmts.get.mapIdGCPstmt + mapIdGCPstmt.setInt(1, timeLimit) mapIdGCPstmt.executeUpdate() val challengeGCPstmt = Statements.tlStmts.get.challengeGCPstmt diff --git a/src/main/scala/lc/core/captcha.scala b/src/main/scala/lc/core/captcha.scala index b0c2b9a..ff8ac3a 100644 --- a/src/main/scala/lc/core/captcha.scala +++ b/src/main/scala/lc/core/captcha.scala @@ -115,7 +115,8 @@ class Captcha { def checkAnswer(answer: Answer): Result = { val selectPstmt = Statements.tlStmts.get.selectPstmt - selectPstmt.setString(1, answer.id) + selectPstmt.setInt(1, Config.getCaptchaExpiryTimeLimit) + selectPstmt.setString(2, answer.id) val rs: ResultSet = selectPstmt.executeQuery() val psOpt = if (rs.first()) { val secret = rs.getString("secret") diff --git a/src/main/scala/lc/database/statements.scala b/src/main/scala/lc/database/statements.scala index f165d9d..1439b56 100644 --- a/src/main/scala/lc/database/statements.scala +++ b/src/main/scala/lc/database/statements.scala @@ -50,7 +50,7 @@ class Statements(dbConn: DBConn) { "SELECT c.secret, c.provider " + "FROM challenge c, mapId m " + "WHERE m.token=c.token AND " + - "DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 5, m.lastServed)) > 0 AND " + + "DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, ?, m.lastServed)) > 0 AND " + "m.uuid = ?" ) @@ -91,7 +91,7 @@ class Statements(dbConn: DBConn) { ) val mapIdGCPstmt: PreparedStatement = dbConn.con.prepareStatement( - "DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 5, lastServed)) < 0" + "DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, ?, lastServed)) < 0" ) val getCountChallengeTable: PreparedStatement = dbConn.con.prepareStatement( From 070b862f25399a7fa326aea3cd7582558e99fb3c Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Fri, 5 Mar 2021 14:51:17 +0530 Subject: [PATCH 09/17] Remove access methods Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/Main.scala | 8 +-- src/main/scala/lc/core/captcha.scala | 8 +-- src/main/scala/lc/core/captchaProviders.scala | 31 ++++------ src/main/scala/lc/core/config.scala | 56 ++++--------------- 4 files changed, 31 insertions(+), 72 deletions(-) diff --git a/src/main/scala/lc/Main.scala b/src/main/scala/lc/Main.scala index 145f939..491ed3f 100644 --- a/src/main/scala/lc/Main.scala +++ b/src/main/scala/lc/Main.scala @@ -8,13 +8,13 @@ import lc.core.Config object LCFramework { def main(args: scala.Array[String]): Unit = { val captcha = new Captcha() - val server = new Server(port = Config.getPort, captcha = captcha) + val server = new Server(port = Config.port, captcha = captcha) val backgroundTask = new BackgroundTask( captcha = captcha, - throttle = Config.getThrottle, - timeLimit = Config.getCaptchaExpiryTimeLimit + throttle = Config.throttle, + timeLimit = Config.captchaExpiryTimeLimit ) - backgroundTask.beginThread(delay = Config.getThreadDelay) + backgroundTask.beginThread(delay = Config.threadDelay) server.start() } } diff --git a/src/main/scala/lc/core/captcha.scala b/src/main/scala/lc/core/captcha.scala index ff8ac3a..d2fbe29 100644 --- a/src/main/scala/lc/core/captcha.scala +++ b/src/main/scala/lc/core/captcha.scala @@ -53,9 +53,9 @@ class Captcha { token.asInstanceOf[Int] } - val supportedinputType = Config.getSupportedinputType - val supportedLevels = Config.getSupportedLevels - val supportedMedia = Config.getSupportedMedia + val supportedinputType = Config.supportedinputType + val supportedLevels = Config.supportedLevels + val supportedMedia = Config.supportedMedia private def validateParam(param: Parameters): Boolean = { if ( @@ -115,7 +115,7 @@ class Captcha { def checkAnswer(answer: Answer): Result = { val selectPstmt = Statements.tlStmts.get.selectPstmt - selectPstmt.setInt(1, Config.getCaptchaExpiryTimeLimit) + selectPstmt.setInt(1, Config.captchaExpiryTimeLimit) selectPstmt.setString(2, answer.id) val rs: ResultSet = selectPstmt.executeQuery() val psOpt = if (rs.first()) { diff --git a/src/main/scala/lc/core/captchaProviders.scala b/src/main/scala/lc/core/captchaProviders.scala index 1567cd4..f8588f0 100644 --- a/src/main/scala/lc/core/captchaProviders.scala +++ b/src/main/scala/lc/core/captchaProviders.scala @@ -3,8 +3,7 @@ package lc.core import lc.captchas._ import lc.captchas.interfaces.ChallengeProvider import lc.captchas.interfaces.Challenge -import org.json4s.{DefaultFormats, JObject, JField, JArray, JString} -import org.json4s.jackson.Serialization.write +import scala.collection.mutable.Map object CaptchaProviders { private val providers = Map( @@ -23,10 +22,9 @@ object CaptchaProviders { } } - implicit val formats: DefaultFormats.type = DefaultFormats - private val seed = Config.getSeed + private val seed = Config.seed private val random = new scala.util.Random(seed) - private val config = Config.getCaptchaConfig + private val config = Config.captchaConfigMap private def getNextRandomInt(max: Int): Int = random.synchronized { @@ -37,26 +35,21 @@ object CaptchaProviders { return providers(id) } - private def filterProviderByParam(param: Parameters): List[(String, String)] = { + private def filterProviderByParam(param: Parameters): Iterable[(List[String], List[String])] = { for { - JObject(child) <- config - JField("name", JString(name)) <- child - JField("supportedLevels", JArray(supportedLevels)) <- child - JField("supportedMedia", JArray(supportedMedia)) <- child - JField("supportedinputType", JArray(supportedinputType)) <- child - JField("config", config) <- child - if supportedLevels.contains(JString(param.level)) - if supportedMedia.contains(JString(param.media)) - if supportedinputType.contains(JString(param.input_type)) - } yield (name, write(config)) + configValue <- config.values + if configValue("supportedLevels").contains(param.level) + if configValue("supportedMedia").contains(param.media) + if configValue("supportedinputType").contains(param.input_type) + } yield (configValue("name"), configValue("config")) } def getProvider(param: Parameters): ChallengeProvider = { - val providerConfig = filterProviderByParam(param) + val providerConfig = filterProviderByParam(param).toList val randomIndex = getNextRandomInt(providerConfig.length) val providerIndex = providerConfig(randomIndex)._1 - val selectedProvider = providers(providerIndex) - selectedProvider.configure(providerConfig(randomIndex)._2) + val selectedProvider = providers(providerIndex(0)) + selectedProvider.configure(providerConfig(randomIndex)._2(0)) selectedProvider } } diff --git a/src/main/scala/lc/core/config.scala b/src/main/scala/lc/core/config.scala index 0321e96..eabd373 100644 --- a/src/main/scala/lc/core/config.scala +++ b/src/main/scala/lc/core/config.scala @@ -3,6 +3,7 @@ package lc.core import scala.io.Source.fromFile import org.json4s.{DefaultFormats, JValue, JObject, JField} import org.json4s.jackson.JsonMethods.parse +import scala.collection.immutable.HashMap object Config { @@ -14,16 +15,17 @@ object Config { finally configFile.close private val configJson = parse(configString) - private val port = (configJson \ "port").extract[Int] - private val throttle = (configJson \ "throttle").extract[Int] - private val seed = (configJson \ "randomSeed").extract[Int] - private val captchaExpiryTimeLimit = (configJson \ "captchaExpiryTimeLimit").extract[Int] - private val threadDelay = (configJson \ "threadDelay").extract[Int] - private val capthcaConfig = (configJson \ "captchas") + val port: Int = (configJson \ "port").extract[Int] + val throttle: Int = (configJson \ "throttle").extract[Int] + val seed: Int = (configJson \ "randomSeed").extract[Int] + val captchaExpiryTimeLimit: Int = (configJson \ "captchaExpiryTimeLimit").extract[Int] + val threadDelay: Int = (configJson \ "threadDelay").extract[Int] + private val captchaConfig = (configJson \ "captchas") + val captchaConfigMap: Map[String,HashMap[String,List[String]]] = captchaConfig.values.asInstanceOf[Map[String, HashMap[String, List[String]]]] - private val supportedLevels = getAllValues(configJson, "supportedLevels") - private val supportedMedia = getAllValues(configJson, "supportedMedia") - private val supportedinputType = getAllValues(configJson, "supportedinputType") + val supportedLevels: Set[String] = getAllValues(configJson, "supportedLevels") + val supportedMedia: Set[String] = getAllValues(configJson, "supportedMedia") + val supportedinputType: Set[String] = getAllValues(configJson, "supportedinputType") private def getAllValues(config: JValue, param: String): Set[String] = { val configValues = (config \\ param) @@ -41,40 +43,4 @@ object Config { valueSet } - def getPort(): Int = { - port - } - - def getThrottle(): Int = { - throttle - } - - def getSeed(): Int = { - seed - } - - def getCaptchaExpiryTimeLimit(): Int = { - captchaExpiryTimeLimit - } - - def getThreadDelay(): Int = { - threadDelay - } - - def getCaptchaConfig(): JValue = { - capthcaConfig - } - - def getSupportedLevels(): Set[String] = { - supportedLevels - } - - def getSupportedMedia(): Set[String] = { - supportedMedia - } - - def getSupportedinputType(): Set[String] = { - supportedinputType - } - } From 933145c32ea77360771707a89c9182458fa14227 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Thu, 11 Mar 2021 21:11:12 +0530 Subject: [PATCH 10/17] Disable scalafmt on compile option Signed-off-by: Rahul Rudragoudar --- build.sbt | 1 - 1 file changed, 1 deletion(-) diff --git a/build.sbt b/build.sbt index ba3cf96..4691280 100644 --- a/build.sbt +++ b/build.sbt @@ -21,7 +21,6 @@ scalacOptions ++= List( "-Ywarn-unused" ) javacOptions += "-g:none" -scalafmtOnCompile := true compileOrder := CompileOrder.JavaThenScala fork in run := true From a30a9775724c25491e5ad7cf62b3e9cbad5e69b6 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Thu, 11 Mar 2021 21:11:47 +0530 Subject: [PATCH 11/17] Remove redundant key param Signed-off-by: Rahul Rudragoudar --- config.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/config.json b/config.json index e97d2d9..727b973 100644 --- a/config.json +++ b/config.json @@ -4,34 +4,34 @@ "captchaExpiryTimeLimit": 5, "threadDelay": 2, "throttle": 10, - "captchas":{ - "FilterChallenge":{ + "captchas":[ + { "name": "FilterChallenge", - "supportedLevels":["medium", "hard"], - "supportedMedia":["image/png"], - "supportedinputType":["text"], + "allowedLevels":["medium", "hard"], + "allowedMedia":["image/png"], + "allowedInputType":["text"], "config":{} }, - "GifCaptcha":{ + { "name": "GifCaptcha", - "supportedLevels":["hard"], - "supportedMedia":["image/gif"], - "supportedinputType":["text"], + "allowedLevels":["hard"], + "allowedMedia":["image/gif"], + "allowedInputType":["text"], "config":{} }, - "ShadowTextCaptcha":{ + { "name": "ShadowTextCaptcha", - "supportedLevels":["easy"], - "supportedMedia":["image/png"], - "supportedinputType":["text"], + "allowedLevels":["easy"], + "allowedMedia":["image/png"], + "allowedInputType":["text"], "config": {} }, - "RainDropsCaptcha":{ + { "name": "RainDropsCaptcha", - "supportedLevels":["easy","medium"], - "supportedMedia":["image/gif"], - "supportedinputType":["text"], + "allowedLevels":["easy","medium"], + "allowedMedia":["image/gif"], + "allowedInputType":["text"], "config":{} } - } + ] } \ No newline at end of file From 2c0f3deb8a4f0ba702618df3062568158048b2dd Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Thu, 11 Mar 2021 21:23:24 +0530 Subject: [PATCH 12/17] Add supportedParams method Signed-off-by: Rahul Rudragoudar --- src/main/java/lc/captchas/FontFunCaptcha.java | 11 +++++++++++ src/main/java/lc/captchas/GifCaptcha.java | 12 ++++++++++++ src/main/java/lc/captchas/ShadowTextCaptcha.java | 12 ++++++++++++ .../lc/captchas/interfaces/ChallengeProvider.java | 5 +++++ src/main/scala/lc/captchas/FilterChallenge.scala | 12 ++++++++++++ src/main/scala/lc/captchas/LabelCaptcha.scala | 12 ++++++++++++ src/main/scala/lc/captchas/RainDropsCaptcha.scala | 12 ++++++++++++ 7 files changed, 76 insertions(+) diff --git a/src/main/java/lc/captchas/FontFunCaptcha.java b/src/main/java/lc/captchas/FontFunCaptcha.java index e4379fc..bb1c278 100644 --- a/src/main/java/lc/captchas/FontFunCaptcha.java +++ b/src/main/java/lc/captchas/FontFunCaptcha.java @@ -6,6 +6,8 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FilenameFilter; +import java.util.HashMap; +import java.util.List; import lc.captchas.interfaces.Challenge; import lc.captchas.interfaces.ChallengeProvider; import lc.misc.HelperFunctions; @@ -16,6 +18,15 @@ public class FontFunCaptcha implements ChallengeProvider { return "FontFunCaptcha"; } + public HashMap> supportedParameters() { + HashMap> supportedParams = new HashMap>(); + supportedParams.put("supportedLevels", List.of("medium")); + supportedParams.put("supportedMedia", List.of("image/png")); + supportedParams.put("supportedInputType", List.of("text")); + + return supportedParams; + } + public void configure(String config) { // TODO: Add custom config } diff --git a/src/main/java/lc/captchas/GifCaptcha.java b/src/main/java/lc/captchas/GifCaptcha.java index 9352167..13cf0fa 100644 --- a/src/main/java/lc/captchas/GifCaptcha.java +++ b/src/main/java/lc/captchas/GifCaptcha.java @@ -6,6 +6,9 @@ import java.awt.RenderingHints; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.IOException; +import java.util.HashMap; +import java.util.List; + import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.MemoryCacheImageOutputStream; import java.io.ByteArrayOutputStream; @@ -52,6 +55,15 @@ public class GifCaptcha implements ChallengeProvider { // TODO: Add custom config } + public HashMap> supportedParameters() { + HashMap> supportedParams = new HashMap>(); + supportedParams.put("supportedLevels", List.of("hard")); + supportedParams.put("supportedMedia", List.of("image/gif")); + supportedParams.put("supportedInputType", List.of("text")); + + return supportedParams; + } + public Challenge returnChallenge() { String 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 3462df2..5b3b873 100644 --- a/src/main/java/lc/captchas/ShadowTextCaptcha.java +++ b/src/main/java/lc/captchas/ShadowTextCaptcha.java @@ -10,6 +10,9 @@ import java.awt.image.BufferedImage; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import java.io.ByteArrayOutputStream; +import java.util.HashMap; +import java.util.List; + import lc.misc.HelperFunctions; import lc.captchas.interfaces.Challenge; import lc.captchas.interfaces.ChallengeProvider; @@ -24,6 +27,15 @@ public class ShadowTextCaptcha implements ChallengeProvider { // TODO: Add custom config } + public HashMap> supportedParameters() { + HashMap> supportedParams = new HashMap>(); + supportedParams.put("supportedLevels", List.of("easy")); + supportedParams.put("supportedMedia", List.of("image/png")); + supportedParams.put("supportedInputType", List.of("text")); + + return supportedParams; + } + public boolean checkAnswer(String secret, String answer) { return answer.toLowerCase().equals(secret); } diff --git a/src/main/java/lc/captchas/interfaces/ChallengeProvider.java b/src/main/java/lc/captchas/interfaces/ChallengeProvider.java index 09ad8c0..a3a70e2 100644 --- a/src/main/java/lc/captchas/interfaces/ChallengeProvider.java +++ b/src/main/java/lc/captchas/interfaces/ChallengeProvider.java @@ -1,5 +1,8 @@ package lc.captchas.interfaces; +import java.util.Map; +import java.util.List; + public interface ChallengeProvider { public String getId(); @@ -8,4 +11,6 @@ public interface ChallengeProvider { public boolean checkAnswer(String secret, String answer); public void configure(String config); + + public Map> supportedParameters(); } diff --git a/src/main/scala/lc/captchas/FilterChallenge.scala b/src/main/scala/lc/captchas/FilterChallenge.scala index 80c8d6f..a4508b6 100644 --- a/src/main/scala/lc/captchas/FilterChallenge.scala +++ b/src/main/scala/lc/captchas/FilterChallenge.scala @@ -7,6 +7,8 @@ import java.awt.Font import java.awt.Color import lc.captchas.interfaces.ChallengeProvider import lc.captchas.interfaces.Challenge +import scala.jdk.CollectionConverters.MapHasAsJava +import java.util.{List => JavaList, Map => JavaMap} class FilterChallenge extends ChallengeProvider { def getId = "FilterChallenge" @@ -15,6 +17,16 @@ class FilterChallenge extends ChallengeProvider { // TODO: add custom config } + def supportedParameters(): JavaMap[String, JavaList[String]] = { + val supportedParams = Map( + "supportedLevels" -> JavaList.of("medium", "hard"), + "supportedMedia" -> JavaList.of("image/png"), + "supportedInputType" -> JavaList.of("text") + ).asJava + + supportedParams + } + def returnChallenge(): Challenge = { val filterTypes = List(new FilterType1, new FilterType2) val r = new scala.util.Random diff --git a/src/main/scala/lc/captchas/LabelCaptcha.scala b/src/main/scala/lc/captchas/LabelCaptcha.scala index 9b86568..5233678 100644 --- a/src/main/scala/lc/captchas/LabelCaptcha.scala +++ b/src/main/scala/lc/captchas/LabelCaptcha.scala @@ -9,6 +9,8 @@ import java.awt.image.BufferedImage import java.awt.Color import lc.captchas.interfaces.ChallengeProvider import lc.captchas.interfaces.Challenge +import scala.jdk.CollectionConverters.MapHasAsJava +import java.util.{List => JavaList, Map => JavaMap} class LabelCaptcha extends ChallengeProvider { private var knownFiles = new File("known").list.toList @@ -27,6 +29,16 @@ class LabelCaptcha extends ChallengeProvider { // TODO: add custom config } + def supportedParameters(): JavaMap[String, JavaList[String]] = { + val supportedParams = Map( + "supportedLevels" -> JavaList.of("hard"), + "supportedMedia" -> JavaList.of("image/png"), + "supportedInputType" -> JavaList.of("text") + ).asJava + + supportedParams + } + def returnChallenge(): Challenge = synchronized { val r = scala.util.Random.nextInt(knownFiles.length) diff --git a/src/main/scala/lc/captchas/RainDropsCaptcha.scala b/src/main/scala/lc/captchas/RainDropsCaptcha.scala index 214a525..2788096 100644 --- a/src/main/scala/lc/captchas/RainDropsCaptcha.scala +++ b/src/main/scala/lc/captchas/RainDropsCaptcha.scala @@ -10,6 +10,8 @@ import javax.imageio.stream.MemoryCacheImageOutputStream; import lc.captchas.interfaces.ChallengeProvider import lc.captchas.interfaces.Challenge import lc.misc.GifSequenceWriter +import scala.jdk.CollectionConverters.MapHasAsJava +import java.util.{List => JavaList, Map => JavaMap} class Drop { var x = 0 @@ -35,6 +37,16 @@ class RainDropsCP extends ChallengeProvider { // TODO: add custom config } + def supportedParameters(): JavaMap[String, JavaList[String]] = { + val supportedParams = Map( + "supportedLevels" -> JavaList.of("medium", "easy"), + "supportedMedia" -> JavaList.of("image/gif"), + "supportedInputType" -> JavaList.of("text") + ).asJava + + supportedParams + } + private def extendDrops(drops: Array[Drop], steps: Int, xOffset: Int) = { drops.map(d => { val nd = new Drop() From e931e43bb97c63d5c68f2c5626f4432ca25b3456 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Thu, 11 Mar 2021 21:24:22 +0530 Subject: [PATCH 13/17] Extract to case class Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/core/config.scala | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/scala/lc/core/config.scala b/src/main/scala/lc/core/config.scala index eabd373..2bf02be 100644 --- a/src/main/scala/lc/core/config.scala +++ b/src/main/scala/lc/core/config.scala @@ -1,9 +1,8 @@ package lc.core import scala.io.Source.fromFile -import org.json4s.{DefaultFormats, JValue, JObject, JField} +import org.json4s.{DefaultFormats, JValue, JObject, JField, JString} import org.json4s.jackson.JsonMethods.parse -import scala.collection.immutable.HashMap object Config { @@ -20,12 +19,15 @@ object Config { val seed: Int = (configJson \ "randomSeed").extract[Int] val captchaExpiryTimeLimit: Int = (configJson \ "captchaExpiryTimeLimit").extract[Int] val threadDelay: Int = (configJson \ "threadDelay").extract[Int] - private val captchaConfig = (configJson \ "captchas") - val captchaConfigMap: Map[String,HashMap[String,List[String]]] = captchaConfig.values.asInstanceOf[Map[String, HashMap[String, List[String]]]] - val supportedLevels: Set[String] = getAllValues(configJson, "supportedLevels") - val supportedMedia: Set[String] = getAllValues(configJson, "supportedMedia") - val supportedinputType: Set[String] = getAllValues(configJson, "supportedinputType") + private val captchaConfigJson = (configJson \ "captchas") + val captchaConfigTransform: JValue = captchaConfigJson transformField { + case JField("config", JObject(config)) => ("config", JString(config.toString)) + } + val captchaConfig: List[CaptchaConfig] = captchaConfigTransform.extract[List[CaptchaConfig]] + val allowedLevels: Set[String] = getAllValues(configJson, ParametersEnum.ALLOWEDLEVELS.toString) + val allowedMedia: Set[String] = getAllValues(configJson, ParametersEnum.ALLOWEDMEDIA.toString) + val allowedInputType: Set[String] = getAllValues(configJson, ParametersEnum.ALLOWEDINPUTTYPE.toString) private def getAllValues(config: JValue, param: String): Set[String] = { val configValues = (config \\ param) From 2b617ef75ddd256bc52839c56bd9042a004f0dcc Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Thu, 11 Mar 2021 21:25:33 +0530 Subject: [PATCH 14/17] Add additional filtering on captchas Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/core/captchaProviders.scala | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/scala/lc/core/captchaProviders.scala b/src/main/scala/lc/core/captchaProviders.scala index f8588f0..5af97a0 100644 --- a/src/main/scala/lc/core/captchaProviders.scala +++ b/src/main/scala/lc/core/captchaProviders.scala @@ -24,7 +24,7 @@ object CaptchaProviders { private val seed = Config.seed private val random = new scala.util.Random(seed) - private val config = Config.captchaConfigMap + private val config = Config.captchaConfig private def getNextRandomInt(max: Int): Int = random.synchronized { @@ -35,21 +35,31 @@ object CaptchaProviders { return providers(id) } - private def filterProviderByParam(param: Parameters): Iterable[(List[String], List[String])] = { - for { - configValue <- config.values - if configValue("supportedLevels").contains(param.level) - if configValue("supportedMedia").contains(param.media) - if configValue("supportedinputType").contains(param.input_type) - } yield (configValue("name"), configValue("config")) + private def filterProviderByParam(param: Parameters): Iterable[(String, String)] = { + val configFilter = for { + configValue <- config + if configValue.allowedLevels.contains(param.level) + if configValue.allowedMedia.contains(param.media) + if configValue.allowedInputType.contains(param.input_type) + } yield (configValue.name, configValue.config) + + val providerFilter = for { + providerValue <- configFilter + providerConfigMap = providers(providerValue._1).supportedParameters() + if providerConfigMap.get(ParametersEnum.SUPPORTEDLEVEL.toString).contains(param.level) + if providerConfigMap.get(ParametersEnum.SUPPORTEDMEDIA.toString).contains(param.media) + if providerConfigMap.get(ParametersEnum.SUPPORTEDINPUTTYPE.toString).contains(param.input_type) + } yield (providerValue._1, providerValue._2) + + providerFilter } def getProvider(param: Parameters): ChallengeProvider = { val providerConfig = filterProviderByParam(param).toList val randomIndex = getNextRandomInt(providerConfig.length) val providerIndex = providerConfig(randomIndex)._1 - val selectedProvider = providers(providerIndex(0)) - selectedProvider.configure(providerConfig(randomIndex)._2(0)) + val selectedProvider = providers(providerIndex) + selectedProvider.configure(providerConfig(randomIndex)._2) selectedProvider } } From 21b299a30fe0d4c499c04d02b88140b5411f6a3d Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Thu, 11 Mar 2021 21:26:30 +0530 Subject: [PATCH 15/17] Add captchaConfig case class Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/core/models.scala | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/scala/lc/core/models.scala b/src/main/scala/lc/core/models.scala index 2e6f48c..4c16333 100644 --- a/src/main/scala/lc/core/models.scala +++ b/src/main/scala/lc/core/models.scala @@ -1,7 +1,16 @@ package lc.core +sealed trait ChallengeResult case class Size(height: Int, width: Int) case class Parameters(level: String, media: String, input_type: String, size: Option[Size]) -case class Id(id: String) +case class Id(id: String) extends ChallengeResult +case class Error(message: String) extends ChallengeResult case class Answer(answer: String, id: String) case class Result(result: String) +case class CaptchaConfig( + name: String, + allowedLevels: List[String], + allowedMedia: List[String], + allowedInputType: List[String], + config: String +) From 033db81721f13cbe5dfbf3cb7d331ec1f25a4d44 Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Thu, 11 Mar 2021 21:26:58 +0530 Subject: [PATCH 16/17] Add captcha fields enum Signed-off-by: Rahul Rudragoudar --- src/main/scala/lc/core/captcha.scala | 33 +++++++++++----------- src/main/scala/lc/core/captchaFields.scala | 29 +++++++++++++++++++ 2 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 src/main/scala/lc/core/captchaFields.scala diff --git a/src/main/scala/lc/core/captcha.scala b/src/main/scala/lc/core/captcha.scala index d2fbe29..c8c2edc 100644 --- a/src/main/scala/lc/core/captcha.scala +++ b/src/main/scala/lc/core/captcha.scala @@ -53,25 +53,25 @@ class Captcha { token.asInstanceOf[Int] } - val supportedinputType = Config.supportedinputType - val supportedLevels = Config.supportedLevels - val supportedMedia = Config.supportedMedia + val allowedInputType = Config.allowedInputType + val allowedLevels = Config.allowedLevels + val allowedMedia = Config.allowedMedia private def validateParam(param: Parameters): Boolean = { if ( - supportedLevels.contains(param.level) && - supportedMedia.contains(param.media) && - supportedinputType.contains(param.input_type) + allowedLevels.contains(param.level) && + allowedMedia.contains(param.media) && + allowedInputType.contains(param.input_type) ) return true else return false } - def getChallenge(param: Parameters): Id = { + def getChallenge(param: Parameters): ChallengeResult = { try { val validParam = validateParam(param) - val result = if (validParam) { + if (validParam) { val tokenPstmt = Statements.tlStmts.get.tokenPstmt tokenPstmt.setString(1, param.level) tokenPstmt.setString(2, param.media) @@ -84,23 +84,22 @@ class Captcha { } val updateAttemptedPstmt = Statements.tlStmts.get.updateAttemptedPstmt val token = tokenOpt.getOrElse(generateChallenge(param)) - val uuidResult = if (token != -1) { + val result = if (token != -1) { val uuid = getUUID(token) updateAttemptedPstmt.setString(1, uuid) updateAttemptedPstmt.executeUpdate() - uuid + Id(uuid) } else { - "No Captcha for the provided parameters" + Error(ErrorMessageEnum.NO_CAPTCHA.toString) } - uuidResult + result } else { - "Invalid Parameters" + Error(ErrorMessageEnum.INVALID_PARAM.toString) } - Id(result) } catch { case e: Exception => println(e) - Id("Something went wrong") + Error(ErrorMessageEnum.SMW.toString) } } @@ -122,10 +121,10 @@ class Captcha { val secret = rs.getString("secret") val provider = rs.getString("provider") val check = CaptchaProviders.getProviderById(provider).checkAnswer(secret, answer.answer) - val result = if (check) "TRUE" else "FALSE" + val result = if (check) ResultEnum.TRUE.toString else ResultEnum.FALSE.toString result } else { - "EXPIRED" + ResultEnum.EXPIRED.toString } val deleteAnswerPstmt = Statements.tlStmts.get.deleteAnswerPstmt deleteAnswerPstmt.setString(1, answer.id) diff --git a/src/main/scala/lc/core/captchaFields.scala b/src/main/scala/lc/core/captchaFields.scala new file mode 100644 index 0000000..5418ee9 --- /dev/null +++ b/src/main/scala/lc/core/captchaFields.scala @@ -0,0 +1,29 @@ +package lc.core + +object ParametersEnum extends Enumeration { + type Parameter = Value + + val SUPPORTEDLEVEL: Value = Value("supportedLevels") + val SUPPORTEDMEDIA: Value = Value("supportedMedia") + val SUPPORTEDINPUTTYPE: Value = Value("supportedInputType") + + val ALLOWEDLEVELS: Value = Value("allowedLevels") + val ALLOWEDMEDIA: Value = Value("allowedMedia") + val ALLOWEDINPUTTYPE: Value = Value("allowedInputType") +} + +object ResultEnum extends Enumeration { + type Result = Value + + val TRUE: Value = Value("True") + val FALSE: Value = Value("False") + val EXPIRED: Value = Value("Expired") +} + +object ErrorMessageEnum extends Enumeration { + type ErrorMessage = Value + + val SMW: Value = Value("Oops, something went worng!") + val INVALID_PARAM: Value = Value("Invalid Pramaters") + val NO_CAPTCHA: Value = Value("No captcha for the provided parameters") +} From f776026c3fa0f5ec07d210fb06f98e553be9f46a Mon Sep 17 00:00:00 2001 From: Rahul Rudragoudar Date: Thu, 11 Mar 2021 21:35:42 +0530 Subject: [PATCH 17/17] Bump jdk version Signed-off-by: Rahul Rudragoudar --- .github/workflows/scala.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 7afbe37..8007c8f 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up JDK 1.8 + - name: Set up JDK 1.11 uses: actions/setup-java@v1 with: - java-version: 1.8 + java-version: 1.11 - name: Run tests run: sbt test - name: Run linter