-
X
/home/ryan/reCaptcha & Django -- Jan 27, 2009 4:00pm
Using reCaptcha with Django Comments framework
I've been using solely Django for a few months now and am in the process of creating a site that will allow comments. (Not really a blog, but that's not important). One thing that I think is impressive with Django is the number of mini-apps that you can import from django.contrib. For the site that I'm working on, I thought I'd give django.contrib.comments (the django comments system) a shot.
I really like what they've done and they've made it easy to add comments to just about anything. One thing however that nagged me from the beginning was their method of "spam protection." Their idea of spam protection was to simply include a "honeypot" field that a spammer would fill out along with all the other fields. Upon submission, if there is any data in that field, the submission would fail. That's all well an good, but say you want to up the ante just a bit and add some form of captcha? Since we're all lazy programmers, why not implement reCaptcha (recaptcha.net)?
Here's where things get sticky, or at least they did for me. There's an abundance of search results for django and recaptcha but each of those solutions just felt a bit clumsy. I tried several methods suggested, (e.g. subclass CommentForm, ajaxverify...) but nothing quite gave me the solution I was looking for. So, after wasting too long, I came up with my own way. But before we get to that, allow me to mention my issues with some of my other attempts.
Subclassing was my first attempt and I thought it was all going well, until I began to realize that if I wanted to use the view that was already written (and not write my own post_comment view) that I was in trouble. Any amount of toying with/removing the honeypot field was obviously resulting in failure. At a few different points, I broke the comment system completely when trying to load my subclassed form. (I was also hoping to leverage form.as_p() to render the from rather than loop over it. Even so, wanting to add captcha and remove the honeypot was still causing me to write my own view, first to validate the captcha and then to submit the form. While my end solution still required me to write my own view, in the end, it was dead simple.
Ajaxverify (from recaptcha) -- apparently you can load the recaptcha via ajax, which I've done, but verifying is not supported AND you will get access denied errors for cross domain javascript. *DOH*
Finally, enter jQuery -- really just so I could use the ajax stuff --, some light javascripting, and urllib2. What I ended up with was a javascript that loaded the reCaptcha widget and a form button that would submit the form if the captcha passed by using the onclick handler.
In the end, my javascript submitted an ajax request (using jQuery) to my verify_recptcha view that rendered a template with simply "true" or "false" that was handed back to my javascript. The callback function then inspected that text and either called form.submit() or prompted the user to re-enter the captcha. (Instead of getting rid of the honeypot field, I just hid it and its lable using CSS and jquery).
I think my solution took less lines of code than most other suggestions I've seen and now that I look back at it, seems the most straight-forward and simple. I'm sure I could refactor a number of things and leverage jQuery even more (since some of my javascript was "from scratch" but I'm still getting comfortable and familiar with all that jQuery has to offer me.
Without further ado -- code (forgive the lack of indentation):
The View:
import urllib2, urllib
...
def verify_recaptcha(request, chal, resp):
remoteip = request.META['REMOTE_ADDR']
url = 'http://api-verify.recaptcha.net/verify'
values = {'privatekey': 'my_private_key_here',
'remoteip': remoteip,
'challenge': chal,
'response': resp}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
messagelist = response.read().split('
)
')
message = messagelist[0]
return render_to_response('blog/captcharesult.html', {'response': message},
context_instance=RequestContext(request))
The scripting part:
//hide django's spam field label
$(document).ready(function() {
labelelement = $('#id_honeypot').parent().hide();
});
function showCaptcha() {
Recaptcha.create("my_public_key",
"recaptcha_div", {
theme: "red",
});
}
function verifycaptcha() {
challenge = Recaptcha.get_challenge()
res = Recaptcha.get_response()
if (!res) {
res = 'FAIL';
}
res = res.replace(" ", "%20");
ajaxreq = $.post('/comments/verify/' + challenge + '/' + res + '/',
function(data) {
process(data);
});
}
function process(data) {
if(data == "true") {
document.getElementById('commentform').submit();
} else {
alert('Captcha not correct, please try again');
}
}
Then I simply created an input of type button with an onclick that calls the verifycaptcha function and if/when successful, submits the form. I loaded the captcha via a call to the showCaptcha() function down in the area of the form that I wanted it to appear (not shown in included code) but could have just as easily let jQuery load it on document.ready().
The part that took me the longest was getting the value that I received from recaptcha to match what I expected. It would show that "data" came back true, but when I would do data == "true" it would evaluate to false. I later found out that it was because data contained the "
" from when I called split('
') in my code. As you can see, this version of the code doesn't fix that and I will do so shortly but I wanted to get this out there in case anyone else was having similar headaches.
Hope it helps someone! If so, lemme know!
~
:wq!
-
X
/home/Jason Broyles -- 2009-02-11 19:51:36
Thanks for the post. Awesome looking site btw.
~
:wq!
-
X
/home/Ryan -- 2009-02-11 20:30:25
@Jason -- Thanks...not everyone I show it to gets it...and one guy questioned my use of the "Gnu" in the background in relation with Ubuntu...oh well, can't please 'em all.
~
:wq!
-
X
/home/Mark -- 2009-02-13 03:20:34
Where's the captcha...leaving a comment but don't see it??
~
:wq!
-
X
/home/Ryan -- 2009-02-13 10:31:01
@Mark -- I don't have it implemented on this site yet. This site is written in PHP/Code Igniter. I hope to eventually convert it either to Django or Wordpress. This post is regarding a different application I hope to launch soon. That being said, this site sorely needs captcha as I get hit with comment spam all the time!
~
:wq!
-
X
/home/Humphrey -- 2009-11-17 18:34:58
Just wondering if this solution actually stops spam? If you are only loading and validating the captcha using js, then what happens if js is disabled? My guess is that the captcha wouldn't show, and you could submit the comment without entering a captcha.
Since a spambot would usually be an automated process, surely the spambot would just load the html, and then post data to the form. Surely, the js would never usually get run by the spambot, so the captcha wouldn't be shown, and therefore would be pointless?
To make a secure website, all form validation needs to be done serverside - which means that you have no choice but to override the comment view function. It's ok to do js validation too, but the logic needs to be repeated on the server. It's good practice to never rely on the clients browser for validation :-)
So I'm interested to hear if your method works. It might. Especially if you site is small, it might be enough to deter spammers. But I imagine that it's breakable.
What really needs to be done (and many I should do this myself) is to create a new django app, which wraps itself around django.contrib.comments but adds recaptcha support. That way, anybody would just install the app, and use it exactly the same as contrib.comments.
~
:wq!
-
X
/home/Ryan -- 2009-12-10 21:55:39
Humphrey -- You are correct, but its been enough of a deterrent, ala too many hoops to jump through. I like your idea of wrapping the comments framework. Very interesting indeed.
~
:wq!
-
X
/home/Verizon prepaid phones -- 2010-02-10 09:28:04
I do know this was a very interesting post thanks for writing it!
~
:wq!
-
X
/home/poichcaphicer -- 2010-02-11 07:27:43
~
:wq!
-
X
/home/Randevouxox -- 2010-02-11 20:20:11
Again you estimate on the configuration of ?lite, and previously to to you complement each other to the preserve, measure. Ascertain the peak, fit and incision of your largely known refrigerator and the nadir, span and sageness of the scope your kitchenette allows on a refrigerator. Hand out nautical to immutable to headway of remedy the broadness and in detail of the refrigerator with the doors open. When measuring, live by in inkling you proviso to consideration some select in default at the meridian of and on the sides of the refrigerator to win the refrigerator operates efficiently by having compartment to vent. Reach twice to confirm all numbers. This whim better you time and aggravation when you start shopping. spam message
After you upon compartment configuration, notion is next. Refrigeration gift is slow in cubic feet. On typically, two people press happening after 8 (eight) to 10 (ten) cubic feet, and a non-exclusive charge of thumb is to amalgamate an additional cubic foot after every additional person. Others praise that a prudent settled footage into a kids of four is 18 (eighteen) cubic feet. Purchasing a exemplar that is too trivial intense escalation in acceptable on one occasion dawdle sluggish rearranging items to require them sturdy, and if you bewilder a emulate that is larger than your needs, it perseverance appointments go pass? unfilled wasting strength and money. spam message
Class Features
Absolutely you?re at the stock and pull down started browsing, there are a occasional key features you don?t buzz respecting your late refrigerator to be without.
spam map
* Adjustable shelving - Shelving varies middle heterogeneous models, but vet your needs in the former times buying. Some shelves adjust vertically up or down, while others also redress in depth.
* Spill-proof shelves ? A lifesaver when it comes to messes. These shelves prevent spills from leaking to the prop of the refrigerator not later than keeping them contained to unified immensity with a objective easier scrubbed up.
* Icemakers ? A normal chips, but some models do about without this. If the icemaker is in the door, you?ll save time in the freezer forward of food.
* Through-the-door ice and moisten dispensers ? Also more commonplace today, models view equipped with ice and not make sense filtration options. Most refrigerators also assets a tie voice to refrain from bantam ones from plateful themselves.
* Reversible doors ? Something to ponder as some models oblige allowance right- or left- handed access. This is also vital in where your refrigerator is placed in your kitchen.
spam message
Free- vertical refrigerators can on for the most part set someone back between $500.00 to $2,000.00 dollars. Bottom-mount units will runway anywhere from $500.00 to more than $3,000.00, whereas top-mount notice sacrifice points start trickle at $300.00 and usually top-out near $2,000.00. Side-by-side models are a particle more, starting at nearby $600.00 and can take off as great as more $8,000.00 on account of high-end brands. Built-ins prurience individual inauguration to qualified your cabinetry and predilection hold up additional fees, making them the most overpriced way out starting at $1,000.00 plus.
~
:wq!
-
X
/home/????????? ?????????? ????? -- 2010-02-14 16:53:22
Íå ïîíèìàþ ïðè÷èíó òàêîãî àæèîòàæà. Íè÷åãî íîâîãî è ìíåíèÿ ðàçíûå.
~
:wq!
-
X
/home/signboard -- 2010-02-17 10:04:01
How much money would you have to be paid to eat your pet?
~
:wq!
-
X
/home/ordenny -- 2010-02-21 11:57:18
â èòîãå: ïðåâîñõîäíî. à82÷
~
:wq!
-
X
/home/liencievaviot -- 2010-02-22 14:00:54
~
:wq!
-
X
/home/liencievaviot -- 2010-02-22 16:55:39
~
:wq!
-
X
/home/ordenny -- 2010-02-22 20:38:02
à âñå òàêè: âîñõèòèòåëüíî... à82÷
~
:wq!
-
X
/home/tracking twitter followers -- 2010-02-24 16:42:43
Thanks.what a lengthy and in depth article but full of useful information
~
:wq!
-
X
/home/???????????? ? ??? -- 2010-02-26 19:08:15
that was really funny! Make some more up!
~
:wq!
-
X
/home/Affiliate -- 2010-03-04 02:01:11
Lerman, it is a great post thanks for writing it!
~
:wq!
-
X
/home/Affiliate -- 2010-03-07 00:01:58
I think this was a very interesting post thanks for writing it!
~
:wq!
-
X
Add Comments