Recaptcha to Avoid Comment Spam

Feb 28, 2010 at 12:28 PM

I tried to add the Recaptcha user control for ASP.NET to the comment.view file but as I can see it is not being rendered. Is there a way to do this? Thanks

Coordinator
Mar 3, 2010 at 3:28 AM

You can't just add Asp.Net controls to a view page in Graffiti.  Asp.Net controls can only be added to .aspx pages or .ascx user controls.  Graffiti's views are not Asp.Net pages in that sense.  The views essentially sit on top of Asp.Net and Asp.Net processes the content on the views, but you would need to write a custom rendering engine to have it parse the views and figure out how to render Asp.Net controls.  And I don't just mean calling functions inside existing Asp.Net events, I think you would have to write the entire thing yourself.

Mar 3, 2010 at 5:26 AM

Thanks for the reply Charles, I understood what you meant. Writing a rendering engine would be little bit complex. Anyway thanks again.

May 17, 2012 at 6:12 PM

What is the solution? How do we add recaptcha? in layman's terms...

May 25, 2012 at 2:09 AM
Edited May 25, 2012 at 2:16 AM

Step 1: Create a recaptcha.ashx in your root site, remember edit YOUR-PRIVATE-KEY-HERE

<%@ WebHandler Language="C#" CodeBehind="recaptcha.ashx.cs" Class="Graffiti.Web.recaptcha" %>

using System;
using System.Collections.Generic;
using System.Web;
using System.Net;
using System.Text;
using System.IO;

namespace Graffiti.Web
{
    /// <summary>
    /// Summary description for recaptcha
    /// </summary>
    public class recaptcha : IHttpHandler
    {
        private const string private_key = @"YOUR-PRIVATE-KEY-HERE";
        private const string VerifyUrl = @"http://api-verify.recaptcha.net/verify";
        
        private bool CheckIP(string ipCheck)
        {
            System.Net.IPAddress ipReal = System.Net.IPAddress.Parse(ipCheck);
            if (ipReal.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork &&
                ipReal.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)            
                return false;
            return true;
        }
        
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";            
            if (context.Request.RequestType != "POST")//make sure it only POST by ajax and jquery
            {
                context.Response.Write("fail");
                return; 
            }
            
            string recaptcha_challenge_field = context.Request.QueryString["recaptcha_challenge_field"];
            string recaptcha_response_field = context.Request.QueryString["recaptcha_response_field"];
            string remote_ip = context.Request.UserHostAddress;
            
            if (recaptcha_challenge_field == null || recaptcha_challenge_field.Length == 0 ||
               recaptcha_response_field == null || recaptcha_response_field.Length == 0 ||
               CheckIP(remote_ip) == false)
            {
                context.Response.Write("fail");
                return; 
            } 
            
            //every parametters now OK, now check it !

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(VerifyUrl);
            // to avoid issues with Expect headers
            request.ProtocolVersion = HttpVersion.Version10;
            request.Timeout = 30 * 1000 /* 30 seconds */;
            request.Method = "POST";
            request.UserAgent = "reCAPTCHA/ASP.NET";
            request.ContentType = "application/x-www-form-urlencoded";
            string formdata = String.Format("privatekey={0}&remoteip={1}&challenge={2}&response={3}",
                                    HttpUtility.UrlEncode(private_key),
                                    HttpUtility.UrlEncode(remote_ip),
                                    HttpUtility.UrlEncode(recaptcha_challenge_field),
                                    HttpUtility.UrlEncode(recaptcha_response_field));
            
            byte[] formbytes = Encoding.ASCII.GetBytes(formdata);

            using (Stream requestStream = request.GetRequestStream())
                requestStream.Write(formbytes, 0, formbytes.Length);

            string[] results;
            try
            {
                using (WebResponse httpResponse = request.GetResponse())
                {
                    using (TextReader readStream = new StreamReader(httpResponse.GetResponseStream(), Encoding.UTF8))
                    {
                        results = readStream.ReadToEnd().Split();
                    }
                }
            }
            catch (Exception e)
            {
                //something wrong ! return false so user cannot comment this !!!
                context.Response.Write("fail");
                return;
            }
            switch (results[0])
            {
                case "true":
                    //user enter valid the reCAPTCHA code
                    context.Response.Write("success");
                    return;        
                case "false":
                    //he he he...., user enter an invalid reCHAPTCHA code
                    context.Response.Write("fail");
                    return;        
                default:
                    //something wrong, that I cannot handle
                    context.Response.Write("fail");
                    return;        
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

Step 2: create a javascript recaptcha.js your theme folder

var Error = "Invalid recaptcha. Please try again";
function validateReCaptcha() {
    challengeField = $("input#recaptcha_challenge_field").val();
    responseField = $("input#recaptcha_response_field").val();
    var html = $.ajax({
        type: "POST",
        url: "/recaptcha.ashx?recaptcha_challenge_field=" + challengeField + "&recaptcha_response_field=" + responseField,
        async: false
    }).responseText;
    if (html == "success") {        
        return true;
    }
    else {
        $("#comment_status").attr("style","");
        $("#comment_status").html(Error);
        Recaptcha.reload();
        return false;
    }
    return false;
}

Step 3: Edit layout.view, at <head> tag, add

$macros.JavaScript("recaptcha.js")

Step 4: Edit post.view, place your re-captcha in you view, remember edit YOUR-PUBLIC-KEY-HERE

<p>
      <label>
        <strong>Enter reCaptcha Code</strong>
      </label>
      <script type="text/javascript" src="http://api.recaptcha.net/challenge?k=YOUR-PUBLIC-KEY-HERE"></script>
</p>    

Step 5: Edit post.view, check code before submit at the submit button

Before: 

onclick="Comments.submitComment('$urls.Ajax');" />

After:

onclick="if(validateReCaptcha()){Comments.submitComment('$urls.Ajax');}"

Step 6: That all

Hope this help you avoid SPAM COMMENTS

PS: This is the Hack reCaptcha in my site: http://phuocle.net