refactor, separate code into files

This commit is contained in:
hrj 2020-07-03 20:21:35 +05:30
parent e45302df8c
commit 03548d17ae
3 changed files with 158 additions and 159 deletions

View File

@ -0,0 +1,23 @@
package lc
import java.sql._
class DBConn(){
val con: Connection = DriverManager.getConnection("jdbc:h2:./captcha", "sa", "")
lazy val insertPstmt: PreparedStatement = con.prepareStatement("INSERT INTO challenge(token, id, secret, provider, contentType, image) VALUES (?, ?, ?, ?, ?, ?)")
lazy val mapPstmt: PreparedStatement = con.prepareStatement("INSERT INTO mapId(uuid, token) VALUES (?, ?)")
lazy val selectPstmt: PreparedStatement = con.prepareStatement("SELECT secret, provider FROM challenge WHERE token = ?")
lazy val imagePstmt: PreparedStatement = con.prepareStatement("SELECT image FROM challenge c, mapId m WHERE c.token=m.token AND m.uuid = ?")
lazy val updatePstmt: PreparedStatement = con.prepareStatement("UPDATE challenge SET solved = True WHERE token = (SELECT m.token FROM mapId m, challenge c WHERE m.token=c.token AND m.uuid = ?)")
lazy val userPstmt: PreparedStatement = con.prepareStatement("INSERT INTO users(email, hash) VALUES (?,?)")
lazy val validatePstmt: PreparedStatement = con.prepareStatement("SELECT hash FROM users WHERE hash = ? LIMIT 1")
def getConn(): Statement = {
con.createStatement()
}
def closeConnection(): Unit = {
con.close()
}
}

View File

@ -1,43 +1,15 @@
package lc
import com.sksamuel.scrimage._
import java.sql._
import java.io._
import lc.HTTPServer._
import lc.FontFunCaptcha._
import lc.GifCaptcha._
import lc.ShadowTextCaptcha._
import javax.imageio._
import java.awt.image._
import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.JsonDSL._
import java.util.Base64
import org.json4s.jackson.Serialization
import org.json4s.jackson.Serialization.{read, write}
import java.io.ByteArrayInputStream
import java.util.concurrent._
import java.util.UUID
import scala.Array
import java.sql.{Blob, ResultSet}
class DBConn(){
val con: Connection = DriverManager.getConnection("jdbc:h2:./captcha", "sa", "")
lazy val insertPstmt: PreparedStatement = con.prepareStatement("INSERT INTO challenge(token, id, secret, provider, contentType, image) VALUES (?, ?, ?, ?, ?, ?)")
lazy val mapPstmt: PreparedStatement = con.prepareStatement("INSERT INTO mapId(uuid, token) VALUES (?, ?)")
lazy val selectPstmt: PreparedStatement = con.prepareStatement("SELECT secret, provider FROM challenge WHERE token = ?")
lazy val imagePstmt: PreparedStatement = con.prepareStatement("SELECT image FROM challenge c, mapId m WHERE c.token=m.token AND m.uuid = ?")
lazy val updatePstmt: PreparedStatement = con.prepareStatement("UPDATE challenge SET solved = True WHERE token = (SELECT m.token FROM mapId m, challenge c WHERE m.token=c.token AND m.uuid = ?)")
lazy val userPstmt: PreparedStatement = con.prepareStatement("INSERT INTO users(email, hash) VALUES (?,?)")
lazy val validatePstmt: PreparedStatement = con.prepareStatement("SELECT hash FROM users WHERE hash = ? LIMIT 1")
def getConn(): Statement = {
con.createStatement()
}
def closeConnection(): Unit = {
con.close()
}
}
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 Answer(answer: String, id: String)
class Captcha(throttle: Int) extends DBConn {
@ -167,128 +139,6 @@ class Captcha(throttle: Int) extends DBConn {
}
}
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 Answer(answer: String, id: String)
case class Secret(token: Int)
class RateLimiter extends DBConn {
val stmt = getConn()
val userLastActive = collection.mutable.Map[Int, Long]()
val userAllowance = collection.mutable.Map[Int, Double]()
val rate = 2.0
val per = 45.0
val allowance = rate
def validateUser(user: Int) : Boolean = {
synchronized {
val allow = if(userLastActive.contains(user)){
true
} else {
validatePstmt.setInt(1, user)
val rs = validatePstmt.executeQuery()
val validated = if(rs.next()){
val hash = rs.getInt("hash")
userLastActive(hash) = System.currentTimeMillis()
userAllowance(hash) = allowance
true
} else {
false
}
validated
}
allow
}
}
def checkLimit(user: Int): Boolean = {
synchronized {
val current = System.currentTimeMillis()
val time_passed = (current - userLastActive(user)) / 1000000000
userLastActive(user) = current
userAllowance(user) += time_passed * (rate/per)
if(userAllowance(user) > rate){ userAllowance(user) = rate }
val allow = if(userAllowance(user) < 1.0){
false
} else {
userAllowance(user) -= 1.0
true
}
allow
}
}
}
class Server(port: Int){
val captcha = new Captcha(0)
val rateLimiter = new RateLimiter()
val server = new HTTPServer(port)
val host = server.getVirtualHost(null)
implicit val formats = DefaultFormats
host.addContext("/v1/captcha",(req, resp) => {
val accessToken = Option(req.getHeaders().get("access-token")).map(_.toInt)
val access = accessToken.map(t => rateLimiter.validateUser(t) && rateLimiter.checkLimit(t)).getOrElse(false)
val id = if(access){
val body = req.getJson()
val json = parse(body)
val param = json.extract[Parameters]
captcha.getChallenge(param)
} else {
"Not a valid user or rate limit reached!"
}
resp.getHeaders().add("Content-Type","application/json")
resp.send(200, write(id))
0
},"POST")
host.addContext("/v1/media",(req, resp) => {
var id = Id(null)
if ("GET" == req.getMethod()){
val params = req.getParams()
id = Id(params.get("id"))
} else {
val body = req.getJson()
val json = parse(body)
id = json.extract[Id]
}
val image = captcha.getCaptcha(id)
resp.getHeaders().add("Content-Type","image/png")
resp.send(200, image)
0
},"POST", "GET")
host.addContext("/v1/answer",(req, resp) => {
val body = req.getJson()
val json = parse(body)
val answer = json.extract[Answer]
val result = captcha.checkAnswer(answer)
resp.getHeaders().add("Content-Type","application/json")
val responseContent = if(result) """{"result":"True"}""" else """{"result":"False"}"""
resp.send(200,responseContent)
0
},"POST")
host.addContext("/v1/register", new FileContextHandler(new File("client/")))
host.addContext("/v1/token", (req,resp) => {
val params = req.getParams()
val hash = captcha.getHash(params.get("email"))
val token = Secret(hash)
resp.getHeaders().add("Content-Type", "application/json")
resp.send(200, write(token))
0
})
def start(): Unit = {
server.start()
}
}
object LCFramework{
def main(args: scala.Array[String]) {
val captcha = new Captcha(2)

View File

@ -0,0 +1,126 @@
package lc
import java.io.File
import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.jackson.Serialization.{read, write}
import lc.HTTPServer._
case class Secret(token: Int)
class RateLimiter extends DBConn {
val stmt = getConn()
val userLastActive = collection.mutable.Map[Int, Long]()
val userAllowance = collection.mutable.Map[Int, Double]()
val rate = 2.0
val per = 45.0
val allowance = rate
def validateUser(user: Int) : Boolean = {
synchronized {
val allow = if(userLastActive.contains(user)){
true
} else {
validatePstmt.setInt(1, user)
val rs = validatePstmt.executeQuery()
val validated = if(rs.next()){
val hash = rs.getInt("hash")
userLastActive(hash) = System.currentTimeMillis()
userAllowance(hash) = allowance
true
} else {
false
}
validated
}
allow
}
}
def checkLimit(user: Int): Boolean = {
synchronized {
val current = System.currentTimeMillis()
val time_passed = (current - userLastActive(user)) / 1000000000
userLastActive(user) = current
userAllowance(user) += time_passed * (rate/per)
if(userAllowance(user) > rate){ userAllowance(user) = rate }
val allow = if(userAllowance(user) < 1.0){
false
} else {
userAllowance(user) -= 1.0
true
}
allow
}
}
}
class Server(port: Int){
val captcha = new Captcha(0)
val rateLimiter = new RateLimiter()
val server = new HTTPServer(port)
val host = server.getVirtualHost(null)
implicit val formats = DefaultFormats
host.addContext("/v1/captcha",(req, resp) => {
val accessToken = Option(req.getHeaders().get("access-token")).map(_.toInt)
val access = accessToken.map(t => rateLimiter.validateUser(t) && rateLimiter.checkLimit(t)).getOrElse(false)
val id = if(access){
val body = req.getJson()
val json = parse(body)
val param = json.extract[Parameters]
captcha.getChallenge(param)
} else {
"Not a valid user or rate limit reached!"
}
resp.getHeaders().add("Content-Type","application/json")
resp.send(200, write(id))
0
},"POST")
host.addContext("/v1/media",(req, resp) => {
var id = Id(null)
if ("GET" == req.getMethod()){
val params = req.getParams()
id = Id(params.get("id"))
} else {
val body = req.getJson()
val json = parse(body)
id = json.extract[Id]
}
val image = captcha.getCaptcha(id)
resp.getHeaders().add("Content-Type","image/png")
resp.send(200, image)
0
},"POST", "GET")
host.addContext("/v1/answer",(req, resp) => {
val body = req.getJson()
val json = parse(body)
val answer = json.extract[Answer]
val result = captcha.checkAnswer(answer)
resp.getHeaders().add("Content-Type","application/json")
val responseContent = if(result) """{"result":"True"}""" else """{"result":"False"}"""
resp.send(200,responseContent)
0
},"POST")
host.addContext("/v1/register", new FileContextHandler(new File("client/")))
host.addContext("/v1/token", (req,resp) => {
val params = req.getParams()
val hash = captcha.getHash(params.get("email"))
val token = Secret(hash)
resp.getHeaders().add("Content-Type", "application/json")
resp.send(200, write(token))
0
})
def start(): Unit = {
server.start()
}
}