1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@cs.vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (C): 2013, VU University Amsterdam 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License 10 as published by the Free Software Foundation; either version 2 11 of the License, or (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public 19 License along with this library; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 22 As a special exception, if you link this library with other files, 23 compiled with a Free Software compiler, to produce an executable, this 24 library does not by itself cause the resulting executable to be covered 25 by the GNU General Public License. This exception does not however 26 invalidate any other reasons why the executable file might be covered by 27 the GNU General Public License. 28*/ 29 30:- module(recaptcha, 31 [ recaptcha//1, % +Options 32 recaptcha_parameters/1, % -HTTP parameter list 33 recaptcha_verify/2 % +Request, +HTTPParamList 34 ]). 35:- use_module(library(http/html_head)). 36:- use_module(library(http/html_write)). 37:- use_module(library(http/http_open)). 38:- use_module(library(error)). 39:- use_module(library(option)). 40 41:- html_resource( 42 recaptcha, 43 [ virtual(true), 44 requires([ 'http://www.google.com/recaptcha/api/js/recaptcha_ajax.js' 45 ]) 46 ]).
83:- multifile
84 key/2.
clean
.96recaptcha(Options) --> 97 { ( key(public, PublicKey) 98 -> true 99 ; existence_error(recaptcha_key, public) 100 ), 101 option(theme(Theme), Options, clean) 102 }, 103 html_requires(recaptcha), 104 html(div(id(recaptcha), [])), 105 create_captcha(recaptcha, PublicKey, Theme). 106 107 108create_captcha(Id, PublicKey, Theme) --> 109 html(script(type('text/javascript'), 110 \[ 'Recaptcha.create("',PublicKey,'",\n', 111 ' "',Id,'",\n', 112 ' {\n', 113 ' theme:"',Theme,'"\n', 114 ' });\n' 115 ])).
123recaptcha_parameters(
124 [ recaptcha_challenge_field(_Challenge, [optional(true), default('')]),
125 recaptcha_response_field(_Response, [optional(true), default('')])
126 ]).
142recaptcha_verify(Request, Parameters) :- 143 memberchk(recaptcha_challenge_field(Challenge, _), Parameters), 144 memberchk(recaptcha_response_field(Response, _), Parameters), 145 ( Response == '' 146 -> domain_error(recaptcha_response, Response) 147 ; recaptcha_verify(Request, Challenge, Response) 148 ). 149 150recaptcha_verify(Request, Challenge, Response) :- 151 remote_IP(Request, Peer), 152 ( key(private, PrivateKey) 153 -> true 154 ; existence_error(recaptcha_key, private) 155 ), 156 setup_call_cleanup( 157 http_open('http://www.google.com/recaptcha/api/verify', 158 In, 159 [ post(form([ privatekey(PrivateKey), 160 remoteip(Peer), 161 challenge(Challenge), 162 response(Response) 163 ])) 164 ]), 165 read_stream_to_lines(In, Lines), 166 close(In)), 167 maplist(atom_codes, Atoms, Lines), 168 ( Atoms = [true|_] 169 -> true 170 ; Atoms = [false, 'incorrect-captcha-sol'|_] 171 -> fail 172 ; Atoms = [false, Error, _], 173 throw(error(recaptcha_error(Error), _)) 174 ). 175 176 177read_stream_to_lines(In, Lines) :- 178 read_line_to_codes(In, Line0), 179 read_stream_to_lines(Line0, In, Lines). 180 181read_stream_to_lines(end_of_file, _, []) :- !. 182read_stream_to_lines(Line, In, [Line|More]) :- 183 read_line_to_codes(In, Line1), 184 read_stream_to_lines(Line1, In, More). 185 186 187remote_IP(Request, IP) :- 188 memberchk(x_forwarded_for(IP0), Request), !, 189 atomic_list_concat(Parts, ', ', IP0), 190 last(Parts, IP). 191remote_IP(Request, IP) :- 192 memberchk(peer(Peer), Request), !, 193 peer_to_ip(Peer, IP). 194remote_IP(_, -). 195 196 197peer_to_ip(ip(A,B,C,D), IP) :- 198 atomic_list_concat([A,B,C,D], '.', IP).
public
and to the reCAPTCHA private key if Which is private
.
We leave the key handling to a hook to accomodate different ways for storing and transferring the keys. A simple implementation is:
:- use_module(library(http/recaptcha)). :- multifile recaptcha:key/2. recaptcha:key(public, 'Public key goes here'). recaptcha:key(private, 'Private key goes here').
Add reCAPTCHA functionality to a form
This module is a plugin for the SWI-Prolog HTTP/HTML framework to add reCAPTCHA functionality to a form. It works as follows:
method('POST')
and include, in addition to the data you request from the human user, the reCAPTCHA widget using e.g.,examples/demo.pl
contains a fully functional demo. */