ARTICLE: "furnace.recaptcha" "Recaptcha support for Furnace"
"The " { $vocab-link "furnace.recaptcha" } " vocabulary implements support for the recaptcha. Recaptcha is a web service that provides the user with a captcha, a test that is easy to solve by visual inspection, but hard to solve by writing a computer program. Use a captcha to protect forms from abusive users." $nl
-"The recaptcha responder is a " { $link filter-responder } " that wraps another responder. Set the " { $slot "domain" } ", " { $slot "public-key" } ", and " { $slot "private-key" } " slots of this responder to your recaptcha account information." $nl
+"The recaptcha responder is a " { $link filter-responder } " that wraps another responder. Set the " { $slot "domain" } ", " { $slot "site-key" } ", and " { $slot "secret-key" } " slots of this responder to your recaptcha account information." $nl
"Wrapping a responder with recaptcha support:"
{ $subsections <recaptcha> }
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors furnace.actions furnace.redirection html.forms
-html.templates.chloe.compiler html.templates.chloe.syntax
-http.client http.server http.server.filters io.sockets kernel
-locals namespaces sequences splitting urls validators
-xml.syntax furnace.conversations ;
+USING: accessors assocs furnace.actions furnace.conversations
+furnace.redirection html.forms html.templates.chloe.compiler
+html.templates.chloe.syntax http.client http.server
+http.server.filters io.sockets json.reader kernel locals
+namespaces sequences splitting urls validators xml.syntax ;
IN: furnace.recaptcha
-TUPLE: recaptcha < filter-responder domain public-key private-key ;
+TUPLE: recaptcha < filter-responder domain secret-key site-key ;
SYMBOL: recaptcha-error
<PRIVATE
-: (render-recaptcha) ( url -- xml )
- dup
- [XML
+: render-recaptcha ( recaptcha -- xml )
+ site-key>> [XML
<script type="text/javascript"
- src=<->>
+ src="https://www.google.com/recaptcha/api.js" async="async" defer="defer">
</script>
- <noscript>
- <iframe src=<->
- height="300" width="500" frameborder="0"></iframe><br/>
- <textarea name="recaptcha_challenge_field" rows="3" cols="40">
- </textarea>
- <input type="hidden" name="recaptcha_response_field"
- value="manual_challenge"/>
- </noscript>
+ <div class="g-recaptcha" data-sitekey=<->></div>
XML] ;
-: recaptcha-url ( secure? -- ? )
- "https" "http" ? "://www.google.com/recaptcha/api/challenge" append
- recaptcha-error cget [ "?error=" glue ] when* >url ;
-
-: render-recaptcha ( -- xml )
- secure-connection? recaptcha-url
- recaptcha get public-key>> "k" set-query-param (render-recaptcha) ;
-
: parse-recaptcha-response ( string -- valid? error )
- "\n" split first2 [ "true" = ] dip ;
+ json> [ "success" of ] [ "error-codes" of ] bi ;
-:: (validate-recaptcha) ( challenge response recaptcha -- valid? error )
- recaptcha private-key>> :> private-key
+:: (validate-recaptcha) ( response recaptcha -- valid? error )
+ recaptcha secret-key>> :> secret-key
remote-address get host>> :> remote-ip
H{
- { "challenge" challenge }
{ "response" response }
- { "privatekey" private-key }
+ { "secret" secret-key }
{ "remoteip" remote-ip }
- } URL" http://api-verify.recaptcha.net/verify"
+ } URL" https://www.google.com/recaptcha/api/siteverify"
http-post nip parse-recaptcha-response ;
: validate-recaptcha-params ( -- )
{
- { "recaptcha_challenge_field" [ v-required ] }
- { "recaptcha_response_field" [ v-required ] }
+ { "g-recaptcha-response" [ v-required ] }
} validate-params ;
PRIVATE>
-CHLOE: recaptcha drop [ render-recaptcha ] [xml-code] ;
+CHLOE: recaptcha drop [ recaptcha get render-recaptcha ] [xml-code] ;
: validate-recaptcha ( -- )
begin-conversation
validate-recaptcha-params
- "recaptcha_challenge_field" value
- "recaptcha_response_field" value
+ "g-recaptcha-response" value
recaptcha get
(validate-recaptcha)
recaptcha-error cset