Linter and Formatter support (#58)

* Add scala linter and formatter

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>

* Add java formatter

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>

* Add linter support

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>

* Increase maxColumn limit

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>

* Reformat and lint

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>

* Minor reformatting

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>

* Add scala formatter on compile option

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>

* Enable scala linter for CI

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
This commit is contained in:
Rahul Rudragoudar 2021-02-25 23:49:39 +05:30 committed by GitHub
parent 6d04cdc3b4
commit de50d8123e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 3445 additions and 3410 deletions

View File

@ -19,3 +19,5 @@ jobs:
java-version: 1.8
- name: Run tests
run: sbt test
- name: Run linter
run: sbt "scalafixAll --check"

8
.scalafix.conf Normal file
View File

@ -0,0 +1,8 @@
rules=[
ExplicitResultTypes,
RemoveUnused,
DisableSyntax,
LeakingImplicitClassVal,
NoValInForComprehension,
ProcedureSyntax
]

2
.scalafmt.conf Normal file
View File

@ -0,0 +1,2 @@
version=2.5.2
maxColumn = 120

View File

@ -4,3 +4,4 @@ scala:
- 2.13.2
script:
- sbt ++$TRAVIS_SCALA_VERSION compile
- sbt "scalafixAll --check"

View File

@ -1,21 +1,27 @@
lazy val root = (project in file(".")).
settings(
inThisBuild(List(
lazy val root = (project in file(".")).settings(
inThisBuild(
List(
organization := "com.example",
scalaVersion := "2.13.3",
version := "0.1.0-SNAPSHOT")),
name := "LibreCaptcha",
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-core" % "4.0.5",
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-filters" % "4.0.5",
libraryDependencies += "org.json4s" % "json4s-jackson_2.13" % "3.6.9"
version := "0.1.0-SNAPSHOT",
semanticdbEnabled := true,
semanticdbVersion := scalafixSemanticdb.revision,
scalafixScalaBinaryVersion := "2.13"
)
),
name := "LibreCaptcha",
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-core" % "4.0.5",
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-filters" % "4.0.5",
libraryDependencies += "org.json4s" % "json4s-jackson_2.13" % "3.6.9"
)
unmanagedResourceDirectories in Compile += {baseDirectory.value / "lib"}
unmanagedResourceDirectories in Compile += { baseDirectory.value / "lib" }
scalacOptions ++= List(
"-Yrangepos",
"-Ywarn-unused"
)
javacOptions += "-g:none"
scalafmtOnCompile := true
compileOrder := CompileOrder.JavaThenScala
fork in run := true

3
project/plugins.sbt Normal file
View File

@ -0,0 +1,3 @@
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.25")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.0")
addSbtPlugin("com.lightbend.sbt" % "sbt-java-formatter" % "0.6.0")

View File

@ -10,69 +10,71 @@ import lc.captchas.interfaces.Challenge;
import lc.captchas.interfaces.ChallengeProvider;
import lc.misc.HelperFunctions;
public class FontFunCaptcha implements ChallengeProvider{
public class FontFunCaptcha implements ChallengeProvider {
public String getId() {
return "FontFunCaptcha";
}
public String getId() {
return "FontFunCaptcha";
}
private String getFontName(String path, String level){
File file = new File(path+level+"/");
FilenameFilter txtFileFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name)
{
if(name.endsWith(".ttf"))
return true;
else
return false;
}
private String getFontName(String path, String level) {
File file = new File(path + level + "/");
FilenameFilter txtFileFilter =
new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.endsWith(".ttf")) return true;
else return false;
}
};
File[] files = file.listFiles(txtFileFilter);
return path+level.toLowerCase()+"/"+files[HelperFunctions.randomNumber(0,files.length-1)].getName();
}
File[] files = file.listFiles(txtFileFilter);
return path
+ level.toLowerCase()
+ "/"
+ files[HelperFunctions.randomNumber(0, files.length - 1)].getName();
}
private Font loadCustomFont(String level, String path) {
String fontName = getFontName(path,level);
try{
Font font = Font.createFont(Font.TRUETYPE_FONT, new File(fontName));
font = font.deriveFont(Font.PLAIN, 48f);
return font;
} catch (Exception e){
e.printStackTrace();
}
return null;
private Font loadCustomFont(String level, String path) {
String fontName = getFontName(path, level);
try {
Font font = Font.createFont(Font.TRUETYPE_FONT, new File(fontName));
font = font.deriveFont(Font.PLAIN, 48f);
return font;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private byte[] fontFun(String captchaText, String level, String path){
String[] colors = {"#f68787","#f8a978","#f1eb9a","#a4f6a5"};
BufferedImage img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = img.createGraphics();
for(int i=0; i< captchaText.length(); i++) {
Font font = loadCustomFont(level,path);
graphics2D.setFont(font);
FontMetrics fontMetrics = graphics2D.getFontMetrics();
HelperFunctions.setRenderingHints(graphics2D);
graphics2D.setColor(Color.decode(colors[HelperFunctions.randomNumber(0,3)]));
graphics2D.drawString(String.valueOf(captchaText.charAt(i)), (i * 48), fontMetrics.getAscent());
}
graphics2D.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img,"png",baos);
}catch (Exception e){
e.printStackTrace();
}
return baos.toByteArray();
private byte[] fontFun(String captchaText, String level, String path) {
String[] colors = {"#f68787", "#f8a978", "#f1eb9a", "#a4f6a5"};
BufferedImage img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = img.createGraphics();
for (int i = 0; i < captchaText.length(); i++) {
Font font = loadCustomFont(level, path);
graphics2D.setFont(font);
FontMetrics fontMetrics = graphics2D.getFontMetrics();
HelperFunctions.setRenderingHints(graphics2D);
graphics2D.setColor(Color.decode(colors[HelperFunctions.randomNumber(0, 3)]));
graphics2D.drawString(
String.valueOf(captchaText.charAt(i)), (i * 48), fontMetrics.getAscent());
}
graphics2D.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img, "png", baos);
} catch (Exception e) {
e.printStackTrace();
}
return baos.toByteArray();
}
public Challenge returnChallenge() {
String secret = HelperFunctions.randomString(7);
String path = "./lib/fonts/";
return new Challenge(fontFun(secret,"medium",path),"image/png",secret.toLowerCase());
}
public Challenge returnChallenge() {
String secret = HelperFunctions.randomString(7);
String path = "./lib/fonts/";
return new Challenge(fontFun(secret, "medium", path), "image/png", secret.toLowerCase());
}
public boolean checkAnswer(String secret, String answer){
return answer.toLowerCase().equals(secret);
}
public boolean checkAnswer(String secret, String answer) {
return answer.toLowerCase().equals(secret);
}
}

View File

@ -14,49 +14,50 @@ import lc.captchas.interfaces.ChallengeProvider;
import lc.misc.HelperFunctions;
import lc.misc.GifSequenceWriter;
public class GifCaptcha implements ChallengeProvider{
public class GifCaptcha implements ChallengeProvider {
private BufferedImage charToImg(String text){
BufferedImage img = new BufferedImage(250, 100, BufferedImage.TYPE_INT_RGB);
Font font = new Font("Bradley Hand", Font.ROMAN_BASELINE, 48);
Graphics2D graphics2D = img.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
graphics2D.setFont(font);
graphics2D.setColor(new Color((int)(Math.random() * 0x1000000)));
graphics2D.drawString( text , 45, 45);
graphics2D.dispose();
return img;
}
private BufferedImage charToImg(String text) {
BufferedImage img = new BufferedImage(250, 100, BufferedImage.TYPE_INT_RGB);
Font font = new Font("Bradley Hand", Font.ROMAN_BASELINE, 48);
Graphics2D graphics2D = img.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
graphics2D.setFont(font);
graphics2D.setColor(new Color((int) (Math.random() * 0x1000000)));
graphics2D.drawString(text, 45, 45);
graphics2D.dispose();
return img;
}
private byte[] gifCaptcha(String text){
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageOutputStream output = new MemoryCacheImageOutputStream(byteArrayOutputStream);
GifSequenceWriter writer = new GifSequenceWriter( output, 1,1000, true );
for(int i=0; i< text.length(); i++){
BufferedImage nextImage = charToImg(String.valueOf(text.charAt(i)));
writer.writeToSequence(nextImage);
}
writer.close();
output.close();
return byteArrayOutputStream.toByteArray();
} catch (IOException e){
e.printStackTrace();
}
return null;
private byte[] gifCaptcha(String text) {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageOutputStream output = new MemoryCacheImageOutputStream(byteArrayOutputStream);
GifSequenceWriter writer = new GifSequenceWriter(output, 1, 1000, true);
for (int i = 0; i < text.length(); i++) {
BufferedImage nextImage = charToImg(String.valueOf(text.charAt(i)));
writer.writeToSequence(nextImage);
}
writer.close();
output.close();
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public Challenge returnChallenge() {
String secret = HelperFunctions.randomString(6);
return new Challenge(gifCaptcha(secret),"image/gif",secret.toLowerCase());
}
public Challenge returnChallenge() {
String secret = HelperFunctions.randomString(6);
return new Challenge(gifCaptcha(secret), "image/gif", secret.toLowerCase());
}
public boolean checkAnswer(String secret, String answer) {
return answer.toLowerCase().equals(secret);
}
public boolean checkAnswer(String secret, String answer) {
return answer.toLowerCase().equals(secret);
}
public String getId() {
return "GifCaptcha";
}
public String getId() {
return "GifCaptcha";
}
}

View File

@ -14,54 +14,54 @@ import lc.misc.HelperFunctions;
import lc.captchas.interfaces.Challenge;
import lc.captchas.interfaces.ChallengeProvider;
public class ShadowTextCaptcha implements ChallengeProvider{
public class ShadowTextCaptcha implements ChallengeProvider {
public String getId() {
return "ShadowTextCaptcha";
public String getId() {
return "ShadowTextCaptcha";
}
public boolean checkAnswer(String secret, String answer) {
return answer.toLowerCase().equals(secret);
}
private byte[] shadowText(String text) {
BufferedImage img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB);
Font font = new Font("Arial", Font.ROMAN_BASELINE, 48);
Graphics2D graphics2D = img.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
TextLayout textLayout = new TextLayout(text, font, graphics2D.getFontRenderContext());
HelperFunctions.setRenderingHints(graphics2D);
graphics2D.setPaint(Color.WHITE);
graphics2D.fillRect(0, 0, 350, 100);
graphics2D.setPaint(Color.BLACK);
textLayout.draw(graphics2D, 15, 50);
graphics2D.dispose();
float[] kernel = {
1f / 9f, 1f / 9f, 1f / 9f,
1f / 9f, 1f / 9f, 1f / 9f,
1f / 9f, 1f / 9f, 1f / 9f
};
ConvolveOp op = new ConvolveOp(new Kernel(3, 3, kernel), ConvolveOp.EDGE_NO_OP, null);
BufferedImage img2 = op.filter(img, null);
Graphics2D g2d = img2.createGraphics();
HelperFunctions.setRenderingHints(g2d);
g2d.setPaint(Color.WHITE);
textLayout.draw(g2d, 13, 50);
g2d.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img2, "png", baos);
} catch (Exception e) {
e.printStackTrace();
}
return baos.toByteArray();
}
public boolean checkAnswer(String secret, String answer) {
return answer.toLowerCase().equals(secret);
}
private byte[] shadowText(String text){
BufferedImage img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB);
Font font = new Font("Arial",Font.ROMAN_BASELINE ,48);
Graphics2D graphics2D = img.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
TextLayout textLayout = new TextLayout(text, font, graphics2D.getFontRenderContext());
HelperFunctions.setRenderingHints(graphics2D);
graphics2D.setPaint(Color.WHITE);
graphics2D.fillRect(0, 0, 350, 100);
graphics2D.setPaint(Color.BLACK);
textLayout.draw(graphics2D, 15, 50);
graphics2D.dispose();
float[] kernel = {
1f / 9f, 1f / 9f, 1f / 9f,
1f / 9f, 1f / 9f, 1f / 9f,
1f / 9f, 1f / 9f, 1f / 9f
};
ConvolveOp op = new ConvolveOp(new Kernel(3, 3, kernel),
ConvolveOp.EDGE_NO_OP, null);
BufferedImage img2 = op.filter(img, null);
Graphics2D g2d = img2.createGraphics();
HelperFunctions.setRenderingHints(g2d);
g2d.setPaint(Color.WHITE);
textLayout.draw(g2d, 13, 50);
g2d.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img2,"png",baos);
}catch(Exception e){
e.printStackTrace();
}
return baos.toByteArray();
}
public Challenge returnChallenge() {
String secret = HelperFunctions.randomString(6);
return new Challenge(shadowText(secret),"image/png",secret.toLowerCase());
}
public Challenge returnChallenge() {
String secret = HelperFunctions.randomString(6);
return new Challenge(shadowText(secret), "image/png", secret.toLowerCase());
}
}

View File

@ -2,8 +2,10 @@ package lc.captchas.interfaces;
public interface ChallengeProvider {
public String getId();
public Challenge returnChallenge();
public boolean checkAnswer(String secret, String answer);
//TODO: def configure(): Unit
// TODO: def configure(): Unit
}

View File

@ -2,6 +2,7 @@
// It was available under CC By 3.0
package lc.misc;
import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
@ -10,136 +11,113 @@ import java.io.*;
import java.util.Iterator;
public class GifSequenceWriter {
protected ImageWriter gifWriter;
protected ImageWriteParam imageWriteParam;
protected IIOMetadata imageMetaData;
protected ImageWriter gifWriter;
protected ImageWriteParam imageWriteParam;
protected IIOMetadata imageMetaData;
/**
* Creates a new GifSequenceWriter
*
* @param outputStream the ImageOutputStream to be written to
* @param imageType one of the imageTypes specified in BufferedImage
* @param timeBetweenFramesMS the time between frames in miliseconds
* @param loopContinuously wether the gif should loop repeatedly
* @throws IIOException if no gif ImageWriters are found
*
* @author Elliot Kroo (elliot[at]kroo[dot]net)
*/
public GifSequenceWriter(
ImageOutputStream outputStream,
int imageType,
int timeBetweenFramesMS,
boolean loopContinuously) throws IIOException, IOException {
// my method to create a writer
gifWriter = getWriter();
imageWriteParam = gifWriter.getDefaultWriteParam();
ImageTypeSpecifier imageTypeSpecifier =
ImageTypeSpecifier.createFromBufferedImageType(imageType);
/**
* Creates a new GifSequenceWriter
*
* @param outputStream the ImageOutputStream to be written to
* @param imageType one of the imageTypes specified in BufferedImage
* @param timeBetweenFramesMS the time between frames in miliseconds
* @param loopContinuously wether the gif should loop repeatedly
* @throws IIOException if no gif ImageWriters are found
* @author Elliot Kroo (elliot[at]kroo[dot]net)
*/
public GifSequenceWriter(
ImageOutputStream outputStream,
int imageType,
int timeBetweenFramesMS,
boolean loopContinuously)
throws IIOException, IOException {
// my method to create a writer
gifWriter = getWriter();
imageWriteParam = gifWriter.getDefaultWriteParam();
ImageTypeSpecifier imageTypeSpecifier =
ImageTypeSpecifier.createFromBufferedImageType(imageType);
imageMetaData =
gifWriter.getDefaultImageMetadata(imageTypeSpecifier,
imageWriteParam);
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
String metaFormatName = imageMetaData.getNativeMetadataFormatName();
String metaFormatName = imageMetaData.getNativeMetadataFormatName();
IIOMetadataNode root = (IIOMetadataNode)
imageMetaData.getAsTree(metaFormatName);
IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName);
IIOMetadataNode graphicsControlExtensionNode = getNode(
root,
"GraphicControlExtension");
IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute(
"transparentColorFlag",
"FALSE");
graphicsControlExtensionNode.setAttribute(
"delayTime",
Integer.toString(timeBetweenFramesMS / 10));
graphicsControlExtensionNode.setAttribute(
"transparentColorIndex",
"0");
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
graphicsControlExtensionNode.setAttribute(
"delayTime", Integer.toString(timeBetweenFramesMS / 10));
graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
commentsNode.setAttribute("CommentExtension", "Created by MAH");
IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
commentsNode.setAttribute("CommentExtension", "Created by MAH");
IIOMetadataNode appEntensionsNode = getNode(
root,
"ApplicationExtensions");
IIOMetadataNode appEntensionsNode = getNode(root, "ApplicationExtensions");
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");
child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");
int loop = loopContinuously ? 0 : 1;
int loop = loopContinuously ? 0 : 1;
child.setUserObject(new byte[]{ 0x1, (byte) (loop & 0xFF), (byte)
((loop >> 8) & 0xFF)});
appEntensionsNode.appendChild(child);
child.setUserObject(new byte[] {0x1, (byte) (loop & 0xFF), (byte) ((loop >> 8) & 0xFF)});
appEntensionsNode.appendChild(child);
imageMetaData.setFromTree(metaFormatName, root);
imageMetaData.setFromTree(metaFormatName, root);
gifWriter.setOutput(outputStream);
gifWriter.setOutput(outputStream);
gifWriter.prepareWriteSequence(null);
gifWriter.prepareWriteSequence(null);
}
public void writeToSequence(RenderedImage img) throws IOException {
gifWriter.writeToSequence(new IIOImage(img, null, imageMetaData), imageWriteParam);
}
/**
* Close this GifSequenceWriter object. This does not close the underlying stream, just finishes
* off the GIF.
*/
public void close() throws IOException {
gifWriter.endWriteSequence();
}
/**
* Returns the first available GIF ImageWriter using ImageIO.getImageWritersBySuffix("gif").
*
* @return a GIF ImageWriter object
* @throws IIOException if no GIF image writers are returned
*/
private static ImageWriter getWriter() throws IIOException {
Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("gif");
if (!iter.hasNext()) {
throw new IIOException("No GIF Image Writers Exist");
} else {
return iter.next();
}
}
public void writeToSequence(RenderedImage img) throws IOException {
gifWriter.writeToSequence(
new IIOImage(
img,
null,
imageMetaData),
imageWriteParam);
}
/**
* Close this GifSequenceWriter object. This does not close the underlying
* stream, just finishes off the GIF.
*/
public void close() throws IOException {
gifWriter.endWriteSequence();
}
/**
* Returns the first available GIF ImageWriter using
* ImageIO.getImageWritersBySuffix("gif").
*
* @return a GIF ImageWriter object
* @throws IIOException if no GIF image writers are returned
*/
private static ImageWriter getWriter() throws IIOException {
Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("gif");
if(!iter.hasNext()) {
throw new IIOException("No GIF Image Writers Exist");
} else {
return iter.next();
}
}
/**
* Returns an existing child node, or creates and returns a new child node (if
* the requested node does not exist).
*
* @param rootNode the <tt>IIOMetadataNode</tt> to search for the child node.
* @param nodeName the name of the child node.
*
* @return the child node, if found or a new node created with the given name.
*/
private static IIOMetadataNode getNode(
IIOMetadataNode rootNode,
String nodeName) {
int nNodes = rootNode.getLength();
for (int i = 0; i < nNodes; i++) {
if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName)
== 0) {
return((IIOMetadataNode) rootNode.item(i));
}
}
IIOMetadataNode node = new IIOMetadataNode(nodeName);
rootNode.appendChild(node);
return(node);
/**
* Returns an existing child node, or creates and returns a new child node (if the requested node
* does not exist).
*
* @param rootNode the <tt>IIOMetadataNode</tt> to search for the child node.
* @param nodeName the name of the child node.
* @return the child node, if found or a new node created with the given name.
*/
private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName) {
int nNodes = rootNode.getLength();
for (int i = 0; i < nNodes; i++) {
if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0) {
return ((IIOMetadataNode) rootNode.item(i));
}
}
IIOMetadataNode node = new IIOMetadataNode(nodeName);
rootNode.appendChild(node);
return (node);
}
}

View File

@ -4,24 +4,24 @@ import java.awt.*;
public class HelperFunctions {
public static void setRenderingHints(Graphics2D g2d){
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
public static void setRenderingHints(Graphics2D g2d) {
g2d.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(
RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
public static String randomString(int n){
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz23456789$#%@&?";
StringBuilder stringBuilder = new StringBuilder();
for(int i=0; i<n; i++){
int index = (int)(characters.length() * Math.random());
stringBuilder.append(characters.charAt(index));
}
return stringBuilder.toString();
public static String randomString(int n) {
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz23456789$#%@&?";
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < n; i++) {
int index = (int) (characters.length() * Math.random());
stringBuilder.append(characters.charAt(index));
}
return stringBuilder.toString();
}
public static int randomNumber(int min,int max){
return (int)(Math.random() * ((max - min) +1)) + min;
}
public static int randomNumber(int min, int max) {
return (int) (Math.random() * ((max - min) + 1)) + min;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,12 @@
package lc
import org.json4s.DefaultFormats
import org.json4s.jackson.JsonMethods._
import scala.io.Source.fromFile
import lc.database.Statements
import lc.core.{Captcha, CaptchaProviders}
import lc.server.Server
import lc.background.BackgroundTask
object LCFramework{
def main(args: scala.Array[String]) {
val captcha = new Captcha()
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)
@ -20,15 +15,16 @@ object LCFramework{
}
object MakeSamples {
def main(args: scala.Array[String]) {
def main(args: scala.Array[String]): Unit = {
val samples = CaptchaProviders.generateChallengeSamples()
samples.foreach {case (key, sample) =>
val extensionMap = Map("image/png" -> "png", "image/gif" -> "gif")
println(key + ": " + sample)
samples.foreach {
case (key, sample) =>
val extensionMap = Map("image/png" -> "png", "image/gif" -> "gif")
println(key + ": " + sample)
val outStream = new java.io.FileOutputStream("samples/"+key+"."+extensionMap(sample.contentType))
outStream.write(sample.content)
outStream.close
val outStream = new java.io.FileOutputStream("samples/" + key + "." + extensionMap(sample.contentType))
outStream.write(sample.content)
outStream.close
}
}
}

View File

@ -5,34 +5,33 @@ import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
import lc.core.Captcha
import lc.core.{Parameters, Size}
class BackgroundTask(captcha: Captcha, throttle: Int) {
private val task = new Runnable {
def run(): Unit = {
try {
private val task = new Runnable {
def run(): Unit = {
try {
val mapIdGCPstmt = Statements.tlStmts.get.mapIdGCPstmt
mapIdGCPstmt.executeUpdate()
val mapIdGCPstmt = Statements.tlStmts.get.mapIdGCPstmt
mapIdGCPstmt.executeUpdate()
val challengeGCPstmt = Statements.tlStmts.get.challengeGCPstmt
challengeGCPstmt.executeUpdate()
val challengeGCPstmt = Statements.tlStmts.get.challengeGCPstmt
challengeGCPstmt.executeUpdate()
val imageNum = Statements.tlStmts.get.getCountChallengeTable.executeQuery()
var throttleIn = (throttle*1.1).toInt
if(imageNum.next())
throttleIn = (throttleIn-imageNum.getInt("total"))
while(0 < throttleIn){
captcha.generateChallenge(Parameters("","","",Option(Size(0,0))))
throttleIn -= 1
}
} catch { case e: Exception => println(e) }
val imageNum = Statements.tlStmts.get.getCountChallengeTable.executeQuery()
var throttleIn = (throttle * 1.1).toInt
if (imageNum.next())
throttleIn = (throttleIn - imageNum.getInt("total"))
while (0 < throttleIn) {
captcha.generateChallenge(Parameters("", "", "", Option(Size(0, 0))))
throttleIn -= 1
}
} catch { case e: Exception => println(e) }
}
def beginThread(delay: Int) : Unit = {
val ex = new ScheduledThreadPoolExecutor(1)
val thread = ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
}
}
def beginThread(delay: Int): Unit = {
val ex = new ScheduledThreadPoolExecutor(1)
ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
}
}

View File

@ -8,7 +8,6 @@ import java.awt.Color
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
class FilterChallenge extends ChallengeProvider {
def getId = "FilterChallenge"
def returnChallenge(): Challenge = {
@ -62,4 +61,3 @@ class FilterType2 extends FilterType {
image
}
}

View File

@ -4,45 +4,45 @@ import java.io.File
import java.io.ByteArrayOutputStream
import javax.imageio.ImageIO
import scala.collection.mutable.Map
import java.nio.file.{Files,Path,StandardCopyOption}
import java.nio.file.{Files, StandardCopyOption}
import java.awt.image.BufferedImage
import java.awt.{Graphics2D,Color}
import java.awt.Color
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
class LabelCaptcha extends ChallengeProvider {
private var knownFiles = new File("known").list.toList
private var unknownFiles = new File("unknown").list.toList
private var unknownAnswers = Map[String, Map[String, Int]]()
private var total = Map[String, Int]()
private val unknownAnswers = Map[String, Map[String, Int]]()
private val total = Map[String, Int]()
for(file <- unknownFiles) {
unknownAnswers += file -> Map[String, Int]()
total += file -> 0
for (file <- unknownFiles) {
unknownAnswers += file -> Map[String, Int]()
total += file -> 0
}
def getId = "LabelCaptcha"
def returnChallenge(): Challenge = synchronized {
val r = scala.util.Random.nextInt(knownFiles.length)
val s = scala.util.Random.nextInt(unknownFiles.length)
val knownImageFile = knownFiles(r)
val unknownImageFile = unknownFiles(s)
val ip = new ImagePair(knownImageFile, unknownImageFile)
def returnChallenge(): Challenge =
synchronized {
val r = scala.util.Random.nextInt(knownFiles.length)
val s = scala.util.Random.nextInt(unknownFiles.length)
val knownImageFile = knownFiles(r)
val unknownImageFile = unknownFiles(s)
var knownImage = ImageIO.read(new File("known/"+knownImageFile))
var unknownImage = ImageIO.read(new File("unknown/"+unknownImageFile))
val mergedImage = merge(knownImage, unknownImage)
val knownImage = ImageIO.read(new File("known/" + knownImageFile))
val unknownImage = ImageIO.read(new File("unknown/" + unknownImageFile))
val mergedImage = merge(knownImage, unknownImage)
val token = encrypt(knownImageFile + "," + unknownImageFile)
val baos = new ByteArrayOutputStream()
ImageIO.write(mergedImage,"png",baos)
val token = encrypt(knownImageFile + "," + unknownImageFile)
val baos = new ByteArrayOutputStream()
ImageIO.write(mergedImage, "png", baos)
new Challenge(baos.toByteArray(), "image/png", token)
}
new Challenge(baos.toByteArray(), "image/png", token)
}
private def merge(knownImage: BufferedImage, unknownImage: BufferedImage) = {
val width = knownImage.getWidth()+unknownImage.getWidth()
val width = knownImage.getWidth() + unknownImage.getWidth()
val height = List(knownImage.getHeight(), unknownImage.getHeight()).max
val imageType = knownImage.getType()
val finalImage = new BufferedImage(width, height, imageType)
@ -55,34 +55,39 @@ class LabelCaptcha extends ChallengeProvider {
finalImage
}
def checkAnswer(token: String, input: String): Boolean = synchronized {
val parts = decrypt(token).split(",")
val knownImage = parts(0)
val unknownImage = parts(1)
val expectedAnswer = knownImage.split('.')(0)
val userAnswer = input.split(' ')
if(userAnswer(0)==expectedAnswer) {
val unknownFile = unknownImage
if((unknownAnswers(unknownFile)).contains(userAnswer(1))) {
unknownAnswers(unknownFile)(userAnswer(1)) += 1
total(unknownFile) += 1
} else {
unknownAnswers(unknownFile)+=(userAnswer(1)) -> 1
total(unknownFile) += 1
}
if(total(unknownFile)>=3) {
if((unknownAnswers(unknownFile)(userAnswer(1))/total(unknownFile))>=0.9) {
unknownAnswers -= unknownFile
Files.move(new File("unknown/"+unknownFile).toPath, new File("known/"+userAnswer(1)+".png").toPath, StandardCopyOption.REPLACE_EXISTING)
knownFiles = new File("known").list.toList
unknownFiles = new File("unknown").list.toList
def checkAnswer(token: String, input: String): Boolean =
synchronized {
val parts = decrypt(token).split(",")
val knownImage = parts(0)
val unknownImage = parts(1)
val expectedAnswer = knownImage.split('.')(0)
val userAnswer = input.split(' ')
if (userAnswer(0) == expectedAnswer) {
val unknownFile = unknownImage
if ((unknownAnswers(unknownFile)).contains(userAnswer(1))) {
unknownAnswers(unknownFile)(userAnswer(1)) += 1
total(unknownFile) += 1
} else {
unknownAnswers(unknownFile) += (userAnswer(1)) -> 1
total(unknownFile) += 1
}
if (total(unknownFile) >= 3) {
if ((unknownAnswers(unknownFile)(userAnswer(1)) / total(unknownFile)) >= 0.9) {
unknownAnswers -= unknownFile
Files.move(
new File("unknown/" + unknownFile).toPath,
new File("known/" + userAnswer(1) + ".png").toPath,
StandardCopyOption.REPLACE_EXISTING
)
knownFiles = new File("known").list.toList
unknownFiles = new File("unknown").list.toList
}
}
true
} else {
false
}
true
} else {
false
}
}
// TODO: Encryption is not implemented for the POC, since the API re-maps the tokens anyway.
// But we need to encrypt after POC, to avoid leaking file-names.

View File

@ -5,9 +5,7 @@ import java.awt.RenderingHints
import java.awt.Font
import java.awt.font.TextAttribute
import java.awt.Color
import java.io.ByteArrayOutputStream
import javax.imageio.ImageIO
import javax.imageio.stream.ImageOutputStream;
import java.io.ByteArrayOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
@ -19,8 +17,8 @@ class Drop {
var yOffset = 0
var color = 0
var colorChange = 10
def mkColor = {
new Color(color, color, math.min(200, color+100))
def mkColor: Color = {
new Color(color, color, math.min(200, color + 100))
}
}
@ -36,8 +34,8 @@ class RainDropsCP extends ChallengeProvider {
private def extendDrops(drops: Array[Drop], steps: Int, xOffset: Int) = {
drops.map(d => {
val nd = new Drop()
nd.x + xOffset*steps
nd.y + d.yOffset*steps
nd.x + xOffset * steps
nd.y + d.yOffset * steps
nd
})
}
@ -48,20 +46,23 @@ class RainDropsCP extends ChallengeProvider {
val width = 450
val height = 100
val imgType = BufferedImage.TYPE_INT_RGB
val xOffset = 2+r.nextInt(3)
val xOffset = 2 + r.nextInt(3)
val xBias = (height / 10) - 2
val dropsOrig = Array.fill[Drop](2000)( new Drop())
val dropsOrig = Array.fill[Drop](2000)(new Drop())
for (d <- dropsOrig) {
d.x = r.nextInt(width) - (xBias/2)*xOffset
d.yOffset = 6+r.nextInt(6)
d.x = r.nextInt(width) - (xBias / 2) * xOffset
d.yOffset = 6 + r.nextInt(6)
d.y = r.nextInt(height)
d.color = r.nextInt(240)
if (d.color > 128) {
d.colorChange *= -1
}
}
val drops = dropsOrig ++ extendDrops(dropsOrig, 1, xOffset) ++ extendDrops(dropsOrig, 2, xOffset) ++ extendDrops(dropsOrig, 3, xOffset)
val drops = dropsOrig ++ extendDrops(dropsOrig, 1, xOffset) ++ extendDrops(dropsOrig, 2, xOffset) ++ extendDrops(
dropsOrig,
3,
xOffset
)
val baseFont = new Font(Font.MONOSPACED, Font.BOLD, 80)
val attributes = new java.util.HashMap[TextAttribute, Object]()
@ -72,7 +73,7 @@ class RainDropsCP extends ChallengeProvider {
val baos = new ByteArrayOutputStream();
val ios = new MemoryCacheImageOutputStream(baos);
val writer = new GifSequenceWriter(ios, imgType, 60, true);
for(i <- 0 until 60){
for (_ <- 0 until 60) {
// val yOffset = 5+r.nextInt(5)
val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
val g = canvas.createGraphics()
@ -85,14 +86,14 @@ class RainDropsCP extends ChallengeProvider {
// paint the rain
for (d <- drops) {
g.setColor(d.mkColor)
g.drawLine(d.x, d.y, d.x+xOffset, d.y+d.yOffset)
d.x += xOffset/2
d.y += d.yOffset/2
g.drawLine(d.x, d.y, d.x + xOffset, d.y + d.yOffset)
d.x += xOffset / 2
d.y += d.yOffset / 2
d.color += d.colorChange
if (d.x > width || d.y > height) {
val ySteps = (height / d.yOffset) + 1
d.x -= xOffset*ySteps
d.y -= d.yOffset*ySteps
val ySteps = (height / d.yOffset) + 1
d.x -= xOffset * ySteps
d.y -= d.yOffset * ySteps
}
if (d.color > 200 || d.color < 21) {
@ -103,7 +104,7 @@ class RainDropsCP extends ChallengeProvider {
// center the text
g.setFont(spacedFont)
val textWidth = g.getFontMetrics().charsWidth(secret.toCharArray, 0, secret.toCharArray.length)
val textX = (width - textWidth)/2
val textX = (width - textWidth) / 2
// paint the top outline
g.setColor(textHighlightColor)

View File

@ -1,6 +1,5 @@
package lc.core
import org.json4s.JsonAST.JValue
import java.sql.{Blob, ResultSet}
import java.util.UUID
import java.io.ByteArrayInputStream
@ -10,29 +9,30 @@ import lc.core.CaptchaProviders
class Captcha {
def getCaptcha(id: Id): Array[Byte] = {
var image :Array[Byte] = null
var image: Array[Byte] = null
var blob: Blob = null
try {
val imagePstmt = Statements.tlStmts.get.imagePstmt
imagePstmt.setString(1, id.id)
val rs: ResultSet = imagePstmt.executeQuery()
if(rs.next()){
imagePstmt.setString(1, id.id)
val rs: ResultSet = imagePstmt.executeQuery()
if (rs.next()) {
blob = rs.getBlob("image")
if(blob != null){
image = blob.getBytes(1, blob.length().toInt)
if (blob != null) {
image = blob.getBytes(1, blob.length().toInt)
}
}
image
} catch { case e: Exception =>
println(e)
image
} catch {
case e: Exception =>
println(e)
image
}
}
def generateChallenge(param: Parameters): Int = {
//TODO: eval params to choose a provider
val provider = CaptchaProviders.getProvider()
val providerId = provider.getId()
//TODO: eval params to choose a provider
val provider = CaptchaProviders.getProvider()
val providerId = provider.getId()
val challenge = provider.returnChallenge()
val blob = new ByteArrayInputStream(challenge.content)
val insertPstmt = Statements.tlStmts.get.insertPstmt
@ -43,10 +43,10 @@ class Captcha {
insertPstmt.setBlob(5, blob)
insertPstmt.executeUpdate()
val rs: ResultSet = insertPstmt.getGeneratedKeys()
val token = if(rs.next()){
val token = if (rs.next()) {
rs.getInt("token")
}
println("Added new challenge: "+ token.toString)
println("Added new challenge: " + token.toString)
token.asInstanceOf[Int]
}
@ -54,7 +54,7 @@ class Captcha {
try {
val tokenPstmt = Statements.tlStmts.get.tokenPstmt
val rs = tokenPstmt.executeQuery()
val tokenOpt = if(rs.next()) {
val tokenOpt = if (rs.next()) {
Some(rs.getInt("token"))
} else {
None
@ -64,44 +64,45 @@ class Captcha {
updateAttemptedPstmt.setString(1, uuid)
updateAttemptedPstmt.executeUpdate()
Id(uuid)
} catch {case e: Exception =>
println(e)
Id(getUUID(-1))
} catch {
case e: Exception =>
println(e)
Id(getUUID(-1))
}
}
private def getUUID(id: Int): String = {
val uuid = UUID.randomUUID().toString
val mapPstmt = Statements.tlStmts.get.mapPstmt
mapPstmt.setString(1,uuid)
mapPstmt.setInt(2,id)
mapPstmt.setString(1, uuid)
mapPstmt.setInt(2, id)
mapPstmt.executeUpdate()
uuid
}
def checkAnswer(answer: Answer): Result = {
val selectPstmt = Statements.tlStmts.get.selectPstmt
selectPstmt.setString(1, answer.id)
val rs: ResultSet = selectPstmt.executeQuery()
val psOpt = if (rs.first()) {
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"
result
} else {
"EXPIRED"
}
val deleteAnswerPstmt = Statements.tlStmts.get.deleteAnswerPstmt
deleteAnswerPstmt.setString(1, answer.id)
deleteAnswerPstmt.executeUpdate()
Result(psOpt)
val selectPstmt = Statements.tlStmts.get.selectPstmt
selectPstmt.setString(1, answer.id)
val rs: ResultSet = selectPstmt.executeQuery()
val psOpt = if (rs.first()) {
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"
result
} else {
"EXPIRED"
}
val deleteAnswerPstmt = Statements.tlStmts.get.deleteAnswerPstmt
deleteAnswerPstmt.setString(1, answer.id)
deleteAnswerPstmt.executeUpdate()
Result(psOpt)
}
def display(): Unit = {
val rs: ResultSet = Statements.tlStmts.get.getChallengeTable.executeQuery()
println("token\t\tid\t\tsecret\t\tattempted")
while(rs.next()) {
while (rs.next()) {
val token = rs.getInt("token")
val id = rs.getString("id")
val secret = rs.getString("secret")
@ -111,11 +112,11 @@ class Captcha {
val rss: ResultSet = Statements.tlStmts.get.getMapIdTable.executeQuery()
println("uuid\t\ttoken\t\tlastServed")
while(rss.next()){
while (rss.next()) {
val uuid = rss.getString("uuid")
val token = rss.getInt("token")
val lastServed = rss.getTimestamp("lastServed")
println(s"${uuid}\t\t${token}\t\t${lastServed}\n\n")
}
}
}
}

View File

@ -2,6 +2,7 @@ package lc.core
import lc.captchas._
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
object CaptchaProviders {
private val providers = Map(
@ -9,30 +10,32 @@ object CaptchaProviders {
//"FontFunCaptcha" -> new FontFunCaptcha,
"GifCaptcha" -> new GifCaptcha,
"ShadowTextCaptcha" -> new ShadowTextCaptcha,
"RainDropsCaptcha" -> new RainDropsCP,
"RainDropsCaptcha" -> new RainDropsCP
//"LabelCaptcha" -> new LabelCaptcha
)
)
def generateChallengeSamples() = {
providers.map {case (key, provider) =>
(key, provider.returnChallenge())
def generateChallengeSamples(): Map[String, Challenge] = {
providers.map {
case (key, provider) =>
(key, provider.returnChallenge())
}
}
private val seed = System.currentTimeMillis.toString.substring(2,6).toInt
private val seed = System.currentTimeMillis.toString.substring(2, 6).toInt
private val random = new scala.util.Random(seed)
private def getNextRandomInt(max: Int) = random.synchronized {
random.nextInt(max)
}
private def getNextRandomInt(max: Int) =
random.synchronized {
random.nextInt(max)
}
def getProviderById(id: String): ChallengeProvider = {
return providers(id)
}
def getProvider(): ChallengeProvider = {
val keys = providers.keys
val providerIndex = keys.toVector(getNextRandomInt(keys.size))
providers(providerIndex)
}
}
}

View File

@ -4,4 +4,4 @@ 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 Result(result: String)
case class Result(result: String)

View File

@ -2,7 +2,7 @@ package lc.database
import java.sql._
class DBConn(){
class DBConn() {
val con: Connection = DriverManager.getConnection("jdbc:h2:./data/H2/captcha", "sa", "")
def getStatement(): Statement = {
@ -10,6 +10,6 @@ class DBConn(){
}
def closeConnection(): Unit = {
con.close()
con.close()
}
}

View File

@ -2,30 +2,108 @@ package lc.database
import lc.database.DBConn
import java.sql.Statement
import java.sql.PreparedStatement
class Statements(dbConn: DBConn) {
private val stmt = dbConn.getStatement()
stmt.execute("CREATE TABLE IF NOT EXISTS challenge(token int auto_increment, id varchar, secret varchar, provider varchar, contentType varchar, image blob, attempted int default 0, PRIMARY KEY(token))")
stmt.execute("CREATE TABLE IF NOT EXISTS mapId(uuid varchar, token int, lastServed timestamp, PRIMARY KEY(uuid), FOREIGN KEY(token) REFERENCES challenge(token) ON DELETE CASCADE)")
stmt.execute(
"CREATE TABLE IF NOT EXISTS challenge" +
"(token int auto_increment, " +
"id varchar, " +
"secret varchar, " +
"provider varchar, " +
"contentType varchar, " +
"image blob, " +
"attempted int default 0, " +
"PRIMARY KEY(token))"
)
stmt.execute(
"CREATE TABLE IF NOT EXISTS mapId" +
"(uuid varchar, " +
"token int, " +
"lastServed timestamp, " +
"PRIMARY KEY(uuid), " +
"FOREIGN KEY(token) " +
"REFERENCES challenge(token) " +
"ON DELETE CASCADE)"
)
val insertPstmt = dbConn.con.prepareStatement("INSERT INTO challenge(id, secret, provider, contentType, image) VALUES (?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS )
val mapPstmt = dbConn.con.prepareStatement("INSERT INTO mapId(uuid, token, lastServed) VALUES (?, ?, CURRENT_TIMESTAMP)")
val selectPstmt = dbConn.con.prepareStatement("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 m.uuid = ?")
val imagePstmt = dbConn.con.prepareStatement("SELECT image FROM challenge c, mapId m WHERE c.token=m.token AND m.uuid = ?")
val updateAttemptedPstmt = dbConn.con.prepareStatement("UPDATE challenge SET attempted = attempted+1 WHERE token = (SELECT m.token FROM mapId m, challenge c WHERE m.token=c.token AND m.uuid = ?)")
val tokenPstmt = dbConn.con.prepareStatement("SELECT token FROM challenge WHERE attempted < 10 ORDER BY RAND() LIMIT 1")
val deleteAnswerPstmt = dbConn.con.prepareStatement("DELETE FROM mapId WHERE uuid = ?")
val challengeGCPstmt = dbConn.con.prepareStatement("DELETE FROM challenge WHERE attempted >= 10 AND token NOT IN (SELECT token FROM mapId)")
val mapIdGCPstmt = dbConn.con.prepareStatement("DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, lastServed)) < 0")
val insertPstmt: PreparedStatement = dbConn.con.prepareStatement(
"INSERT INTO " +
"challenge(id, secret, provider, contentType, image) " +
"VALUES (?, ?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS
)
val mapPstmt: PreparedStatement =
dbConn.con.prepareStatement(
"INSERT INTO " +
"mapId(uuid, token, lastServed) " +
"VALUES (?, ?, CURRENT_TIMESTAMP)"
)
val selectPstmt: PreparedStatement = dbConn.con.prepareStatement(
"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 " +
"m.uuid = ?"
)
val imagePstmt: PreparedStatement = dbConn.con.prepareStatement(
"SELECT image " +
"FROM challenge c, mapId m " +
"WHERE c.token=m.token AND " +
"m.uuid = ?"
)
val updateAttemptedPstmt: PreparedStatement = dbConn.con.prepareStatement(
"UPDATE challenge " +
"SET attempted = attempted+1 " +
"WHERE token = (SELECT m.token " +
"FROM mapId m, challenge c " +
"WHERE m.token=c.token AND " +
"m.uuid = ?)"
)
val tokenPstmt: PreparedStatement = dbConn.con.prepareStatement(
"SELECT token " +
"FROM challenge " +
"WHERE attempted < 10 " +
"ORDER BY RAND() LIMIT 1"
)
val deleteAnswerPstmt: PreparedStatement = dbConn.con.prepareStatement(
"DELETE FROM mapId WHERE uuid = ?"
)
val challengeGCPstmt: PreparedStatement = dbConn.con.prepareStatement(
"DELETE FROM challenge " +
"WHERE attempted >= 10 AND " +
"token NOT IN (SELECT token FROM mapId)"
)
val mapIdGCPstmt: PreparedStatement = dbConn.con.prepareStatement(
"DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, lastServed)) < 0"
)
val getCountChallengeTable: PreparedStatement = dbConn.con.prepareStatement(
"SELECT COUNT(*) AS total FROM challenge"
)
val getChallengeTable: PreparedStatement = dbConn.con.prepareStatement(
"SELECT * FROM challenge"
)
val getMapIdTable: PreparedStatement = dbConn.con.prepareStatement(
"SELECT * FROM mapId"
)
val getCountChallengeTable = dbConn.con.prepareStatement("SELECT COUNT(*) AS total FROM challenge")
val getChallengeTable = dbConn.con.prepareStatement("SELECT * FROM challenge")
val getMapIdTable = dbConn.con.prepareStatement("SELECT * FROM mapId")
}
object Statements {
private val dbConn: DBConn = new DBConn()
val tlStmts = ThreadLocal.withInitial(() => new Statements(dbConn))
}
val tlStmts: ThreadLocal[Statements] = ThreadLocal.withInitial(() => new Statements(dbConn))
}

View File

@ -7,46 +7,56 @@ import lc.core.Captcha
import lc.core.{Parameters, Id, Answer}
import lc.server.HTTPServer
class Server(port: Int, captcha: Captcha) {
val server = new HTTPServer(port)
val host: HTTPServer.VirtualHost = server.getVirtualHost(null)
class Server(port: Int, captcha: Captcha){
val server = new HTTPServer(port)
val host = server.getVirtualHost(null)
implicit val formats: DefaultFormats.type = DefaultFormats
implicit val formats = DefaultFormats
host.addContext(
"/v1/captcha",
(req, resp) => {
val body = req.getJson()
val json = parse(body)
val param = json.extract[Parameters]
val id = captcha.getChallenge(param)
resp.getHeaders().add("Content-Type", "application/json")
resp.send(200, write(id))
0
},
"POST"
)
host.addContext("/v1/captcha",(req, resp) => {
val body = req.getJson()
val json = parse(body)
val param = json.extract[Parameters]
val id = captcha.getChallenge(param)
resp.getHeaders().add("Content-Type","application/json")
resp.send(200, write(id))
0
},"POST")
host.addContext(
"/v1/media",
(req, resp) => {
val params = req.getParams()
val id = Id(params.get("id"))
val image = captcha.getCaptcha(id)
resp.getHeaders().add("Content-Type", "image/png")
resp.send(200, image)
0
},
"GET"
)
host.addContext("/v1/media",(req, resp) => {
val params = req.getParams()
val id = Id(params.get("id"))
val image = captcha.getCaptcha(id)
resp.getHeaders().add("Content-Type","image/png")
resp.send(200, image)
0
},"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")
resp.send(200, write(result))
0
},
"POST"
)
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")
resp.send(200, write(result))
0
},"POST")
def start(): Unit = {
println("Starting server on port:" + port)
server.start()
}
def start(): Unit = {
println("Starting server on port:" + port)
server.start()
}
}