package er.captcha;
import java.util.Properties;
import net.tanesha.recaptcha.ReCaptcha;
import net.tanesha.recaptcha.ReCaptchaFactory;
import net.tanesha.recaptcha.ReCaptchaResponse;
import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WORequest;
import com.webobjects.foundation.NSValidation;
import er.extensions.appserver.ERXRequest;
import er.extensions.components.ERXNonSynchronizingComponent;
import er.extensions.components.ERXSimpleSpamCheck;
import er.extensions.foundation.ERXProperties;
/**
* <p>
* ERReCaptcha uses the ReCaptcha system for identifying humans vs spambots. For more information, see
* http://recaptcha.net. To use this component, you must sign up for a recaptcha account and set the system properties
* "er.captcha.recaptcha.publicKey" and "er.captcha.recaptcha.privateKey" accordingly.
* </p>
* <p>
* This component will both set a "valid" binding to true/false based on the check as well as call a
* validationFailedWithException when the check fails.
* </p>
*
* @binding secure sets whether or not the recaptcha URL should be secure (defaults to using the request's protocol)
* @binding theme the recaptcha theme to use
* @binding valid will be set to true or false depending on whether the check passed
* @binding errorMessage the error message to display for an incorrect-captcha-sol error
* @property er.captcha.recaptcha.publicKey your ReCaptcha public key
* @property er.captcha.recaptcha.privateKey your ReCaptcha private key
*
* @author mschrag
*/
public class ERReCaptcha extends ERXNonSynchronizingComponent {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
/**
* Constructs a new ERReCaptcha component.
*
* @param context
* the context
*/
public ERReCaptcha(WOContext context) {
super(context);
}
/**
* Returns a ReCaptcha object configured with the current settings.
*
* @return a ReCaptcha object configured with the current settings
*/
protected ReCaptcha recaptcha() {
String publicKey = ERXProperties.stringForKey("er.captcha.recaptcha.publicKey");
String privateKey = ERXProperties.stringForKey("er.captcha.recaptcha.privateKey");
if (publicKey == null || privateKey == null) {
throw new IllegalStateException("You have not set 'er.captcha.recaptcha.publicKey' or 'er.captcha.recaptcha.publicKey'. Please go to http://recaptcha.net and sign up for a key.");
}
ReCaptcha recaptcha;
boolean secure = booleanValueForBinding("secure", ERXRequest.isRequestSecure(context().request()));
if (secure) {
recaptcha = ReCaptchaFactory.newSecureReCaptcha(publicKey, privateKey, false);
}
else {
recaptcha = ReCaptchaFactory.newReCaptcha(publicKey, privateKey, false);
}
return recaptcha;
}
/**
* Returns the ReCaptcha HTML chunk to render into the page.
*
* @return the ReCaptcha HTML chunk to render into the page
*/
public String recaptchaHTML() {
Properties props = new Properties();
// props.setProperty("tabindex", null);
String theme = stringValueForBinding("theme");
if (theme != null) {
props.setProperty("theme", theme);
}
String errorMessage = stringValueForBinding("errorMessage");
String html = recaptcha().createRecaptchaHtml(errorMessage, props);
return html;
}
@Override
public void takeValuesFromRequest(WORequest request, WOContext context) {
super.takeValuesFromRequest(request, context);
if (context.wasFormSubmitted()) {
String challenge = request.stringFormValueForKey("recaptcha_challenge_field");
if (challenge == null) {
challenge = "";
}
String response = request.stringFormValueForKey("recaptcha_response_field");
if (response == null) {
response = "";
}
String remoteAddress = request._remoteAddress();
if (remoteAddress == null) {
remoteAddress = WOApplication.application().hostAddress().getHostAddress();
}
ReCaptchaResponse recaptchaResponse = recaptcha().checkAnswer(remoteAddress, challenge, response);
if (!recaptchaResponse.isValid()) {
String errorMessage = recaptchaResponse.getErrorMessage();
if (errorMessage != null && errorMessage.equals("incorrect-captcha-sol")) {
errorMessage = stringValueForBinding("errorMessage");
}
validationFailedWithException(new NSValidation.ValidationException(errorMessage), this, ERXSimpleSpamCheck.SPAM_CHECK_KEY);
setValueForBinding(Boolean.FALSE, "valid");
}
else {
setValueForBinding(Boolean.TRUE, "valid");
}
}
}
}