package com.avoka.lib.click.control; import java.util.Properties; import net.tanesha.recaptcha.ReCaptcha; import net.tanesha.recaptcha.ReCaptchaFactory; import net.tanesha.recaptcha.ReCaptchaImpl; import net.tanesha.recaptcha.ReCaptchaResponse; import org.apache.click.control.AbstractControl; import org.apache.click.control.Field; import org.apache.click.util.HtmlStringBuffer; import org.apache.commons.lang.StringUtils; /** * Provides an implementation of a ReCaptcha fields for a Click form. *

* ReCaptcha is used by a wide variety of sites such as Facebook, TicketMaster, * Twitter and StumbleUpon that want to restrict the submission to humans. CAPTCHA * stands for Completely Automated Public Turing test to tell Computers and Humans Apart *

* It is useful for the following types of forms: *

* ReCaptcha provides a free service, it uses the responses to the challenges, to digitize books. * To use ReCaptcha an individual or company must first register to get a Private and Public key. This * For more information on ReCaptcha visit http://wiki.recaptcha.net *

* The design allows for only one ReCaptchaField per form. This is because the rendered html will have * 2 constant forms fields see RECAPTCHA_CHALLENGE_FIELD and RECAPTCHA_RESPONSE_FIELD below; *

* This class uses the ReCaptcha java lib recaptcha4j-0.0.7.jar downloaded from http://wiki.recaptcha.net *

* TODO: Change field error message, that is displayed if a validation error occurs, to come from a * resource bundle. Add more themes names as constants http://wiki.recaptcha.net/index.php/Overview *

* @author Larry Bunton */ public class ReCaptchaField extends Field { private static final String RECAPTCHA_RESPONSE_FIELD = "recaptcha_response_field"; private static final String RECAPTCHA_CHALLENGE_FIELD = "recaptcha_challenge_field"; private static final long serialVersionUID = 1L; public static final String THEME_CLEAN = "clean"; private String publicKey; private String privateKey; Properties options = new Properties(); /** * @param name the field name * @param publicKey the public key sent by ReCaptcha when you register. * @param privateKey the private key sent by ReCaptcha on registring * @param theme name of ReCaptcha theme as per http://wiki.recaptcha.net/index.php/Overview */ public ReCaptchaField(String name, String publicKey, String privateKey, String theme) { super(name); this.publicKey = publicKey; this.privateKey = privateKey; if (StringUtils.isNotEmpty(theme)) { options.setProperty(ReCaptchaImpl.PROPERTY_THEME, theme); } } /** * Render the HTML representation of the ReCaptchaField. * * @see #toString() * * @param buffer the specified buffer to render the control's output to */ public void render(HtmlStringBuffer buffer) { ReCaptcha recaptcha = ReCaptchaFactory.newReCaptcha(publicKey, privateKey, false); String output = recaptcha.createRecaptchaHtml(null, options); buffer.append(output); } @Override public boolean onProcess() { bindRequestValue(); if (getValidate()) { validate(); } dispatchActionEvent(); return true; } /** * Validate the TextField request submission. *

* A field error message is displayed if a validation error occurs. */ @Override public void validate() { setError(null); String remoteAddr = getContext().getRequest().getRemoteAddr(); ReCaptchaImpl reCaptcha = new ReCaptchaImpl(); reCaptcha.setPrivateKey(privateKey); String challenge = getContext().getRequestParameter(RECAPTCHA_CHALLENGE_FIELD); String userResponse = getContext().getRequestParameter(RECAPTCHA_RESPONSE_FIELD); ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challenge, userResponse); if (!reCaptchaResponse.isValid()) { setError("Incorrect ReCAPTCHA Response, please try again."); } } /** * Return the captcha fields html tag: input. * * @see AbstractControl#getTag() * * @return this controls html tag */ public String getTag() { return "captcha"; } }