package org.jboss.seam.captcha; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.Serializable; import java.util.Random; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.contexts.Contexts; /** * Default CAPTCHA algorithm, a simple addition problem. May be * extended and customized. * * @author Gavin King * */ @Name("org.jboss.seam.captcha.captcha") @Scope(ScopeType.SESSION) @Install(precedence=Install.BUILT_IN) @BypassInterceptors public class Captcha implements Serializable { private static Random random = new Random( System.currentTimeMillis() ); private String correctResponse; private String challenge; private String response; /** * Initialize the challenge and correct response. * May be overridden and customized by a subclass. */ @Create public void init() { int x = random.nextInt(50); int y = random.nextInt(50); setCorrectResponse( Integer.toString( x + y ) ); setChallenge( Integer.toString(x) + " + " + Integer.toString(y) + " =" ); } /** * Set the challenge question */ protected void setChallenge(String challenge) { this.challenge = challenge; } /** * Get the challenge question */ protected String getChallenge() { return challenge; } /** * Set the correct response */ protected void setCorrectResponse(String correctResponse) { this.correctResponse = correctResponse; } /** * Validate that the entered response is the correct * response */ public boolean validateResponse(String response) { boolean valid = response!=null && correctResponse!=null && response.trim().equals(correctResponse); if (!valid) { init(); } return valid; } @CaptchaResponse public String getResponse() { return response; } public void setResponse(String input) { this.response = input; } /** * Render the challenge question as an image. * May be overridden by subclasses to achieve * a stronger CAPTCHA. */ public BufferedImage renderChallenge() { BufferedImage challenge = new BufferedImage(70, 20, BufferedImage.TYPE_BYTE_GRAY); Graphics graphics = challenge.getGraphics(); graphics.setColor( getChallengeBackgroundColor() ); graphics.fillRect(0, 0, getChallengeImageWidth(), 20); graphics.setColor( getChallengeTextColor() ); graphics.drawString( getChallenge(), 5, 15 ); return challenge; } /** * May be overridden by subclasses * @return the width, in pixels, of the challenge question */ protected int getChallengeImageWidth() { return 70; } /** * May be overridden by subclasses * @return the background color of the challenge image */ protected Color getChallengeBackgroundColor() { return Color.WHITE; } /** * May be overridden by subclasses * @return @return the foreground color of the challenge image */ protected Color getChallengeTextColor() { return Color.BLACK; } public static Captcha instance() { if ( !Contexts.isSessionContextActive() ) { throw new IllegalStateException("No session context active"); } return (Captcha) Component.getInstance(Captcha.class, ScopeType.SESSION); } }