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:
parent
6d04cdc3b4
commit
de50d8123e
|
@ -19,3 +19,5 @@ jobs:
|
||||||
java-version: 1.8
|
java-version: 1.8
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: sbt test
|
run: sbt test
|
||||||
|
- name: Run linter
|
||||||
|
run: sbt "scalafixAll --check"
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
rules=[
|
||||||
|
ExplicitResultTypes,
|
||||||
|
RemoveUnused,
|
||||||
|
DisableSyntax,
|
||||||
|
LeakingImplicitClassVal,
|
||||||
|
NoValInForComprehension,
|
||||||
|
ProcedureSyntax
|
||||||
|
]
|
|
@ -0,0 +1,2 @@
|
||||||
|
version=2.5.2
|
||||||
|
maxColumn = 120
|
|
@ -4,3 +4,4 @@ scala:
|
||||||
- 2.13.2
|
- 2.13.2
|
||||||
script:
|
script:
|
||||||
- sbt ++$TRAVIS_SCALA_VERSION compile
|
- sbt ++$TRAVIS_SCALA_VERSION compile
|
||||||
|
- sbt "scalafixAll --check"
|
||||||
|
|
22
build.sbt
22
build.sbt
|
@ -1,21 +1,27 @@
|
||||||
lazy val root = (project in file(".")).
|
lazy val root = (project in file(".")).settings(
|
||||||
settings(
|
inThisBuild(
|
||||||
inThisBuild(List(
|
List(
|
||||||
organization := "com.example",
|
organization := "com.example",
|
||||||
scalaVersion := "2.13.3",
|
scalaVersion := "2.13.3",
|
||||||
version := "0.1.0-SNAPSHOT")),
|
version := "0.1.0-SNAPSHOT",
|
||||||
|
semanticdbEnabled := true,
|
||||||
|
semanticdbVersion := scalafixSemanticdb.revision,
|
||||||
|
scalafixScalaBinaryVersion := "2.13"
|
||||||
|
)
|
||||||
|
),
|
||||||
name := "LibreCaptcha",
|
name := "LibreCaptcha",
|
||||||
|
|
||||||
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-core" % "4.0.5",
|
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-core" % "4.0.5",
|
||||||
|
|
||||||
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-filters" % "4.0.5",
|
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-filters" % "4.0.5",
|
||||||
|
|
||||||
libraryDependencies += "org.json4s" % "json4s-jackson_2.13" % "3.6.9"
|
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"
|
javacOptions += "-g:none"
|
||||||
|
scalafmtOnCompile := true
|
||||||
compileOrder := CompileOrder.JavaThenScala
|
compileOrder := CompileOrder.JavaThenScala
|
||||||
|
|
||||||
fork in run := true
|
fork in run := true
|
||||||
|
|
|
@ -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")
|
|
@ -18,18 +18,19 @@ public class FontFunCaptcha implements ChallengeProvider{
|
||||||
|
|
||||||
private String getFontName(String path, String level) {
|
private String getFontName(String path, String level) {
|
||||||
File file = new File(path + level + "/");
|
File file = new File(path + level + "/");
|
||||||
FilenameFilter txtFileFilter = new FilenameFilter() {
|
FilenameFilter txtFileFilter =
|
||||||
|
new FilenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File dir, String name)
|
public boolean accept(File dir, String name) {
|
||||||
{
|
if (name.endsWith(".ttf")) return true;
|
||||||
if(name.endsWith(".ttf"))
|
else return false;
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
File[] files = file.listFiles(txtFileFilter);
|
File[] files = file.listFiles(txtFileFilter);
|
||||||
return path+level.toLowerCase()+"/"+files[HelperFunctions.randomNumber(0,files.length-1)].getName();
|
return path
|
||||||
|
+ level.toLowerCase()
|
||||||
|
+ "/"
|
||||||
|
+ files[HelperFunctions.randomNumber(0, files.length - 1)].getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Font loadCustomFont(String level, String path) {
|
private Font loadCustomFont(String level, String path) {
|
||||||
|
@ -54,7 +55,8 @@ public class FontFunCaptcha implements ChallengeProvider{
|
||||||
FontMetrics fontMetrics = graphics2D.getFontMetrics();
|
FontMetrics fontMetrics = graphics2D.getFontMetrics();
|
||||||
HelperFunctions.setRenderingHints(graphics2D);
|
HelperFunctions.setRenderingHints(graphics2D);
|
||||||
graphics2D.setColor(Color.decode(colors[HelperFunctions.randomNumber(0, 3)]));
|
graphics2D.setColor(Color.decode(colors[HelperFunctions.randomNumber(0, 3)]));
|
||||||
graphics2D.drawString(String.valueOf(captchaText.charAt(i)), (i * 48), fontMetrics.getAscent());
|
graphics2D.drawString(
|
||||||
|
String.valueOf(captchaText.charAt(i)), (i * 48), fontMetrics.getAscent());
|
||||||
}
|
}
|
||||||
graphics2D.dispose();
|
graphics2D.dispose();
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
|
@ -21,7 +21,8 @@ public class GifCaptcha implements ChallengeProvider{
|
||||||
Font font = new Font("Bradley Hand", Font.ROMAN_BASELINE, 48);
|
Font font = new Font("Bradley Hand", Font.ROMAN_BASELINE, 48);
|
||||||
Graphics2D graphics2D = img.createGraphics();
|
Graphics2D graphics2D = img.createGraphics();
|
||||||
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
graphics2D.setRenderingHint(
|
||||||
|
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||||
graphics2D.setFont(font);
|
graphics2D.setFont(font);
|
||||||
graphics2D.setColor(new Color((int) (Math.random() * 0x1000000)));
|
graphics2D.setColor(new Color((int) (Math.random() * 0x1000000)));
|
||||||
graphics2D.drawString(text, 45, 45);
|
graphics2D.drawString(text, 45, 45);
|
||||||
|
|
|
@ -29,7 +29,8 @@ public class ShadowTextCaptcha implements ChallengeProvider{
|
||||||
Font font = new Font("Arial", Font.ROMAN_BASELINE, 48);
|
Font font = new Font("Arial", Font.ROMAN_BASELINE, 48);
|
||||||
Graphics2D graphics2D = img.createGraphics();
|
Graphics2D graphics2D = img.createGraphics();
|
||||||
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
graphics2D.setRenderingHint(
|
||||||
|
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||||
|
|
||||||
TextLayout textLayout = new TextLayout(text, font, graphics2D.getFontRenderContext());
|
TextLayout textLayout = new TextLayout(text, font, graphics2D.getFontRenderContext());
|
||||||
HelperFunctions.setRenderingHints(graphics2D);
|
HelperFunctions.setRenderingHints(graphics2D);
|
||||||
|
@ -43,8 +44,7 @@ public class ShadowTextCaptcha implements ChallengeProvider{
|
||||||
1f / 9f, 1f / 9f, 1f / 9f,
|
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 op = new ConvolveOp(new Kernel(3, 3, kernel), ConvolveOp.EDGE_NO_OP, null);
|
||||||
ConvolveOp.EDGE_NO_OP, null);
|
|
||||||
BufferedImage img2 = op.filter(img, null);
|
BufferedImage img2 = op.filter(img, null);
|
||||||
Graphics2D g2d = img2.createGraphics();
|
Graphics2D g2d = img2.createGraphics();
|
||||||
HelperFunctions.setRenderingHints(g2d);
|
HelperFunctions.setRenderingHints(g2d);
|
||||||
|
|
|
@ -2,7 +2,9 @@ package lc.captchas.interfaces;
|
||||||
|
|
||||||
public interface ChallengeProvider {
|
public interface ChallengeProvider {
|
||||||
public String getId();
|
public String getId();
|
||||||
|
|
||||||
public Challenge returnChallenge();
|
public Challenge returnChallenge();
|
||||||
|
|
||||||
public boolean checkAnswer(String secret, String answer);
|
public boolean checkAnswer(String secret, String answer);
|
||||||
|
|
||||||
// TODO: def configure(): Unit
|
// TODO: def configure(): Unit
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// It was available under CC By 3.0
|
// It was available under CC By 3.0
|
||||||
|
|
||||||
package lc.misc;
|
package lc.misc;
|
||||||
|
|
||||||
import javax.imageio.*;
|
import javax.imageio.*;
|
||||||
import javax.imageio.metadata.*;
|
import javax.imageio.metadata.*;
|
||||||
import javax.imageio.stream.*;
|
import javax.imageio.stream.*;
|
||||||
|
@ -22,51 +23,39 @@ public class GifSequenceWriter {
|
||||||
* @param timeBetweenFramesMS the time between frames in miliseconds
|
* @param timeBetweenFramesMS the time between frames in miliseconds
|
||||||
* @param loopContinuously wether the gif should loop repeatedly
|
* @param loopContinuously wether the gif should loop repeatedly
|
||||||
* @throws IIOException if no gif ImageWriters are found
|
* @throws IIOException if no gif ImageWriters are found
|
||||||
*
|
|
||||||
* @author Elliot Kroo (elliot[at]kroo[dot]net)
|
* @author Elliot Kroo (elliot[at]kroo[dot]net)
|
||||||
*/
|
*/
|
||||||
public GifSequenceWriter(
|
public GifSequenceWriter(
|
||||||
ImageOutputStream outputStream,
|
ImageOutputStream outputStream,
|
||||||
int imageType,
|
int imageType,
|
||||||
int timeBetweenFramesMS,
|
int timeBetweenFramesMS,
|
||||||
boolean loopContinuously) throws IIOException, IOException {
|
boolean loopContinuously)
|
||||||
|
throws IIOException, IOException {
|
||||||
// my method to create a writer
|
// my method to create a writer
|
||||||
gifWriter = getWriter();
|
gifWriter = getWriter();
|
||||||
imageWriteParam = gifWriter.getDefaultWriteParam();
|
imageWriteParam = gifWriter.getDefaultWriteParam();
|
||||||
ImageTypeSpecifier imageTypeSpecifier =
|
ImageTypeSpecifier imageTypeSpecifier =
|
||||||
ImageTypeSpecifier.createFromBufferedImageType(imageType);
|
ImageTypeSpecifier.createFromBufferedImageType(imageType);
|
||||||
|
|
||||||
imageMetaData =
|
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
|
||||||
gifWriter.getDefaultImageMetadata(imageTypeSpecifier,
|
|
||||||
imageWriteParam);
|
|
||||||
|
|
||||||
String metaFormatName = imageMetaData.getNativeMetadataFormatName();
|
String metaFormatName = imageMetaData.getNativeMetadataFormatName();
|
||||||
|
|
||||||
IIOMetadataNode root = (IIOMetadataNode)
|
IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName);
|
||||||
imageMetaData.getAsTree(metaFormatName);
|
|
||||||
|
|
||||||
IIOMetadataNode graphicsControlExtensionNode = getNode(
|
IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
|
||||||
root,
|
|
||||||
"GraphicControlExtension");
|
|
||||||
|
|
||||||
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
|
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
|
||||||
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
|
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
|
||||||
|
graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
|
||||||
graphicsControlExtensionNode.setAttribute(
|
graphicsControlExtensionNode.setAttribute(
|
||||||
"transparentColorFlag",
|
"delayTime", Integer.toString(timeBetweenFramesMS / 10));
|
||||||
"FALSE");
|
graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
|
||||||
graphicsControlExtensionNode.setAttribute(
|
|
||||||
"delayTime",
|
|
||||||
Integer.toString(timeBetweenFramesMS / 10));
|
|
||||||
graphicsControlExtensionNode.setAttribute(
|
|
||||||
"transparentColorIndex",
|
|
||||||
"0");
|
|
||||||
|
|
||||||
IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
|
IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
|
||||||
commentsNode.setAttribute("CommentExtension", "Created by MAH");
|
commentsNode.setAttribute("CommentExtension", "Created by MAH");
|
||||||
|
|
||||||
IIOMetadataNode appEntensionsNode = getNode(
|
IIOMetadataNode appEntensionsNode = getNode(root, "ApplicationExtensions");
|
||||||
root,
|
|
||||||
"ApplicationExtensions");
|
|
||||||
|
|
||||||
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
|
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
|
||||||
|
|
||||||
|
@ -75,8 +64,7 @@ public class GifSequenceWriter {
|
||||||
|
|
||||||
int loop = loopContinuously ? 0 : 1;
|
int loop = loopContinuously ? 0 : 1;
|
||||||
|
|
||||||
child.setUserObject(new byte[]{ 0x1, (byte) (loop & 0xFF), (byte)
|
child.setUserObject(new byte[] {0x1, (byte) (loop & 0xFF), (byte) ((loop >> 8) & 0xFF)});
|
||||||
((loop >> 8) & 0xFF)});
|
|
||||||
appEntensionsNode.appendChild(child);
|
appEntensionsNode.appendChild(child);
|
||||||
|
|
||||||
imageMetaData.setFromTree(metaFormatName, root);
|
imageMetaData.setFromTree(metaFormatName, root);
|
||||||
|
@ -87,25 +75,19 @@ public class GifSequenceWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeToSequence(RenderedImage img) throws IOException {
|
public void writeToSequence(RenderedImage img) throws IOException {
|
||||||
gifWriter.writeToSequence(
|
gifWriter.writeToSequence(new IIOImage(img, null, imageMetaData), imageWriteParam);
|
||||||
new IIOImage(
|
|
||||||
img,
|
|
||||||
null,
|
|
||||||
imageMetaData),
|
|
||||||
imageWriteParam);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close this GifSequenceWriter object. This does not close the underlying
|
* Close this GifSequenceWriter object. This does not close the underlying stream, just finishes
|
||||||
* stream, just finishes off the GIF.
|
* off the GIF.
|
||||||
*/
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
gifWriter.endWriteSequence();
|
gifWriter.endWriteSequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the first available GIF ImageWriter using
|
* Returns the first available GIF ImageWriter using ImageIO.getImageWritersBySuffix("gif").
|
||||||
* ImageIO.getImageWritersBySuffix("gif").
|
|
||||||
*
|
*
|
||||||
* @return a GIF ImageWriter object
|
* @return a GIF ImageWriter object
|
||||||
* @throws IIOException if no GIF image writers are returned
|
* @throws IIOException if no GIF image writers are returned
|
||||||
|
@ -120,21 +102,17 @@ public class GifSequenceWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an existing child node, or creates and returns a new child node (if
|
* Returns an existing child node, or creates and returns a new child node (if the requested node
|
||||||
* the requested node does not exist).
|
* does not exist).
|
||||||
*
|
*
|
||||||
* @param rootNode the <tt>IIOMetadataNode</tt> to search for the child node.
|
* @param rootNode the <tt>IIOMetadataNode</tt> to search for the child node.
|
||||||
* @param nodeName the name of 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.
|
* @return the child node, if found or a new node created with the given name.
|
||||||
*/
|
*/
|
||||||
private static IIOMetadataNode getNode(
|
private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName) {
|
||||||
IIOMetadataNode rootNode,
|
|
||||||
String nodeName) {
|
|
||||||
int nNodes = rootNode.getLength();
|
int nNodes = rootNode.getLength();
|
||||||
for (int i = 0; i < nNodes; i++) {
|
for (int i = 0; i < nNodes; i++) {
|
||||||
if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName)
|
if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0) {
|
||||||
== 0) {
|
|
||||||
return ((IIOMetadataNode) rootNode.item(i));
|
return ((IIOMetadataNode) rootNode.item(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,10 @@ import java.awt.*;
|
||||||
public class HelperFunctions {
|
public class HelperFunctions {
|
||||||
|
|
||||||
public static void setRenderingHints(Graphics2D g2d) {
|
public static void setRenderingHints(Graphics2D g2d) {
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
g2d.setRenderingHint(
|
||||||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
|
g2d.setRenderingHint(
|
||||||
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String randomString(int n) {
|
public static String randomString(int n) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,16 +1,11 @@
|
||||||
package lc
|
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.core.{Captcha, CaptchaProviders}
|
||||||
import lc.server.Server
|
import lc.server.Server
|
||||||
import lc.background.BackgroundTask
|
import lc.background.BackgroundTask
|
||||||
|
|
||||||
|
|
||||||
object LCFramework {
|
object LCFramework {
|
||||||
def main(args: scala.Array[String]) {
|
def main(args: scala.Array[String]): Unit = {
|
||||||
val captcha = new Captcha()
|
val captcha = new Captcha()
|
||||||
val server = new Server(8888, captcha)
|
val server = new Server(8888, captcha)
|
||||||
val backgroudTask = new BackgroundTask(captcha, 10)
|
val backgroudTask = new BackgroundTask(captcha, 10)
|
||||||
|
@ -20,9 +15,10 @@ object LCFramework{
|
||||||
}
|
}
|
||||||
|
|
||||||
object MakeSamples {
|
object MakeSamples {
|
||||||
def main(args: scala.Array[String]) {
|
def main(args: scala.Array[String]): Unit = {
|
||||||
val samples = CaptchaProviders.generateChallengeSamples()
|
val samples = CaptchaProviders.generateChallengeSamples()
|
||||||
samples.foreach {case (key, sample) =>
|
samples.foreach {
|
||||||
|
case (key, sample) =>
|
||||||
val extensionMap = Map("image/png" -> "png", "image/gif" -> "gif")
|
val extensionMap = Map("image/png" -> "png", "image/gif" -> "gif")
|
||||||
println(key + ": " + sample)
|
println(key + ": " + sample)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
|
||||||
import lc.core.Captcha
|
import lc.core.Captcha
|
||||||
import lc.core.{Parameters, Size}
|
import lc.core.{Parameters, Size}
|
||||||
|
|
||||||
|
|
||||||
class BackgroundTask(captcha: Captcha, throttle: Int) {
|
class BackgroundTask(captcha: Captcha, throttle: Int) {
|
||||||
|
|
||||||
private val task = new Runnable {
|
private val task = new Runnable {
|
||||||
|
@ -32,7 +31,7 @@ class BackgroundTask(captcha: Captcha, throttle: Int) {
|
||||||
|
|
||||||
def beginThread(delay: Int): Unit = {
|
def beginThread(delay: Int): Unit = {
|
||||||
val ex = new ScheduledThreadPoolExecutor(1)
|
val ex = new ScheduledThreadPoolExecutor(1)
|
||||||
val thread = ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
|
ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,7 +8,6 @@ import java.awt.Color
|
||||||
import lc.captchas.interfaces.ChallengeProvider
|
import lc.captchas.interfaces.ChallengeProvider
|
||||||
import lc.captchas.interfaces.Challenge
|
import lc.captchas.interfaces.Challenge
|
||||||
|
|
||||||
|
|
||||||
class FilterChallenge extends ChallengeProvider {
|
class FilterChallenge extends ChallengeProvider {
|
||||||
def getId = "FilterChallenge"
|
def getId = "FilterChallenge"
|
||||||
def returnChallenge(): Challenge = {
|
def returnChallenge(): Challenge = {
|
||||||
|
@ -62,4 +61,3 @@ class FilterType2 extends FilterType {
|
||||||
image
|
image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,17 +4,17 @@ import java.io.File
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
import scala.collection.mutable.Map
|
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.image.BufferedImage
|
||||||
import java.awt.{Graphics2D,Color}
|
import java.awt.Color
|
||||||
import lc.captchas.interfaces.ChallengeProvider
|
import lc.captchas.interfaces.ChallengeProvider
|
||||||
import lc.captchas.interfaces.Challenge
|
import lc.captchas.interfaces.Challenge
|
||||||
|
|
||||||
class LabelCaptcha extends ChallengeProvider {
|
class LabelCaptcha extends ChallengeProvider {
|
||||||
private var knownFiles = new File("known").list.toList
|
private var knownFiles = new File("known").list.toList
|
||||||
private var unknownFiles = new File("unknown").list.toList
|
private var unknownFiles = new File("unknown").list.toList
|
||||||
private var unknownAnswers = Map[String, Map[String, Int]]()
|
private val unknownAnswers = Map[String, Map[String, Int]]()
|
||||||
private var total = Map[String, Int]()
|
private val total = Map[String, Int]()
|
||||||
|
|
||||||
for (file <- unknownFiles) {
|
for (file <- unknownFiles) {
|
||||||
unknownAnswers += file -> Map[String, Int]()
|
unknownAnswers += file -> Map[String, Int]()
|
||||||
|
@ -23,15 +23,15 @@ class LabelCaptcha extends ChallengeProvider {
|
||||||
|
|
||||||
def getId = "LabelCaptcha"
|
def getId = "LabelCaptcha"
|
||||||
|
|
||||||
def returnChallenge(): Challenge = synchronized {
|
def returnChallenge(): Challenge =
|
||||||
|
synchronized {
|
||||||
val r = scala.util.Random.nextInt(knownFiles.length)
|
val r = scala.util.Random.nextInt(knownFiles.length)
|
||||||
val s = scala.util.Random.nextInt(unknownFiles.length)
|
val s = scala.util.Random.nextInt(unknownFiles.length)
|
||||||
val knownImageFile = knownFiles(r)
|
val knownImageFile = knownFiles(r)
|
||||||
val unknownImageFile = unknownFiles(s)
|
val unknownImageFile = unknownFiles(s)
|
||||||
val ip = new ImagePair(knownImageFile, unknownImageFile)
|
|
||||||
|
|
||||||
var knownImage = ImageIO.read(new File("known/"+knownImageFile))
|
val knownImage = ImageIO.read(new File("known/" + knownImageFile))
|
||||||
var unknownImage = ImageIO.read(new File("unknown/"+unknownImageFile))
|
val unknownImage = ImageIO.read(new File("unknown/" + unknownImageFile))
|
||||||
val mergedImage = merge(knownImage, unknownImage)
|
val mergedImage = merge(knownImage, unknownImage)
|
||||||
|
|
||||||
val token = encrypt(knownImageFile + "," + unknownImageFile)
|
val token = encrypt(knownImageFile + "," + unknownImageFile)
|
||||||
|
@ -55,7 +55,8 @@ class LabelCaptcha extends ChallengeProvider {
|
||||||
finalImage
|
finalImage
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkAnswer(token: String, input: String): Boolean = synchronized {
|
def checkAnswer(token: String, input: String): Boolean =
|
||||||
|
synchronized {
|
||||||
val parts = decrypt(token).split(",")
|
val parts = decrypt(token).split(",")
|
||||||
val knownImage = parts(0)
|
val knownImage = parts(0)
|
||||||
val unknownImage = parts(1)
|
val unknownImage = parts(1)
|
||||||
|
@ -73,7 +74,11 @@ class LabelCaptcha extends ChallengeProvider {
|
||||||
if (total(unknownFile) >= 3) {
|
if (total(unknownFile) >= 3) {
|
||||||
if ((unknownAnswers(unknownFile)(userAnswer(1)) / total(unknownFile)) >= 0.9) {
|
if ((unknownAnswers(unknownFile)(userAnswer(1)) / total(unknownFile)) >= 0.9) {
|
||||||
unknownAnswers -= unknownFile
|
unknownAnswers -= unknownFile
|
||||||
Files.move(new File("unknown/"+unknownFile).toPath, new File("known/"+userAnswer(1)+".png").toPath, StandardCopyOption.REPLACE_EXISTING)
|
Files.move(
|
||||||
|
new File("unknown/" + unknownFile).toPath,
|
||||||
|
new File("known/" + userAnswer(1) + ".png").toPath,
|
||||||
|
StandardCopyOption.REPLACE_EXISTING
|
||||||
|
)
|
||||||
knownFiles = new File("known").list.toList
|
knownFiles = new File("known").list.toList
|
||||||
unknownFiles = new File("unknown").list.toList
|
unknownFiles = new File("unknown").list.toList
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,7 @@ import java.awt.RenderingHints
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.font.TextAttribute
|
import java.awt.font.TextAttribute
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream;
|
||||||
import javax.imageio.ImageIO
|
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
|
||||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
||||||
import lc.captchas.interfaces.ChallengeProvider
|
import lc.captchas.interfaces.ChallengeProvider
|
||||||
import lc.captchas.interfaces.Challenge
|
import lc.captchas.interfaces.Challenge
|
||||||
|
@ -19,7 +17,7 @@ class Drop {
|
||||||
var yOffset = 0
|
var yOffset = 0
|
||||||
var color = 0
|
var color = 0
|
||||||
var colorChange = 10
|
var colorChange = 10
|
||||||
def mkColor = {
|
def mkColor: Color = {
|
||||||
new Color(color, color, math.min(200, color + 100))
|
new Color(color, color, math.min(200, color + 100))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,8 +58,11 @@ class RainDropsCP extends ChallengeProvider {
|
||||||
d.colorChange *= -1
|
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 baseFont = new Font(Font.MONOSPACED, Font.BOLD, 80)
|
||||||
val attributes = new java.util.HashMap[TextAttribute, Object]()
|
val attributes = new java.util.HashMap[TextAttribute, Object]()
|
||||||
|
@ -72,7 +73,7 @@ class RainDropsCP extends ChallengeProvider {
|
||||||
val baos = new ByteArrayOutputStream();
|
val baos = new ByteArrayOutputStream();
|
||||||
val ios = new MemoryCacheImageOutputStream(baos);
|
val ios = new MemoryCacheImageOutputStream(baos);
|
||||||
val writer = new GifSequenceWriter(ios, imgType, 60, true);
|
val writer = new GifSequenceWriter(ios, imgType, 60, true);
|
||||||
for(i <- 0 until 60){
|
for (_ <- 0 until 60) {
|
||||||
// val yOffset = 5+r.nextInt(5)
|
// val yOffset = 5+r.nextInt(5)
|
||||||
val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
|
val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
|
||||||
val g = canvas.createGraphics()
|
val g = canvas.createGraphics()
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package lc.core
|
package lc.core
|
||||||
|
|
||||||
import org.json4s.JsonAST.JValue
|
|
||||||
import java.sql.{Blob, ResultSet}
|
import java.sql.{Blob, ResultSet}
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
@ -23,7 +22,8 @@ class Captcha {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
image
|
image
|
||||||
} catch { case e: Exception =>
|
} catch {
|
||||||
|
case e: Exception =>
|
||||||
println(e)
|
println(e)
|
||||||
image
|
image
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,8 @@ class Captcha {
|
||||||
updateAttemptedPstmt.setString(1, uuid)
|
updateAttemptedPstmt.setString(1, uuid)
|
||||||
updateAttemptedPstmt.executeUpdate()
|
updateAttemptedPstmt.executeUpdate()
|
||||||
Id(uuid)
|
Id(uuid)
|
||||||
} catch {case e: Exception =>
|
} catch {
|
||||||
|
case e: Exception =>
|
||||||
println(e)
|
println(e)
|
||||||
Id(getUUID(-1))
|
Id(getUUID(-1))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package lc.core
|
||||||
|
|
||||||
import lc.captchas._
|
import lc.captchas._
|
||||||
import lc.captchas.interfaces.ChallengeProvider
|
import lc.captchas.interfaces.ChallengeProvider
|
||||||
|
import lc.captchas.interfaces.Challenge
|
||||||
|
|
||||||
object CaptchaProviders {
|
object CaptchaProviders {
|
||||||
private val providers = Map(
|
private val providers = Map(
|
||||||
|
@ -9,12 +10,13 @@ object CaptchaProviders {
|
||||||
//"FontFunCaptcha" -> new FontFunCaptcha,
|
//"FontFunCaptcha" -> new FontFunCaptcha,
|
||||||
"GifCaptcha" -> new GifCaptcha,
|
"GifCaptcha" -> new GifCaptcha,
|
||||||
"ShadowTextCaptcha" -> new ShadowTextCaptcha,
|
"ShadowTextCaptcha" -> new ShadowTextCaptcha,
|
||||||
"RainDropsCaptcha" -> new RainDropsCP,
|
"RainDropsCaptcha" -> new RainDropsCP
|
||||||
//"LabelCaptcha" -> new LabelCaptcha
|
//"LabelCaptcha" -> new LabelCaptcha
|
||||||
)
|
)
|
||||||
|
|
||||||
def generateChallengeSamples() = {
|
def generateChallengeSamples(): Map[String, Challenge] = {
|
||||||
providers.map {case (key, provider) =>
|
providers.map {
|
||||||
|
case (key, provider) =>
|
||||||
(key, provider.returnChallenge())
|
(key, provider.returnChallenge())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +24,8 @@ object CaptchaProviders {
|
||||||
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 val random = new scala.util.Random(seed)
|
||||||
|
|
||||||
private def getNextRandomInt(max: Int) = random.synchronized {
|
private def getNextRandomInt(max: Int) =
|
||||||
|
random.synchronized {
|
||||||
random.nextInt(max)
|
random.nextInt(max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,30 +2,108 @@ package lc.database
|
||||||
|
|
||||||
import lc.database.DBConn
|
import lc.database.DBConn
|
||||||
import java.sql.Statement
|
import java.sql.Statement
|
||||||
|
import java.sql.PreparedStatement
|
||||||
|
|
||||||
class Statements(dbConn: DBConn) {
|
class Statements(dbConn: DBConn) {
|
||||||
|
|
||||||
private val stmt = dbConn.getStatement()
|
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(
|
||||||
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)")
|
"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 insertPstmt: PreparedStatement = dbConn.con.prepareStatement(
|
||||||
val mapPstmt = dbConn.con.prepareStatement("INSERT INTO mapId(uuid, token, lastServed) VALUES (?, ?, CURRENT_TIMESTAMP)")
|
"INSERT INTO " +
|
||||||
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 = ?")
|
"challenge(id, secret, provider, contentType, image) " +
|
||||||
val imagePstmt = dbConn.con.prepareStatement("SELECT image FROM challenge c, mapId m WHERE c.token=m.token AND m.uuid = ?")
|
"VALUES (?, ?, ?, ?, ?)",
|
||||||
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 = ?)")
|
Statement.RETURN_GENERATED_KEYS
|
||||||
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 mapPstmt: PreparedStatement =
|
||||||
val mapIdGCPstmt = dbConn.con.prepareStatement("DELETE FROM mapId WHERE DATEDIFF(MINUTE, CURRENT_TIMESTAMP, DATEADD(MINUTE, 1, lastServed)) < 0")
|
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 {
|
object Statements {
|
||||||
private val dbConn: DBConn = new DBConn()
|
private val dbConn: DBConn = new DBConn()
|
||||||
val tlStmts = ThreadLocal.withInitial(() => new Statements(dbConn))
|
val tlStmts: ThreadLocal[Statements] = ThreadLocal.withInitial(() => new Statements(dbConn))
|
||||||
}
|
}
|
|
@ -7,14 +7,15 @@ import lc.core.Captcha
|
||||||
import lc.core.{Parameters, Id, Answer}
|
import lc.core.{Parameters, Id, Answer}
|
||||||
import lc.server.HTTPServer
|
import lc.server.HTTPServer
|
||||||
|
|
||||||
|
|
||||||
class Server(port: Int, captcha: Captcha) {
|
class Server(port: Int, captcha: Captcha) {
|
||||||
val server = new HTTPServer(port)
|
val server = new HTTPServer(port)
|
||||||
val host = server.getVirtualHost(null)
|
val host: HTTPServer.VirtualHost = server.getVirtualHost(null)
|
||||||
|
|
||||||
implicit val formats = DefaultFormats
|
implicit val formats: DefaultFormats.type = DefaultFormats
|
||||||
|
|
||||||
host.addContext("/v1/captcha",(req, resp) => {
|
host.addContext(
|
||||||
|
"/v1/captcha",
|
||||||
|
(req, resp) => {
|
||||||
val body = req.getJson()
|
val body = req.getJson()
|
||||||
val json = parse(body)
|
val json = parse(body)
|
||||||
val param = json.extract[Parameters]
|
val param = json.extract[Parameters]
|
||||||
|
@ -22,18 +23,26 @@ class Server(port: Int, captcha: Captcha){
|
||||||
resp.getHeaders().add("Content-Type", "application/json")
|
resp.getHeaders().add("Content-Type", "application/json")
|
||||||
resp.send(200, write(id))
|
resp.send(200, write(id))
|
||||||
0
|
0
|
||||||
},"POST")
|
},
|
||||||
|
"POST"
|
||||||
|
)
|
||||||
|
|
||||||
host.addContext("/v1/media",(req, resp) => {
|
host.addContext(
|
||||||
|
"/v1/media",
|
||||||
|
(req, resp) => {
|
||||||
val params = req.getParams()
|
val params = req.getParams()
|
||||||
val id = Id(params.get("id"))
|
val id = Id(params.get("id"))
|
||||||
val image = captcha.getCaptcha(id)
|
val image = captcha.getCaptcha(id)
|
||||||
resp.getHeaders().add("Content-Type", "image/png")
|
resp.getHeaders().add("Content-Type", "image/png")
|
||||||
resp.send(200, image)
|
resp.send(200, image)
|
||||||
0
|
0
|
||||||
},"GET")
|
},
|
||||||
|
"GET"
|
||||||
|
)
|
||||||
|
|
||||||
host.addContext("/v1/answer",(req, resp) => {
|
host.addContext(
|
||||||
|
"/v1/answer",
|
||||||
|
(req, resp) => {
|
||||||
val body = req.getJson()
|
val body = req.getJson()
|
||||||
val json = parse(body)
|
val json = parse(body)
|
||||||
val answer = json.extract[Answer]
|
val answer = json.extract[Answer]
|
||||||
|
@ -41,8 +50,9 @@ class Server(port: Int, captcha: Captcha){
|
||||||
resp.getHeaders().add("Content-Type", "application/json")
|
resp.getHeaders().add("Content-Type", "application/json")
|
||||||
resp.send(200, write(result))
|
resp.send(200, write(result))
|
||||||
0
|
0
|
||||||
},"POST")
|
},
|
||||||
|
"POST"
|
||||||
|
)
|
||||||
|
|
||||||
def start(): Unit = {
|
def start(): Unit = {
|
||||||
println("Starting server on port:" + port)
|
println("Starting server on port:" + port)
|
||||||
|
|
Loading…
Reference in New Issue