Java CAPTCHA w/ JCaptcha

When looking for a good Java CAPTCHA library, many people just suggested using ReCAPTCHA from Google.  A few online posts discouraged using ReCAPTCHA because it has shown swear words at times and has the possibility of being down which would also bring your own site down.  I like my Java Web Apps to have as few dependencies as possible, so I looked for a self-contained solution.  JCaptcha had everything I needed and was easy to integrate.  It was nice to be able to customize what kind of CAPTCHA words to use and what they would look like.

First off, add the dependency with Maven or as a Jar:

<dependency>
     <groupId>com.octo.captcha</groupId>
     <artifactId>jcaptcha</artifactId>
     <version>1.0</version>
 </dependency>

Add a custom engine to make it look how you want:

public class CustomCaptchaEngine extends ListImageCaptchaEngine {

     protected void buildInitialFactories() {

        com.jhlabs.image.WaterFilter water = new com.jhlabs.image.WaterFilter();
        water.setAmplitude(2d);
        water.setAntialias(true);
        water.setPhase(20d);
        water.setWavelength(70d);

        ImageDeformation backDef = new ImageDeformationByFilters(new ImageFilter[]{});
        ImageDeformation textDef = new ImageDeformationByFilters(new ImageFilter[]{});
        ImageDeformation postDef = new ImageDeformationByFilters(new ImageFilter[]{water});

        com.octo.captcha.component.word.wordgenerator.WordGenerator dictionaryWords = new com.octo.captcha.component.word.wordgenerator.ComposeDictionaryWordGenerator(
        new com.octo.captcha.component.word.FileDictionary("toddlist"));

        TextPaster randomPaster = new DecoratedRandomTextPaster(new Integer(6), new Integer(7), new SingleColorGenerator(Color.black), new TextDecorator[]{
        new BaffleTextDecorator(new Integer(1), Color.white)});
        BackgroundGenerator back = new UniColorBackgroundGenerator(new Integer(200), new Integer(75), Color.white);

        FontGenerator shearedFont = new RandomFontGenerator(new Integer(30), new Integer(35));

        com.octo.captcha.component.image.wordtoimage.WordToImage word2image;
        word2image = new DeformedComposedWordToImage(shearedFont, back, randomPaster, backDef, textDef, postDef);

        this.addFactory(new com.octo.captcha.image.gimpy.GimpyFactory(dictionaryWords, word2image));
    }
}

Then add an endpoint to serve up a BufferedImage.  I used Jersey for this:

public static ImageCaptchaService captchaService = new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), new CustomCaptchaEngine(), 180, 100000, 75000);

@Path("captcha.jpg")
@Produces("image/jpeg")
@GET
public Response lookupCategorization(@Context HttpServletRequest httpRequest) {

      BufferedImage bi = captchaService.getImageChallengeForID(httpRequest.getSession(true).getId());

 return Response.ok(bi)
      .header("Expires", 0)
      .header("Cache-Control", "no-store, no-cache, must-revalidate")
      .header("Pragma", "no-cache")
      .build();
 }

Add a validation method:

public static boolean validateResponse(HttpServletRequest request, String userCaptchaResponse) {
     if (request.getSession(false) == null) {
         return false;
     }
     boolean validResponse = false;
     try {
        validResponse = captchaService.validateResponseForID(request.getSession().getId(), userCaptchaResponse);
     } catch (CaptchaServiceException e) {}
     return validResponse;
}

Add a validation endpoint:

@Path("validate")
@Produces(MediaType.APPLICATION_JSON)
@POST
public Response validate(@Context HttpServletRequest httpRequest, @FormParam("captcha") String captcha) {

    if(validateResponse(httpRequest, captcha)) {
        ...
    } else {
        ...
    }
}

Add HTML form fields for CAPTCHA:

  <img class="captchaimage" src="captcha.jpg" />
  <input type="text" class="captchaText" autocomplete="off" name="captcha" /> 
  <a href="javascript: void(0);" onClick='loadNewCaptchaImage()'>Reload</a>

Add jQuery JavaScript to load a new image for users:

loadNewCaptchaImage = function () {
      $("img.captchaimage").attr("src", "captcha.jpg" + "?" + (new Date()).getTime()); 
      $('input.captchaText').val('').focus();
}

You can always make the captcha more difficult by adding more font variations, text effects, and background noise. Here are some examples of what you can do to make it difficult for bots to crack the captcha: https://jcaptcha.atlassian.net/wiki/display/general/Samples+tests  Just don’t frustrate your users by making it near impossible for them to figure out what the CAPTCHA says.

Advertisements

Geolocating and Mapping Points with Nominatim and Leaflet

I wanted to add a map feature to http://www.shelfreliancepro.com but had no budget to pay for map apis or libraries. The solution I found was http://nominatim.openstreetmap.org and http://leafletjs.com/.  Nominatim allows you to do all kind of geo-locating, address queries, and location queries.  Leaflet is a simple map interface for plotting points.  Leaflet works very well on mobile devices.

When users would update or add an address to the system, I would mark the address so I knew it needed to have it’s latitude and longitude updated via nominatim.  I run a scheduled task every 10 minutes to find addresses that need an update and update them.

Here’s how it turned out:

map

Generate HTML elements with Java

I was looking for a ASP.NET equivalent in Java for generating HTML elements.  I found a nice Apache package to do this.  It is called the Element Construction Set.  http://jakarta.apache.org/ecs/index.html

Javadocs for the package can be found here: http://www.docjar.org/docs/api/org/apache/ecs/html/

This will greatly simplify generating HTML, particularly in a struts tag library or anywhere not in a jsp.

Example usage from http://jakarta.apache.org/ecs/index.html:

Document doc = (Document) new Document()
              .appendTitle("Demo")
              .appendBody(new H1("Demo Header"))
              .appendBody(new H3("Sub Header:"))
              .appendBody(new Font().setSize("+1")
                         .setColor(HtmlColor.WHITE)
                         .setFace("Times")
                         .addElement("The big dog & the little cat chased each other."));
out.println(doc.toString());
// or write to the outputstream directly
output(out);

Generates the equivalent to:

out.println("<HTML>");
out.println("<HEAD><TITLE>Demo<TITLE><HEAD>");
out.println("<BODY>");
out.println("<H1>Demo Header<H1>");
out.println("<H3>Sub Header:<H3>");
out.println("<FONT SIZE=\"+1\" FACE=\"Times\" COLOR=\"#FFFFFF">);
out.println("The big dog &amp; the little cat chased each other.");
out.println("<FONT>");
out.println("<BODY>");
out.println("<HTML>");