jspwiki-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ajaqu...@apache.org
Subject svn commit: r896521 - in /incubator/jspwiki/trunk: src/WebContent/WEB-INF/ src/WebContent/WEB-INF/classes/ src/java/org/apache/wiki/action/ src/java/org/apache/wiki/content/inspect/ src/java/org/apache/wiki/ui/stripes/ tests/java/org/apache/wiki/conten...
Date Wed, 06 Jan 2010 16:48:17 GMT
Author: ajaquith
Date: Wed Jan  6 16:47:53 2010
New Revision: 896521

URL: http://svn.apache.org/viewvc?rev=896521&view=rev
Log:
Second of three CAPTCHA checkins. CAPTCHA is now treated as a form validation problem. By default, CAPTCHA is now dynamic, and is displayed only when the content inspector says a form POST contains spam. Added i18n support for Asirra.

Added:
    incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Challenge.java
      - copied, changed from r892689, incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Captcha.java
Removed:
    incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Captcha.java
Modified:
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_de.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_es.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fi.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fr.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_it.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_nl.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_pt_BR.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_ru.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_zh_CN.properties
    incubator/jspwiki/trunk/src/WebContent/WEB-INF/jspwiki.tld
    incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java
    incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/AsirraCaptcha.java
    incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/HandlerInfo.java
    incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamInterceptor.java
    incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamProtect.java
    incubator/jspwiki/trunk/tests/java/org/apache/wiki/content/inspect/AsirraCaptchaTest.java
    incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/HandlerInfoTest.java
    incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/SpamInterceptorTest.java

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources.properties Wed Jan  6 16:47:53 2010
@@ -110,9 +110,7 @@
 markupparser.link.create=Create "{0}"
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=Please correctly identify the cats.
-captcha.description=We believe you may be a robot or a spammer.  Could you please pick out the kittens from the below set of images, so we know you are a normal human being?
 captcha.asirra.please.select=Please select all the cat photos:
-captcha.asirra.adopt.me=Adopt me
 captcha.asirra.a.get.challenge=Request different images.
 captcha.asirra.a.whatsthis=What is this?
 captcha.submit=Submit
@@ -373,3 +371,8 @@
 Outcome.decision.hold=Hold
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=Reassign
+validation.challenge.required=The content you submitted looks like spam. Please complete the challenge below.
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=If you are human, please select all of the cats from the images below.
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=Adopt me

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_de.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_de.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_de.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_de.properties Wed Jan  6 16:47:53 2010
@@ -115,9 +115,7 @@
 markupparser.link.create=Erstelle {0}
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=Bitte wähle die Katzen aus!
-captcha.description=Wir befürchten, du könntest ein Automat oder Spammer sein! Um zu zeigen, dass du ein normales menschliches Geschöpf bist, wähle bitte aus der folgenden Bilderserie alle Katzen aus!
 captcha.asirra.please.select=Bitte wähle alle Katzen aus:
-captcha.asirra.adopt.me=Adoptier' mich!
 captcha.asirra.a.get.challenge=Lade andere Bilder!
 captcha.asirra.a.whatsthis=Was ist das?
 captcha.submit=Weiter
@@ -345,6 +343,10 @@
 Outcome.decision.hold=Zurückstellen
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=Neu zuweisen
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=Wir befürchten, du könntest ein Automat oder Spammer sein! Um zu zeigen, dass du ein normales menschliches Geschöpf bist, wähle bitte aus der folgenden Bilderserie alle Katzen aus!
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=Adoptier' mich!
 # Outdated or superfluous properties since 3.0.0
 
 # folgende Properties sind in der aktuellen 'default en' Datei nicht enthalten

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_es.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_es.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_es.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_es.properties Wed Jan  6 16:47:53 2010
@@ -112,9 +112,7 @@
 markupparser.link.create=Crear "{0}"
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=Por favor, identifica correctamente a los gatos.
-captcha.description=Creemos que eres o bien un robot o bien un spammer.  ¿Podrías por favor seleccionar los gatitos del juego de imágenes inferior, de tal modo que sepamos que eres un ser humano normal?
 captcha.asirra.please.select=Por favor, selecciona todas las fotografías de gatos:
-captcha.asirra.adopt.me=Adóptame
 captcha.asirra.a.get.challenge=Pedir otras imágenes
 captcha.asirra.a.whatsthis=¿Qué es esto?
 captcha.submit=Enviar
@@ -346,3 +344,7 @@
 Outcome.decision.hold=Mantener
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=Reasignar
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=Creemos que eres o bien un robot o bien un spammer.  ¿Podrías por favor seleccionar los gatitos del juego de imágenes inferior, de tal modo que sepamos que eres un ser humano normal?
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=Adóptame

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fi.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fi.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fi.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fi.properties Wed Jan  6 16:47:53 2010
@@ -124,11 +124,7 @@
 install.jsp.security.sec.conf.opt1=JAAS ja servlet-alustan turvajärjestelmä (oletus)
 install.jsp.security.sec.conf.opt2=Servlet-alustan turvajärjestelmä
 install.jsp.security.title=Turvajärjestelmä
-# Captcha.jsp
-
-captcha.asirra.adopt.me=Adoptoi minut
 captcha.asirra.please.select=Ole hyvä ja valitse kaikki kissan kuvat:
-captcha.description=Epäilemme sinua robotiksi tai roskapostittajaksi.  Voisitko ystävällisesti poimia kissan kuvat seuraavista kuvista, jotta tiedämme, että olet hyvä ihminen?
 captcha.js.humancheckcomplete.alert=Ole hyvä ja valitse vain kissojen kuvat.
 captcha.submit=Valmis
 captcha.asirra.a.get.challenge=Hae uudet kuvat
@@ -239,3 +235,7 @@
 Outcome.decision.hold=Laita jonoon
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=Lähetä edelleen
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=Epäilemme sinua robotiksi tai roskapostittajaksi.  Voisitko ystävällisesti poimia kissan kuvat seuraavista kuvista, jotta tiedämme, että olet hyvä ihminen?
+#Captcha.jsp. Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=Adoptoi minut

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fr.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fr.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fr.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_fr.properties Wed Jan  6 16:47:53 2010
@@ -113,9 +113,7 @@
 markupparser.link.create=Créer "{0}"
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=Veuillez identifier correctement les chats.
-captcha.description=Nous avous de bonnes raisons de croire que vous soyez un robot ou un spammer. Pourriez-vous sélectionner les photos de chats parmi celles ci-dessous, pour être sûr que vous soyez un humain ?
 captcha.asirra.please.select=Veuillez sélectionner toutes les photos de chats :
-captcha.asirra.adopt.me=M'adopter
 captcha.asirra.a.get.challenge=Obtenir différentes images.
 captcha.asirra.a.whatsthis=Qu'est-ce donc ?
 captcha.submit=Soumettre
@@ -252,3 +250,7 @@
 Outcome.decision.hold=Conserver
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=Réassigner
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=Nous avous de bonnes raisons de croire que vous soyez un robot ou un spammer. Pourriez-vous sélectionner les photos de chats parmi celles ci-dessous, pour être sûr que vous soyez un humain ?
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=M'adopter

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_it.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_it.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_it.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_it.properties Wed Jan  6 16:47:53 2010
@@ -110,9 +110,7 @@
 markupparser.link.create=Creato "{0}"
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=Per favore, identifica i gatti.
-captcha.description=Occorre che capiamo se sei uno spammer o un robot o un essere umano.  Per favore, seleziona i gatti nelle immagini, in modo da dimostrarci di essere un umano?
 captcha.asirra.please.select=Per favore, seleziona tutte le foto dei gatti:
-captcha.asirra.adopt.me=Adottami
 captcha.asirra.a.get.challenge=Richiedi una nuova immagine.
 captcha.asirra.a.whatsthis=Cos'è questo?
 captcha.submit=Submit
@@ -250,3 +248,7 @@
 Outcome.decision.hold=Blocca
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=Riassegna
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=Occorre che capiamo se sei uno spammer o un robot o un essere umano.  Per favore, seleziona i gatti nelle immagini, in modo da dimostrarci di essere un umano?
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=Adottami

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_nl.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_nl.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_nl.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_nl.properties Wed Jan  6 16:47:53 2010
@@ -109,9 +109,7 @@
 markupparser.link.create=Create "{0}"
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=Kies de katten.
-captcha.description=We denken dat je een robot of een spammer bent.  Kun je hieronder de katten selecteren, zodat we zeker weten dat je een mens bent ?
 captcha.asirra.please.select=Selecteer alle kat foto's:
-captcha.asirra.adopt.me=Adopteer me
 captcha.asirra.a.get.challenge=Vraag andere plaatjes
 captcha.asirra.a.whatsthis=Wat is dit ?
 captcha.submit=Submit
@@ -306,3 +304,7 @@
 Outcome.decision.hold=Hold
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=Opnieuw toewijzen
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=We denken dat je een robot of een spammer bent.  Kun je hieronder de katten selecteren, zodat we zeker weten dat je een mens bent ?
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=Adopteer me

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_pt_BR.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_pt_BR.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_pt_BR.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_pt_BR.properties Wed Jan  6 16:47:53 2010
@@ -111,9 +111,7 @@
 markupparser.link.create=Criar "{0}"
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=Por favor identifique corretamente os gatinhos.
-captcha.description=Nós acreditamos que você possa vir a ser um robô ou um spammer.  Você pode por favor escolher os gatinhos do conjunto abaixo de imagens, para que nós saibamos que você é um ser humano?
 captcha.asirra.please.select=Por favor selecione todas as imagens de gatos:
-captcha.asirra.adopt.me=Me adote
 captcha.asirra.a.get.challenge=Pedir imagens diferentes.
 captcha.asirra.a.whatsthis=O que é isso?
 captcha.submit=Enviar
@@ -191,3 +189,7 @@
 Outcome.decision.hold=Hold
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=Reassign
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=Nós acreditamos que você possa vir a ser um robô ou um spammer.  Você pode por favor escolher os gatinhos do conjunto abaixo de imagens, para que nós saibamos que você é um ser humano?
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=Me adote

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_ru.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_ru.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_ru.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_ru.properties Wed Jan  6 16:47:53 2010
@@ -111,9 +111,7 @@
 markupparser.link.create=\u0421\u043e\u0437\u0434\u0430\u0442\u044c "{0}"
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430 \u043d\u0430 \u043a\u043e\u0442\u044f\u0442.
-captcha.description=\u041c\u044b \u0432\u0435\u0440\u0438\u043c \u0447\u0442\u043e \u0412\u044b \u043d\u0435 \u0440\u043e\u0431\u043e\u0442 \u0438\u043b\u0438 \u0441\u043f\u0430\u043c\u0435\u0440. \u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u0441\u044f, \u0441\u043e\u0441\u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u043a\u043e\u0442\u044f\u0442 \u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435.
 captcha.asirra.please.select=\u0412\u044b\u0431\u0435\u0440\u0435\u0442\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u044b \u043a\u043e\u0442\u044f\u0442\u0430.
-captcha.asirra.adopt.me=\u041f\u0440\u0438\u0439\u043c\u0438 \u043c\u0435\u043d\u044f \u0432 \u0441\u0435\u043c\u044c\u044e
 captcha.asirra.a.get.challenge=\u0417\u0430\u043f\u0440\u043e\u0441 \u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432.
 captcha.asirra.a.whatsthis=\u0427\u0442\u043e \u044d\u0442\u043e \u0442\u0430\u043a\u043e\u0435?
 captcha.submit=\u041f\u0443\u0441\u043a
@@ -255,3 +253,7 @@
 Outcome.decision.hold=\u0417\u0430\u0434\u0435\u0440\u0436\u0430\u0442\u044c
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=\u041f\u0435\u0440\u0435\u043d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=\u041c\u044b \u0432\u0435\u0440\u0438\u043c \u0447\u0442\u043e \u0412\u044b \u043d\u0435 \u0440\u043e\u0431\u043e\u0442 \u0438\u043b\u0438 \u0441\u043f\u0430\u043c\u0435\u0440. \u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u0441\u044f, \u0441\u043e\u0441\u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u043a\u043e\u0442\u044f\u0442 \u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435.
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=\u041f\u0440\u0438\u0439\u043c\u0438 \u043c\u0435\u043d\u044f \u0432 \u0441\u0435\u043c\u044c\u044e

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_zh_CN.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_zh_CN.properties?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_zh_CN.properties (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/classes/CoreResources_zh_CN.properties Wed Jan  6 16:47:53 2010
@@ -111,9 +111,7 @@
 markupparser.link.create=\u521b\u5efa\u201c{0}\u201d
 # Captcha.jsp
 captcha.js.humancheckcomplete.alert=\u8bf7\u6b63\u786e\u8fa8\u8ba4 cats\u3002
-captcha.description=\u6211\u4eec\u76f8\u4fe1\u60a8\u53ef\u80fd\u662f\u4e00\u4e2a\u673a\u5668\u4eba\u7a0b\u5e8f\u6216\u8005\u5783\u573e\u90ae\u4ef6\u6563\u64ad\u8005\u3002\u8bf7\u4ece\u4e0b\u9762\u7684\u4e00\u7ec4\u56fe\u4e2d\u8df3\u51fa\u5c0f\u732b\uff08kittens\uff09\uff0c\u8fd9\u6837\u6211\u4eec\u53ef\u4ee5\u77e5\u9053\u60a8\u662f\u6b63\u5e38\u7684\u4eba\u7c7b\uff1f
 captcha.asirra.please.select=\u8bf7\u9009\u62e9\u6240\u6709\u6709\u732b\u7684\u7167\u7247\uff1a
-captcha.asirra.adopt.me=\u6536\u517b\u6211
 captcha.asirra.a.get.challenge=\u8bf7\u6c42\u4e0d\u540c\u7684\u56fe\u7247\u3002
 captcha.asirra.a.whatsthis=\u8fd9\u662f\u4ec0\u4e48\uff1f
 captcha.submit=\u63d0\u4ea4
@@ -343,3 +341,7 @@
 Outcome.decision.hold=\u6302\u8d77
 #Copied from src/WebContent/WEB-INF/classes/templates/default.properties.. Formerly named outcome.decision.reassign.
 Outcome.decision.reassign=\u91cd\u65b0\u6307\u5b9a
+#Formerly named captcha.description.
+org.apache.wiki.content.inspect.AsirraCaptcha.description=\u6211\u4eec\u76f8\u4fe1\u60a8\u53ef\u80fd\u662f\u4e00\u4e2a\u673a\u5668\u4eba\u7a0b\u5e8f\u6216\u8005\u5783\u573e\u90ae\u4ef6\u6563\u64ad\u8005\u3002\u8bf7\u4ece\u4e0b\u9762\u7684\u4e00\u7ec4\u56fe\u4e2d\u8df3\u51fa\u5c0f\u732b\uff08kittens\uff09\uff0c\u8fd9\u6837\u6211\u4eec\u53ef\u4ee5\u77e5\u9053\u60a8\u662f\u6b63\u5e38\u7684\u4eba\u7c7b\uff1f
+#Formerly named captcha.asirra.adopt.me.
+org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe=\u6536\u517b\u6211

Modified: incubator/jspwiki/trunk/src/WebContent/WEB-INF/jspwiki.tld
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/WEB-INF/jspwiki.tld?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/WEB-INF/jspwiki.tld (original)
+++ incubator/jspwiki/trunk/src/WebContent/WEB-INF/jspwiki.tld Wed Jan  6 16:47:53 2010
@@ -725,10 +725,26 @@
   </tag>
 
   <tag>
+    <description>Injects hidden anti-spam parameters into an
+      enclosing web form, which upon submission are verified
+      by SpamDetector to make sure the user isn't a spammer.
+    </description>
     <name>SpamProtect</name>
     <tagclass>org.apache.wiki.tags.SpamProtectTag</tagclass>
     <bodycontent>empty</bodycontent>
     <info>Injects hidden fields used to detect potential spam.</info>
+    <attribute>
+      <description>If this attribute is set, a challenge will always be
+        rendered. Valid values are "captcha" or "password". If this
+        attribute is not set (the default), no challenge will
+        be rendered unless SpamInterceptor has previously determined
+        that the WikiActionBean's contents are spam. In this case,
+        the challenge will always be a CAPTCHA.
+      </description>
+      <name>challenge</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+    </attribute>
   </tag>
 
   <tag>

Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java (original)
+++ incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java Wed Jan  6 16:47:53 2010
@@ -89,8 +89,6 @@
     private String m_changenote = null;
 
     private boolean m_append = false;
-
-    private boolean m_captcha = false;
     
     private boolean m_overrideConflict = false;
 
@@ -222,17 +220,6 @@
         return m_author;
     }
 
-    /**
-     * Returns whether a CAPTCHA is being used for editing.
-     * 
-     * @return <code>true</code> if a CAPTCHA is in use; <code>false</code>
-     *         otherwise.
-     */
-    public boolean getCaptcha()
-    {
-        return m_captcha;
-    }
-
     /*
      * Returns the changenote for this upload.
      */
@@ -483,12 +470,6 @@
         {
             wikiContext.setPage( modifiedPage );
 
-            if( m_captcha )
-            {
-                wikiContext.setVariable( "captcha", Boolean.TRUE );
-                session.removeAttribute( "captcha" );
-            }
-
             // If this is an append, add a separation line and the author's details
             if( m_append )
             {
@@ -587,18 +568,6 @@
     }
 
     /**
-     * Sets a flag indicating that CAPTCHA should be used for editing.
-     * 
-     * @param captcha <code>true</code> if a CAPTCHA is in use;
-     *            <code>false</code> otherwise.
-     */
-    @Validate( required = false )
-    public void setCaptcha( boolean captcha )
-    {
-        m_captcha = captcha;
-    }
-
-    /**
      * Sets the changenote for this upload; usually a short comment.
      * 
      * @param changenote the change note

Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/AsirraCaptcha.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/AsirraCaptcha.java?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/AsirraCaptcha.java (original)
+++ incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/AsirraCaptcha.java Wed Jan  6 16:47:53 2010
@@ -3,6 +3,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Random;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -16,12 +17,14 @@
 import org.apache.commons.httpclient.HttpStatus;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.wiki.WikiContext;
+import org.apache.wiki.i18n.InternationalizationManager;
 import org.apache.wiki.log.Logger;
 import org.apache.wiki.log.LoggerFactory;
+import org.apache.wiki.ui.stripes.WikiActionBeanContext;
 
 /**
  * <p>
- * {@link Captcha} implementation for Microsoft's Asirra anti-bot testing
+ * {@link Challenge} implementation for Microsoft's Asirra anti-bot testing
  * framework, version 3. Although Microsoft provides a handy client-side
  * JavaScript file that automates most of the test, it isn't very easy to
  * integrate without hard-coding it into JSPWiki forms. So, JSPWiki provides an
@@ -90,13 +93,13 @@
  * Asirra JavaScript.
  * </p>
  */
-public class AsirraCaptcha implements Captcha
+public class AsirraCaptcha implements Challenge
 {
     /**
      * Convenience class that encapsulates the image of a pet,
      * some of which are cats.
      */
-    protected static class Challenge
+    protected static class Pet
     {
         private final String m_id;
 
@@ -107,7 +110,7 @@
          * @param id the unique ID of the animal
          * @param url the URL of the animal's picture
          */
-        public Challenge( String id, String url )
+        public Pet( String id, String url )
         {
             m_id = id;
             m_url = url;
@@ -147,6 +150,10 @@
      */
     protected static final Pattern CATS_PATTERN = Pattern.compile( "ImgRec\\(\"(.+?)\",\"(.+?)\",", Pattern.MULTILINE );
 
+    private static final String ASIRRA_ADOPT_ME_KEY = "org.apache.wiki.content.inspect.AsirraCaptcha.adoptMe";
+
+    private static final String ASIRRA_DESCRIPTION_KEY = "org.apache.wiki.content.inspect.AsirraCaptcha.description";
+
     private static final String CAT_PARAM_PREFIX = "asirra_cat_";
 
     /**
@@ -167,49 +174,6 @@
     private static Logger log = LoggerFactory.getLogger( AsirraCaptcha.class );
 
     /**
-     * 
-     * @param context
-     * @return
-     * @throws IOException
-     */
-    private static String makeFormContent( WikiContext context ) throws IOException
-    {
-        String challengeResponse = getChallengeResponse();
-        String sessionId = extractSessionId( challengeResponse );
-        List<Challenge> challenges = extractChallenges( challengeResponse );
-
-        StringBuilder b = new StringBuilder();
-        b
-            .append( "<input name=\"" + SESSION_ID_PARAM + "\" type=\"hidden\" value=\"" + CryptoUtil.encrypt( sessionId )
-                     + "\" />\n" );
-        b.append( "<table class=\"asirraCaptcha\">" );
-        int i = 0;
-        for( Challenge challenge : challenges )
-        {
-            boolean firstInRow = i % 4 == 0;
-            boolean lastInRow = (i + 1) % 4 == 0;
-            if( firstInRow )
-            {
-                b.append( "<tr>" );
-            }
-            b.append( "<td>" );
-            b.append( "<img src=\"http:" + challenge.url() + "\" />" );
-            b.append( "<br/>" );
-            b.append( "<input type=\"checkbox\" name=\"" + CAT_PARAM_PREFIX + i + "\" value=\"1\">" );
-            b.append( "Adopt me" );
-            b.append( "</input>" );
-            b.append( "</td>" );
-            if( lastInRow )
-            {
-                b.append( "</tr>" );
-            }
-            i++;
-        }
-        b.append( "</table>" );
-        return b.toString();
-    }
-
-    /**
      * Generates a parameter with a random nonce used with Asirra challenge/check requests.
      * @return {@code &rand=} plus the nonce
      */
@@ -223,17 +187,17 @@
      * Extracts the Asirra challenge objects from the challenge response.
      * 
      * @param challengeResponse the challenge response
-     * @return a list of {@link Challenge} objects
+     * @return a list of {@link Pet} objects
      */
-    protected static List<Challenge> extractChallenges( String challengeResponse )
+    protected static List<Pet> extractChallenges( String challengeResponse )
     {
-        List<Challenge> challenges = new ArrayList<Challenge>();
+        List<Pet> pets = new ArrayList<Pet>();
         Matcher matcher = CATS_PATTERN.matcher( challengeResponse );
         while ( matcher.find() )
         {
-            challenges.add( new Challenge( matcher.group( 1 ), matcher.group( 2 ) ) );
+            pets.add( new Pet( matcher.group( 1 ), matcher.group( 2 ) ) );
         }
-        return challenges;
+        return pets;
     }
 
     /**
@@ -279,9 +243,9 @@
      * @return {@code true} if Asirra agrees that the user has adopted only
      * cats, or {@code false} otherwise
      */
-    public boolean check( Inspection inspection )
+    public boolean check( WikiActionBeanContext actionBeanContext )
     {
-        HttpServletRequest request = inspection.getContext().getHttpRequest();
+        HttpServletRequest request = actionBeanContext.getRequest();
 
         // Get sessionId
         String encryptedSessionId = request.getParameter( SESSION_ID_PARAM );
@@ -311,7 +275,7 @@
 
             if( status == HttpStatus.SC_OK )
             {
-                if( body.indexOf( "correct" ) != -1 )
+                if( body.indexOf( "/* correct */" ) != -1 )
                 {
                     return true;
                 }
@@ -332,11 +296,49 @@
      * content if it specifies a value for the {@code content} attribute equal
      * to "form" or a null value.
      * 
-     * @param context the current wiki context
+     * @param context the current WikiActionBeanContext
      */
-    public String formContent( WikiContext context ) throws IOException
+    public String formContent( WikiActionBeanContext context ) throws IOException
     {
-        return makeFormContent( context );
+        String challengeResponse = getChallengeResponse();
+        String sessionId = extractSessionId( challengeResponse );
+        List<Pet> pets = extractChallenges( challengeResponse );
+
+        // Get the localized text
+        Locale locale = context.getLocale();
+        InternationalizationManager i18n = context.getEngine().getInternationalizationManager();
+        String description = i18n.get( InternationalizationManager.CORE_BUNDLE, locale, ASIRRA_DESCRIPTION_KEY );
+        String adoptMe = i18n.get( InternationalizationManager.CORE_BUNDLE, locale, ASIRRA_ADOPT_ME_KEY );
+        
+        StringBuilder b = new StringBuilder();
+        b.append( "<input name=\"" + SESSION_ID_PARAM + 
+                  "\" type=\"hidden\" value=\"" + CryptoUtil.encrypt( sessionId ) + "\" />\n" );
+        b.append( "<div class=\"asirra\">" + description + "</div>" );
+        b.append( "<table class=\"asirraCaptcha\">" );
+        int i = 0;
+        for( Pet pet : pets )
+        {
+            boolean firstInRow = i % 4 == 0;
+            boolean lastInRow = (i + 1) % 4 == 0;
+            if( firstInRow )
+            {
+                b.append( "<tr>" );
+            }
+            b.append( "<td>" );
+            b.append( "<img src=\"http:" + pet.url() + "\" />" );
+            b.append( "<br/>" );
+            b.append( "<input type=\"checkbox\" name=\"" + CAT_PARAM_PREFIX + i + "\" value=\"1\">" );
+            b.append( adoptMe );
+            b.append( "</input>" );
+            b.append( "</td>" );
+            if( lastInRow )
+            {
+                b.append( "</tr>" );
+            }
+            i++;
+        }
+        b.append( "</table>" );
+        return b.toString();
     }
 
     /**

Copied: incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Challenge.java (from r892689, incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Captcha.java)
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Challenge.java?p2=incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Challenge.java&p1=incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Captcha.java&r1=892689&r2=896521&rev=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Captcha.java (original)
+++ incubator/jspwiki/trunk/src/java/org/apache/wiki/content/inspect/Challenge.java Wed Jan  6 16:47:53 2010
@@ -6,15 +6,16 @@
 import org.apache.wiki.tags.SpamProtectTag;
 import org.apache.wiki.ui.stripes.SpamInterceptor;
 import org.apache.wiki.ui.stripes.SpamProtect;
+import org.apache.wiki.ui.stripes.WikiActionBeanContext;
 
 /**
  * <p>
- * Describes how CAPTCHA classes should implement scripting and processing
- * methods test particular CAPTCHA schemes.
+ * Describes how Challenge classes should implement scripting and processing
+ * methods to test particular Challenge schemes, such as CAPTCHA.
  * </p>
  * <p>
- * Captcha specifies three logical states, which are invoked by a combination of
- * custom JSP tags and the {@link SpamInterceptor} interceptor.
+ * Challenge specifies three logical states, which are invoked by a combination
+ * of custom JSP tags and the {@link SpamInterceptor} interceptor.
  * </p>
  * <ol>
  * <li><strong>formContent</strong>. When a JSP containing a &lt;SpamProtect&gt;
@@ -23,7 +24,7 @@
  * included in the &lt;form&gt; element of the page. Note that the
  * &lt;SpamProtect&gt tag is not actually guaranteed to be inside of the form
  * element, but in practice, it should be.</li>
- * <li><strong>check</strong>. This method provides any back-end CAPTCHA
+ * <li><strong>check</strong>. This method provides any back-end Challenge
  * processing that the implementation might need when the form contents are
  * posted, for example calling out to a remote service. It is invoked as part of
  * the content-inspection chain called by {@link SpamInterceptor}, which itself
@@ -33,7 +34,7 @@
  * failure.</li>
  * </ol>
  */
-public interface Captcha
+public interface Challenge
 {
     /**
      * Generates any content needed in the &lt;form&gt; element of an HTML page.
@@ -42,30 +43,39 @@
      * actually injected by the {@link SpamProtectTag} tag, when it is
      * encountered on the JSP.
      * 
-     * @param context the current wiki context
+     * @param actionBeanContext the current ActionBeanContext. Callers can obtain the complete
+     *            request context by calling {@link ActionBeanContext#getRequest().
      * @return the form content
      */
-    public String formContent( WikiContext context ) throws IOException;
+    public String formContent( WikiActionBeanContext actionBeanContext ) throws IOException;
 
     /**
-     * Tests the CAPTCHA.
+     * Tests the Challenge.
      * 
-     * @param inspection the current inspection. Callers can obtain the complete
-     *            wiki and request context by calling
-     *            {@link Inspection#getContext()}.
+     * @param actionBeanContext the current ActionBeanContext. Callers can obtain the complete
+     *            request context by calling {@link ActionBeanContext#getRequest().
      * @return {@code true} if the test succeeded; {@code false} otherwise
      */
-    public boolean check( Inspection inspection ) throws IOException;
-    
-    /**
-     * Policy that specifies when a CAPTCHA is needed.
-     */
-    public static enum Policy
+    public boolean check( WikiActionBeanContext actionBeanContext ) throws IOException;
+
+    public enum Request
     {
-        /** Always. */
-        ALWAYS,
-        
-        /** Never. */
-        NEVER
+        /**
+         * No challenge requested, but CAPTCHA should be generated if
+         * content-inspection determines that the ActionBean contains spam.
+         */
+        CAPTCHA_ON_DEMAND,
+
+        /** CAPTCHA was requested. */
+        CAPTCHA,
+
+        /**
+         * Challenge parameter was omitted, possibly because a spammer submitted
+         * the request.
+         */
+        OMITTED,
+
+        /** Password challenge was requested. */
+        PASSWORD
     }
 }

Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/HandlerInfo.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/HandlerInfo.java?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/HandlerInfo.java (original)
+++ incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/HandlerInfo.java Wed Jan  6 16:47:53 2010
@@ -40,7 +40,6 @@
 import org.apache.wiki.action.WikiActionBean;
 import org.apache.wiki.auth.permissions.PagePermission;
 import org.apache.wiki.auth.permissions.PermissionFactory;
-import org.apache.wiki.content.inspect.Captcha;
 import org.apache.wiki.tags.SpamProtectTag;
 
 
@@ -77,8 +76,6 @@
 
     private final String[] m_spamProtectedFields;
 
-    private final Captcha.Policy m_captchaPolicy;
-
     /**
      * Private constructor that identifies relevant Permission and wiki request
      * context information for a supplied WikiActionBean's event method. The
@@ -153,7 +150,6 @@
         // Store any spam-protection information
         SpamProtect spam = method.getAnnotation( SpamProtect.class );
         m_spamProtected = spam != null;
-        m_captchaPolicy = spam == null ? Captcha.Policy.NEVER : spam.captcha();
         m_spamProtectedFields = spam == null ? new String[0] : spam.content();
 
         // Store the Stripes event handler name
@@ -198,19 +194,6 @@
     }
 
     /**
-     * Returns the CAPTCHA policy that should apply to this event method.
-     * If the event method is not annotated {@link SpamProtect}, the
-     * result will be {@link Captcha.Policy#NEVER}. Otherwise, the value
-     * supplied in the annotation value {@link SpamProtect#captcha()}
-     * will be used.
-     * @return the policy
-     */
-    public Captcha.Policy getCaptchaPolicy()
-    {
-        return m_captchaPolicy;
-    }
-
-    /**
      * Returns the HandlerInfo object associated with the default Stripes event
      * handler method for a supplied class. All Stripes ActionBeans (and JSPWiki
      * WikiActionBeans, by definition) must contain a method with the

Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamInterceptor.java?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamInterceptor.java (original)
+++ incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamInterceptor.java Wed Jan  6 16:47:53 2010
@@ -21,62 +21,193 @@
 package org.apache.wiki.ui.stripes;
 
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import javax.servlet.http.HttpServletRequest;
+
+import net.sourceforge.stripes.action.ActionBeanContext;
 import net.sourceforge.stripes.action.Resolution;
 import net.sourceforge.stripes.controller.ExecutionContext;
 import net.sourceforge.stripes.controller.Interceptor;
 import net.sourceforge.stripes.controller.Intercepts;
 import net.sourceforge.stripes.controller.LifecycleStage;
+import net.sourceforge.stripes.util.CryptoUtil;
 import net.sourceforge.stripes.util.bean.NoSuchPropertyException;
 import net.sourceforge.stripes.util.bean.PropertyExpression;
 import net.sourceforge.stripes.util.bean.PropertyExpressionEvaluation;
 import net.sourceforge.stripes.validation.LocalizableError;
 import net.sourceforge.stripes.validation.ValidationError;
 
+import org.apache.commons.jrcs.diff.DifferentiationFailedException;
 import org.apache.wiki.WikiEngine;
 import org.apache.wiki.action.WikiActionBean;
 import org.apache.wiki.api.WikiException;
 import org.apache.wiki.content.inspect.*;
 import org.apache.wiki.log.Logger;
 import org.apache.wiki.log.LoggerFactory;
+import org.apache.wiki.tags.SpamProtectTag;
 
 /**
- * Stripes Interceptor that ensures that SpamFilter algorithms are applied to
- * events annotated with the {@link SpamProtect} annotation. This class
- * processes form parameters generated by the
- * {@link org.apache.wiki.tags.SpamProtectTag} tag. It fires before the
- * {@link LifecycleStage#CustomValidation} stage; that is, after ActionBean and
- * event handler resolution, and just after parameter binding, but before any
- * other custom validation routines have run.
+ * <p>
+ * In collaboration with {@link org.apache.wiki.tags.SpamProtectTag}, intercepts
+ * an ActionBean after the {@link LifecycleStage#CustomValidation} to determine
+ * whether an ActionBean contains spam. An ActionBean contains spam if an
+ * {@link Inspection} produces a {@link Topic#SPAM} score that falls lower than
+ * the threshold configured for the WikiEngine (which is always a negative
+ * number).
+ * </p>
+ * <p>
+ * SpamInterceptor fires only when the targeted event handler method is
+ * annotated with the {@link SpamProtect} annotation. It fires after the
+ * {@link LifecycleStage#EventHandlingCustomValidation} stage; that is, after
+ * ActionBean and event handler resolution, after parameter binding, and after
+ * other all standard and custom validation routines have run. This ensures that
+ * if the content needs to be inspected to see if the user needs to complete a
+ * Challenge (such as a CAPTCHA), the ActionBean can be stashed away
+ * <em>and</em> all of its parameters are guaranteed to be valid.
+ * </p>
  */
-@Intercepts( { LifecycleStage.CustomValidation } )
+@Intercepts( { LifecycleStage.EventHandling } )
 public class SpamInterceptor implements Interceptor
 {
+    /**
+     * Request parameter injected by {@link SpamProtectTag} and verified by
+     * {@link #intercept(ExecutionContext)}.
+     */
+    public static final String CHALLENGE_REQUEST_PARAM = "_cn";
+
+    /**
+     * Key name of global {@link ValidationError}, which is added if
+     * {@link #intercept(ExecutionContext)} determines that the ActionBean
+     * contains spam.
+     */
+    public static final String SPAM_VALIDATION_ERROR = "validation.challenge.required";
 
     private static final Logger log = LoggerFactory.getLogger( SpamInterceptor.class );
 
     /**
+     * Introspects an ActionBean and returns the value for one or more supplied
+     * properties. Any properties not found will be cheerfully ignored.
+     * 
+     * @param actionBean the actionBean to inspect
+     * @param beanProperties the bean properties to examine
+     * @return the values if successfully evaluated, or <code>null</code> if not
+     *         (or not set)
+     */
+    protected static Map<String, Object> getBeanProperties( WikiActionBean actionBean, String[] beanProperties )
+    {
+        Map<String, Object> map = new HashMap<String, Object>();
+        for( String beanProperty : beanProperties )
+        {
+            try
+            {
+                PropertyExpression propExpression = PropertyExpression.getExpression( beanProperty );
+                PropertyExpressionEvaluation evaluation = new PropertyExpressionEvaluation( propExpression, actionBean );
+                Object value = evaluation.getValue();
+                {
+                    if( value == null )
+                    {
+                        value = "";
+                    }
+                    map.put( beanProperty, value );
+                }
+            }
+            catch( NoSuchPropertyException e )
+            {
+                // Ignore any missing properties
+            }
+        }
+        return map;
+    }
+
+    /**
      * Validates spam parameters contained in any requests targeting an
      * ActionBean method annotated with the {@link SpamProtect} annotation. This
-     * creates a new {@link Inspection} for each ActionBean parameter indicated
-     * by the annotation. The {@link InspectionPlan} for the Inspection is
-     * obtained by calling
-     * {@link SpamInspectionFactory#getInspectionPlan(WikiEngine, java.util.Properties)}.
-     * If any of the modifications are determined to be spam, a Stripes
+     * creates a new {@link Inspection} that inspects each ActionBean property
+     * indicated by the {@link SpamProtect#content()}. The
+     * {@link InspectionPlan} for the Inspection is obtained by calling
+     * {@link SpamInspectionFactory#getInspectionPlan(WikiEngine, java.util.Properties)}
+     * . If any of the modifications are determined to be spam, a Stripes
      * {@link ValidationError} is added to the ActionBeanContext.
+     * 
      * @return always returns {@code null}
      */
     public Resolution intercept( ExecutionContext context ) throws Exception
     {
-        // Execute all other interceptors first
-        Resolution r = context.proceed();
-        if( r != null )
+        // If handler not protected by @SpamProtect, bail/execute next
+        // interceptors in the chain
+        HandlerInfo eventInfo = getHandlerInfo( context );
+        if( !eventInfo.isSpamProtected() )
         {
-            return r;
+            return context.proceed();
         }
 
+        // Inspect the ActionBean contents for spam
+        WikiActionBean actionBean = (WikiActionBean) context.getActionBean();
+        boolean isSpam = false;
+
+        switch( getChallengeRequest( actionBean.getContext() ) )
+        {
+            case CAPTCHA_ON_DEMAND: {
+                // First-time submission; no challenge was requested
+                isSpam = checkForSpam( actionBean, eventInfo );
+                break;
+            }
+
+            case PASSWORD: {
+                // Password challenge was requested
+                // Not implemented yet
+                checkForSpam( actionBean, eventInfo );
+                break;
+            }
+
+            case CAPTCHA: {
+                // CAPTCHA challenge was requested
+                checkForSpam( actionBean, eventInfo );
+                WikiEngine engine = actionBean.getContext().getEngine();
+                Challenge captcha = SpamInspectionFactory.getCaptcha( engine );
+                isSpam = !captcha.check( actionBean.getContext() );
+                break;
+            }
+
+            case OMITTED: {
+                // The Challenge param wasn't there. Naughty user!
+                checkForSpam( actionBean, eventInfo );
+                isSpam = true;
+                break;
+            }
+        }
+
+        // If it's spam, add a ValidationError and redirect back to source page
+        if( isSpam )
+        {
+            ValidationError error = new LocalizableError( SPAM_VALIDATION_ERROR );
+            actionBean.getContext().getValidationErrors().addGlobalError( error );
+            return actionBean.getContext().getSourcePageResolution();
+        }
+
+        // Execute next interceptors in the chain
+        return context.proceed();
+    }
+
+    /**
+     * Looks up and returns the HandlerInfo object that corresponds to the
+     * current Stripes ExecutionContext, based on the ActionBean and event
+     * handler method being executed.
+     * 
+     * @param context the Stripes {@link ExecutionContext} that supplies the
+     *            ActionBean, and the targeted event handler method
+     * @return the HandlerInfo for the current event handler method
+     * @throws WikiException if the event handler method does not have an
+     *             associated HandlerInfo object. This should not happen, and if
+     *             it does, it indicates a classpath error or other
+     *             mis-configuration.
+     */
+    private HandlerInfo getHandlerInfo( ExecutionContext context ) throws WikiException
+    {
         // Get the event handler method
         Method handler = context.getHandler();
 
@@ -86,31 +217,43 @@
         HandlerInfo eventInfo = eventinfos.get( handler );
         if( eventInfo == null )
         {
-            String message = "Event handler method " + actionBean.getClass().getName() +
-                             "#" + handler.getName() +
-                             " does not have an associated HandlerInfo object. This should not happen.";
+            String message = "Event handler method " + actionBean.getClass().getName() + "#" + handler.getName()
+                             + " does not have an associated HandlerInfo object. This should not happen.";
             log.error( message );
             throw new WikiException( message );
         }
+        return eventInfo;
+    }
 
-        // Is the target handler protected by a @SpamProtect annotation?
-        if ( !eventInfo.isSpamProtected() )
-        {
-            return null;
-        }
-
+    /**
+     * Inspects an ActionBean to determine if any of its fields contains spam.
+     * An ActionBean is considered to be spam if an {@link Inspection} results
+     * in a {@link Topic#SPAM} score that exceeds the threshold configured for
+     * the WikiEngine.
+     * 
+     * @param actionBean the ActionBean whose contents should be checked
+     * @param eventInfo the current event's handler metadata, which contains
+     *            information about which fields should be inspected
+     * @return {@code true} if the {@link Topic#SPAM} score for the inspection
+     *         exceeds the spam threshold, or {@code false} otherwise
+     * @throws DifferentiationFailedException if it is not possible to create a
+     *             {@link Change} object showing what contents changed
+     */
+    protected boolean checkForSpam( WikiActionBean actionBean, HandlerInfo eventInfo ) throws DifferentiationFailedException
+    {
         // Retrieve all of the bean fields named in the @SpamProtect annotation
         WikiActionBeanContext actionBeanContext = actionBean.getContext();
         WikiEngine engine = actionBeanContext.getEngine();
         InspectionPlan plan = SpamInspectionFactory.getInspectionPlan( engine, engine.getWikiProperties() );
         Map<String, Object> fieldValues = getBeanProperties( actionBean, eventInfo.getSpamProtectedFields() );
 
-        // Create an Inspection for analyzing each field
+        // Create an Inspection for analyzing the bean's contents
         Inspection inspection = new Inspection( actionBeanContext, plan );
         float spamScoreLimit = SpamInspectionFactory.defaultSpamLimit( engine );
         SpamInspectionFactory.setSpamLimit( inspection, spamScoreLimit );
 
         // Let's get to it!
+        List<Change> changes = new ArrayList<Change>();
         for( Map.Entry<String, Object> entry : fieldValues.entrySet() )
         {
             String name = entry.getKey();
@@ -122,57 +265,54 @@
             }
             else
             {
-                change = Change.getChange( value );
-            }
-
-            // Run the Inspection
-            inspection.inspect( value, change );
-            float spamScore = inspection.getScore( Topic.SPAM );
-
-            // If it's spam, add a validation error for the field
-            if( spamScore <= spamScoreLimit )
-            {
-                ValidationError error = new LocalizableError( "message.spam" );
-                actionBeanContext.getValidationErrors().add( name, error );
+                change = Change.getChange( name, value );
             }
+            changes.add( change );
         }
 
-        return null;
+        // Run the Inspection
+        inspection.inspect( changes.toArray( new Change[changes.size()] ) );
+        float spamScore = inspection.getScore( Topic.SPAM );
+
+        // Does the spam score exceed the threshold?
+        return spamScore <= spamScoreLimit;
     }
 
     /**
-     * Introspects an ActionBean and returns the value for one or more supplied
-     * properties. Any properties not found will be cheerfully ignored.
+     * Retrieves the encrypted parameter {@link #CHALLENGE_REQUEST_PARAM} from
+     * the HTTP request and returns its value. If the parameter is not found in
+     * the request, we assume that the request was made by a spammer or other
+     * naughty person, and the method returns {@link Challenge.Request#NONE}.
+     * Otherwise, the value of the parameter is decrypted and returned. This
+     * method is guaranteed to return a non-{@code null} value.
      * 
-     * @param actionBean the actionBean to inspect
-     * @param beanProperties the bean properties to examine
-     * @return the values if successfully evaluated, or <code>null</code> if not
-     *         (or not set)
+     * @param actionBeanContext the action bean context
+     * @return the Challenge that was requested, or
+     *         {@link Challenge.Request#NONE} if the parameter
+     *         {@link #CHALLENGE_REQUEST_PARAM} was not found.
      */
-    protected static Map<String, Object> getBeanProperties( WikiActionBean actionBean, String[] beanProperties )
+    protected Challenge.Request getChallengeRequest( ActionBeanContext actionBeanContext )
     {
-        Map<String, Object> map = new HashMap<String, Object>();
-        for( String beanProperty : beanProperties )
+        HttpServletRequest request = actionBeanContext.getRequest();
+        String encryptedCaptchaParam = request.getParameter( CHALLENGE_REQUEST_PARAM );
+        if( encryptedCaptchaParam != null )
         {
-            try
+            String captchaParam = CryptoUtil.decrypt( encryptedCaptchaParam );
+            if( captchaParam != null )
             {
-                PropertyExpression propExpression = PropertyExpression.getExpression( beanProperty );
-                PropertyExpressionEvaluation evaluation = new PropertyExpressionEvaluation( propExpression, actionBean );
-                Object value = evaluation.getValue();
+                try
                 {
-                    if ( value == null )
-                    {
-                        value = "";
-                    }
-                    map.put( beanProperty, value );
+                    Challenge.Request challenge = Challenge.Request.valueOf( captchaParam );
+                    return challenge;
+                }
+                catch( IllegalArgumentException e )
+                {
+                    // The decrypted Challenge.Request was a funny value
                 }
-            }
-            catch( NoSuchPropertyException e )
-            {
-                // Ignore any missing properties
             }
         }
-        return map;
-    }
 
+        // Challenge param not found or funny value: assume it's a spammer
+        return Challenge.Request.OMITTED;
+    }
 }

Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamProtect.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamProtect.java?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamProtect.java (original)
+++ incubator/jspwiki/trunk/src/java/org/apache/wiki/ui/stripes/SpamProtect.java Wed Jan  6 16:47:53 2010
@@ -22,7 +22,6 @@
 
 import java.lang.annotation.*;
 
-import org.apache.wiki.content.inspect.Captcha;
 import org.apache.wiki.filters.SpamFilter;
 
 /**
@@ -46,10 +45,4 @@
      * array.
      */
     String[] content() default {};
-
-    /**
-     * Indicates when a CAPTCHA test should be administered to the user.
-     * @return the CAPTCHA policy
-     */
-    Captcha.Policy captcha() default Captcha.Policy.ALWAYS;
 }

Modified: incubator/jspwiki/trunk/tests/java/org/apache/wiki/content/inspect/AsirraCaptchaTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/java/org/apache/wiki/content/inspect/AsirraCaptchaTest.java?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/tests/java/org/apache/wiki/content/inspect/AsirraCaptchaTest.java (original)
+++ incubator/jspwiki/trunk/tests/java/org/apache/wiki/content/inspect/AsirraCaptchaTest.java Wed Jan  6 16:47:53 2010
@@ -27,7 +27,7 @@
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 
-import org.apache.wiki.content.inspect.AsirraCaptcha.Challenge;
+import org.apache.wiki.content.inspect.AsirraCaptcha.Pet;
 
 /**
  */
@@ -56,18 +56,18 @@
     
     public void testExtractChallenges()
     {
-        List<Challenge> challenges = AsirraCaptcha.extractChallenges( m_response );
-        assertEquals( 12, challenges.size() );
-        assertEquals( "401906c8e5fb9117ee4e4666758a03af", challenges.get( 0 ).id() );
-        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/401906c8e5fb9117ee4e4666758a03af.jpg", challenges.get( 0 ).url() );
-        assertEquals( "c330de41625bcee3730c04293d181016", challenges.get( 3 ).id() );
-        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/c330de41625bcee3730c04293d181016.jpg", challenges.get( 3 ).url() );
-        assertEquals( "5682da66d19d4f39b2d4cdc4618273fd", challenges.get( 6 ).id() );
-        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/5682da66d19d4f39b2d4cdc4618273fd.jpg", challenges.get( 6 ).url() );
-        assertEquals( "892a31875c881eab6a37715107ede991", challenges.get( 9 ).id() );
-        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/892a31875c881eab6a37715107ede991.jpg", challenges.get( 9 ).url() );
-        assertEquals( "ceae10e7729b37ba77133e006bab9253", challenges.get( 11 ).id() );
-        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/ceae10e7729b37ba77133e006bab9253.jpg", challenges.get( 11 ).url() );
+        List<Pet> pets = AsirraCaptcha.extractChallenges( m_response );
+        assertEquals( 12, pets.size() );
+        assertEquals( "401906c8e5fb9117ee4e4666758a03af", pets.get( 0 ).id() );
+        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/401906c8e5fb9117ee4e4666758a03af.jpg", pets.get( 0 ).url() );
+        assertEquals( "c330de41625bcee3730c04293d181016", pets.get( 3 ).id() );
+        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/c330de41625bcee3730c04293d181016.jpg", pets.get( 3 ).url() );
+        assertEquals( "5682da66d19d4f39b2d4cdc4618273fd", pets.get( 6 ).id() );
+        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/5682da66d19d4f39b2d4cdc4618273fd.jpg", pets.get( 6 ).url() );
+        assertEquals( "892a31875c881eab6a37715107ede991", pets.get( 9 ).id() );
+        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/892a31875c881eab6a37715107ede991.jpg", pets.get( 9 ).url() );
+        assertEquals( "ceae10e7729b37ba77133e006bab9253", pets.get( 11 ).id() );
+        assertEquals( "//s3.amazonaws.com/Asirra/PhotoDB/ceae10e7729b37ba77133e006bab9253.jpg", pets.get( 11 ).url() );
     }
     
     public void testExtractSession()
@@ -83,10 +83,10 @@
     {
         String challengeResponse = AsirraCaptcha.getChallengeResponse();
         String sessionId = AsirraCaptcha.extractSessionId( challengeResponse );
-        List<Challenge> challenges = AsirraCaptcha.extractChallenges( challengeResponse );
+        List<Pet> pets = AsirraCaptcha.extractChallenges( challengeResponse );
         assertNotNull( sessionId );
-        assertNotNull( challenges );
-        assertEquals( 12, challenges.size() );
+        assertNotNull( pets );
+        assertEquals( 12, pets.size() );
     }
     
 }

Modified: incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/HandlerInfoTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/HandlerInfoTest.java?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/HandlerInfoTest.java (original)
+++ incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/HandlerInfoTest.java Wed Jan  6 16:47:53 2010
@@ -36,7 +36,6 @@
 import org.apache.wiki.action.ViewActionBean;
 import org.apache.wiki.auth.permissions.GroupPermission;
 import org.apache.wiki.auth.permissions.WikiPermission;
-import org.apache.wiki.content.inspect.Captcha;
 
 
 public class HandlerInfoTest extends TestCase
@@ -211,7 +210,6 @@
         HandlerInfo handlerInfo = handlerInfos.get( method );
         assertNotNull( handlerInfo );
         assertTrue( handlerInfo.isSpamProtected() );
-        assertEquals( Captcha.Policy.ALWAYS, handlerInfo.getCaptchaPolicy() );
         assertNotNull( handlerInfo.getSpamProtectedFields() );
         assertEquals( 1, handlerInfo.getSpamProtectedFields().length );
         assertEquals( "wikiText", handlerInfo.getSpamProtectedFields()[0] );
@@ -222,7 +220,6 @@
         handlerInfo = handlerInfos.get( method );
         assertNotNull( handlerInfo );
         assertFalse( handlerInfo.isSpamProtected() );
-        assertEquals( Captcha.Policy.NEVER, handlerInfo.getCaptchaPolicy() );
         assertNotNull( handlerInfo.getSpamProtectedFields() );
         assertEquals( 0, handlerInfo.getSpamProtectedFields().length );
     }

Modified: incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/SpamInterceptorTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/SpamInterceptorTest.java?rev=896521&r1=896520&r2=896521&view=diff
==============================================================================
--- incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/SpamInterceptorTest.java (original)
+++ incubator/jspwiki/trunk/tests/java/org/apache/wiki/ui/stripes/SpamInterceptorTest.java Wed Jan  6 16:47:53 2010
@@ -33,6 +33,8 @@
 import org.apache.wiki.TestEngine;
 import org.apache.wiki.action.TestActionBean;
 import org.apache.wiki.content.inspect.BotTrapInspector;
+import org.apache.wiki.content.inspect.Challenge;
+import org.apache.wiki.tags.SpamProtectTag;
 
 public class SpamInterceptorTest extends TestCase
 {
@@ -82,6 +84,10 @@
         trip.addParameter( "TOKENA", new String[0] );
         trip.addParameter( BotTrapInspector.REQ_SPAM_PARAM, CryptoUtil.encrypt( "TOKENA" ) );
         
+        // Add the challenge param
+        String challengeParam = CryptoUtil.encrypt( Challenge.Request.CAPTCHA_ON_DEMAND.name() );
+        trip.addParameter( SpamInterceptor.CHALLENGE_REQUEST_PARAM, challengeParam );
+
         // Add the UTF-8 token
         trip.addParameter( BotTrapInspector.REQ_ENCODING_CHECK, "\u3041" );
 
@@ -90,9 +96,10 @@
         TestActionBean bean = trip.getActionBean( TestActionBean.class );
         assertNull( bean.getPage() );
 
-        // ...but that we failed the token check (sent back to source page to display errors)
-        assertEquals( bean.getContext().getSourcePage(), trip.getDestination() );
+        // ...but that we failed the token check
         assertEquals( 1, trip.getValidationErrors().size() );
+        assertTrue( SpamProtectTag.isSpamDetected( bean.getContext() ) );
+        assertEquals( null, trip.getDestination() );
     }
 
     public void testInvalidTrap() throws Exception
@@ -103,6 +110,10 @@
         trip.addParameter( "TOKENA", trip.getRequest().getSession().getId() );
         trip.addParameter( BotTrapInspector.REQ_SPAM_PARAM, CryptoUtil.encrypt( "TOKENA" ) );
 
+        // Add the challenge param
+        String challengeParam = CryptoUtil.encrypt( Challenge.Request.CAPTCHA_ON_DEMAND.name() );
+        trip.addParameter( SpamInterceptor.CHALLENGE_REQUEST_PARAM, challengeParam );
+
         // Add the UTF-8 token
         trip.addParameter( BotTrapInspector.REQ_ENCODING_CHECK, "\u3041" );
 
@@ -111,9 +122,10 @@
         TestActionBean bean = trip.getActionBean( TestActionBean.class );
         assertEquals( null, bean.getPage() );
 
-        // ...but that we failed the token check (sent back to source page to display errors)
-        assertEquals( bean.getContext().getSourcePage(), trip.getDestination() );
+        // ...but that we failed the trap check
         assertEquals( 1, trip.getValidationErrors().size() );
+        assertTrue( SpamProtectTag.isSpamDetected( bean.getContext() ) );
+        assertEquals( null, trip.getDestination() );
     }
 
     public void testMissingToken() throws Exception
@@ -123,6 +135,10 @@
         trip.addParameter( BotTrapInspector.REQ_TRAP_PARAM, new String[0] );
         trip.addParameter( BotTrapInspector.REQ_SPAM_PARAM, CryptoUtil.encrypt( "" ) );
 
+        // Add the challenge param
+        String challengeParam = CryptoUtil.encrypt( Challenge.Request.CAPTCHA_ON_DEMAND.name() );
+        trip.addParameter( SpamInterceptor.CHALLENGE_REQUEST_PARAM, challengeParam );
+
         // Add the UTF-8 token
         trip.addParameter( BotTrapInspector.REQ_ENCODING_CHECK, "\u3041" );
 
@@ -131,9 +147,10 @@
         TestActionBean bean = trip.getActionBean( TestActionBean.class );
         assertEquals( null, bean.getPage() );
 
-        // ...but that we failed the token check (sent back to source page to display errors)
-        assertEquals( bean.getContext().getSourcePage(), trip.getDestination() );
+        // ...but that we failed the token check
         assertEquals( 1, trip.getValidationErrors().size() );
+        assertTrue( SpamProtectTag.isSpamDetected( bean.getContext() ) );
+        assertEquals( null, trip.getDestination() );
     }
 
     public void testMissingTrap() throws Exception
@@ -143,6 +160,10 @@
         trip.addParameter( "TOKENA", trip.getRequest().getSession().getId() );
         trip.addParameter( BotTrapInspector.REQ_SPAM_PARAM, CryptoUtil.encrypt( "TOKENA" ) );
 
+        // Add the challenge param
+        String challengeParam = CryptoUtil.encrypt( Challenge.Request.CAPTCHA_ON_DEMAND.name() );
+        trip.addParameter( SpamInterceptor.CHALLENGE_REQUEST_PARAM, challengeParam );
+
         // Add the UTF-8 token
         trip.addParameter( BotTrapInspector.REQ_ENCODING_CHECK, "\u3041" );
 
@@ -151,7 +172,9 @@
         TestActionBean bean = trip.getActionBean( TestActionBean.class );
         assertEquals( null, bean.getPage() );
 
-        // ...and that we passed the token check
+        // ...and that we passed the inspection
+        assertEquals( 0, trip.getValidationErrors().size() );
+        assertFalse( SpamProtectTag.isSpamDetected( bean.getContext() ) );
         assertEquals( null, trip.getDestination() );
     }
 
@@ -164,14 +187,43 @@
         trip.addParameter( "TOKENA", trip.getRequest().getSession().getId() );
         trip.addParameter( BotTrapInspector.REQ_SPAM_PARAM, paramValue );
 
+        // Add the challenge param
+        String challengeParam = CryptoUtil.encrypt( Challenge.Request.CAPTCHA_ON_DEMAND.name() );
+        trip.addParameter( SpamInterceptor.CHALLENGE_REQUEST_PARAM, challengeParam );
+
+        // Verify that we got the ActionBean...
+        trip.execute( "test" );
+        TestActionBean bean = trip.getActionBean( TestActionBean.class );
+        assertEquals( null, bean.getPage() );
+
+        // ...but that we failed the UTF-8 check
+        assertEquals( 1, trip.getValidationErrors().size() );
+        assertTrue( SpamProtectTag.isSpamDetected( bean.getContext() ) );
+        assertEquals( null, trip.getDestination() );
+    }
+
+    public void testNoChallenge() throws Exception
+    {
+        // Add the trap + token params
+        MockRoundtrip trip = m_engine.guestTrip( "/Test.action" );
+        trip.addParameter( BotTrapInspector.REQ_TRAP_PARAM, new String[0] );
+        trip.addParameter( "TOKENA", trip.getRequest().getSession().getId() );
+        trip.addParameter( BotTrapInspector.REQ_SPAM_PARAM, CryptoUtil.encrypt( "TOKENA" ) );
+
+        // Omit the challenge param
+
+        // Add the UTF-8 token
+        trip.addParameter( BotTrapInspector.REQ_ENCODING_CHECK, "\u3041" );
+
         // Verify that we got the ActionBean...
         trip.execute( "test" );
         TestActionBean bean = trip.getActionBean( TestActionBean.class );
         assertEquals( null, bean.getPage() );
 
-        // ...but that we failed the token check (sent back to source page to display errors)
-        assertEquals( bean.getContext().getSourcePage(), trip.getDestination() );
+        // ...but that we failed the challenge check
         assertEquals( 1, trip.getValidationErrors().size() );
+        assertTrue( SpamProtectTag.isSpamDetected( bean.getContext() ) );
+        assertEquals( null, trip.getDestination() );
     }
 
     public void testNoToken() throws Exception
@@ -179,6 +231,10 @@
         // Execute the SpamProtect-ed handler with no token
         MockRoundtrip trip = m_engine.guestTrip( "/Test.action" );
 
+        // Add the challenge param
+        String challengeParam = CryptoUtil.encrypt( Challenge.Request.CAPTCHA_ON_DEMAND.name() );
+        trip.addParameter( SpamInterceptor.CHALLENGE_REQUEST_PARAM, challengeParam );
+
         // Add the UTF-8 token
         trip.addParameter( BotTrapInspector.REQ_ENCODING_CHECK, "\u3041" );
 
@@ -187,14 +243,15 @@
         TestActionBean bean = trip.getActionBean( TestActionBean.class );
         assertEquals( null, bean.getPage() );
 
-        // ...but that we failed the token check (sent back to source page to display errors)
-        assertEquals( bean.getContext().getSourcePage(), trip.getDestination() );
+        // ...but that we failed the token check
         assertEquals( 1, trip.getValidationErrors().size() );
+        assertTrue( SpamProtectTag.isSpamDetected( bean.getContext() ) );
+        assertEquals( null, trip.getDestination() );
     }
 
     public void testToken() throws Exception
     {
-        // Add the trap + token params
+        // Add the trap + token + challenge params
         MockRoundtrip trip = m_engine.guestTrip( "/Test.action" );
         TestEngine.addSpamProtectParams( trip );
         trip.addParameter( "text", "test value" );
@@ -204,7 +261,9 @@
         TestActionBean bean = trip.getActionBean( TestActionBean.class );
         assertEquals( null, bean.getPage() );
 
-        // ...and that we passed the token check
+        // ...and that we passed the inspection
+        assertEquals( 0, trip.getValidationErrors().size() );
+        assertFalse( SpamProtectTag.isSpamDetected( bean.getContext() ) );
         assertEquals( null, trip.getDestination() );
     }
 }



Mime
View raw message