All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.shredzone.commons.captcha.impl.DefaultCaptchaService Maven / Gradle / Ivy

/*
 * Shredzone Commons
 *
 * Copyright (C) 2012 Richard "Shred" Körber
 *   http://commons.shredzone.org
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this program.  If not, see .
 */
package org.shredzone.commons.captcha.impl;

import java.awt.image.BufferedImage;
import java.util.Random;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

import org.shredzone.commons.captcha.CaptchaGenerator;
import org.shredzone.commons.captcha.CaptchaService;
import org.springframework.stereotype.Component;

/**
 * Default implementation of {@link CaptchaService}.
 *
 * @author Richard "Shred" Körber
 */
@Component("captchaService")
public class DefaultCaptchaService implements CaptchaService {

    private static final String CHARSET = "ABCDEFGHJLMNOPQRSTUWZ";
    private static final int NUMBER_OF_CHARS = 5;
    private static final String CAPTCHA_NAME = "captcha.position";
    private static final String LASTCLICK_NAME = "captcha.lastclick";

    private final Random rnd = new Random();

    @Resource
    private CaptchaGenerator captchaGenerator;

    @Override
    public BufferedImage createCaptcha(HttpSession session) {
        int captchaPos = computeCaptchaPosition(session);
        return captchaGenerator.createCaptcha(computeChars(captchaPos));
    }

    @Override
    public boolean isValidCaptcha(HttpSession session, int x, int y) {
        Integer pos = getCaptchaPosition(session);

        if (pos == null) {
            // There was no captcha generated yet, so the answer is always false.
            return false;
        }

        int cw = captchaGenerator.getWidth();
        int ch = captchaGenerator.getHeight();

        if (x < 0 || y < 0 || x >= cw || y >= ch) {
            // The click was outside of the captcha, so the answer is always false.
            return false;
        }

        if (x == 0 && y == 0) {
            // Ignore the simplest possible coordinate. No human being would click
            // there... ;-)
            return false;
        }

        int boxWidth = cw / NUMBER_OF_CHARS;
        int answer = x / boxWidth;

        setLastclickPosition(session, answer);

        return answer == pos;
    }

    /**
     * Compute a random set of characters, with exactly one 'X' at the given position.
     *
     * @param pos
     *            position of the 'X'
     * @return captcha text
     */
    private char[] computeChars(int pos) {
        char[] chars = new char[NUMBER_OF_CHARS];

        for (int ix = 0; ix < NUMBER_OF_CHARS; ix++) {
            if (ix == pos) {
                chars[ix] = 'X';
            } else {
                chars[ix] = CHARSET.charAt(rnd.nextInt(CHARSET.length()));
            }
        }

        return chars;
    }

    /**
     * Computes the position of the correct captcha answer.
     * 

* Makes sure the new correct answer is never at the same position as the previous * click. This will keep spammers from just clicking at the same position until they * gave the right answer by lucky chance. * * @param session * {@link HttpSession} with captcha data * @return position of the correct answer */ private int computeCaptchaPosition(HttpSession session) { int newPos; Integer oldPos = getLastclickPosition(session); if (oldPos != null) { // Make sure newPos is always != oldPos newPos = rnd.nextInt(NUMBER_OF_CHARS - 1); if (newPos >= oldPos) newPos++; } else { newPos = rnd.nextInt(NUMBER_OF_CHARS); } setCaptchaPosition(session, newPos); return newPos; } /** * Gets the last captcha position from the session. * * @param session * {@link HttpSession} * @return the last captcha position, or {@code null} if there is none yet */ private Integer getCaptchaPosition(HttpSession session) { return (Integer) session.getAttribute(CAPTCHA_NAME); } /** * Sets the captcha position. * * @param session * {@link HttpSession} * @param pos * captcha position to store */ private void setCaptchaPosition(HttpSession session, int pos) { session.setAttribute(CAPTCHA_NAME, pos); } /** * Gets the position of the last click. * * @param session * {@link HttpSession} * @return position of the last click, or {@code null} if the user did not click yet */ private Integer getLastclickPosition(HttpSession session) { return (Integer) session.getAttribute(LASTCLICK_NAME); } /** * Sets the position of the last click. * * @param session * {@link HttpSession} * @param pos * position of the last click */ private void setLastclickPosition(HttpSession session, int pos) { session.setAttribute(LASTCLICK_NAME, pos); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy