Blogengine.NET Recaptcha 0.91 Installation Instructions

by Filip Stanek 20. February 2010 23:27

NOTE: THESE INSTALLATION INSTRUCTIONS HAVE BEEN UPDATED: To get the latest version, follow the instructions located at: http://www.bloodforge.com/post/BlogengineNET-reCaptcha-093-Installation-Instructions.aspx

First, the linked ZIP file contains the updated files for installing the Recaptcha control.

UPDATES:

  • Version 0.92 - The recaptcha will no longer get focus after it has been loaded. Install procedure is unchanged from version 0.91.
  • Version 0.91 - Changed the way that Recaptcha is verified.  It should no longer be possible to bypass the recaptcha by manually executing JavaScript on the page.
  • Version 0.9 - Initial Version

Quick Installation

First, back up your files in case you need to revert for any reason. If you have not modified any of the BlogEngine files, you can extract the ZIP linked to above and place all of the files into their proper locations ( the unzipped files should contain a folder structure ). There is no need to recompile.

You may need to force a refresh of your browser on the site, since there is a JavaScript file updated, and most browsers like to cache these files.

Manual Installation

Below is a complete summary of what needs to be altered to make the Recaptcha control work.  You’ll need to do this for any files manually modified in your BlogEngine.NET instance.

/App_Code/Controls/Recaptcha.cs

This file was not included in the BlogEngine.NET installation, and should be placed in the ‘/App_Code/Controls/’ folder.

/blog.js

There are three functions in this file that need to be updated to the following:

onCommentError: function(error, context) {
        BlogEngine.toggleCommentSavingIndicators(false);
        error = error || "Unknown error occurred.";
        var iDelimiterPos = error.indexOf("|");
        if (iDelimiterPos > 0) {
            error = error.substr(0, iDelimiterPos);
            // Remove numbers from end of error message.
            while (error.length > 0 && error.substr(error.length - 1, 1).match(/\d/)) {
                error = error.substr(0, error.length - 1);
            }
        }
        
        if( document.getElementById('recaptcha_response_field') )
        {
           Recaptcha.reload();
        }
 
        alert("Sorry, the following error occurred while processing your comment:\n\n" + error);
    }
addComment: function(preview) {
        var isPreview = preview == true;
        if (!isPreview) {
            BlogEngine.toggleCommentSavingIndicators(true);
            this.$("status").innerHTML = BlogEngine.i18n.savingTheComment;
        }
 
        var author = BlogEngine.comments.nameBox.value;
        var email = BlogEngine.comments.emailBox.value;
        var website = BlogEngine.comments.websiteBox.value;
        var country = BlogEngine.comments.countryDropDown ? BlogEngine.comments.countryDropDown.value : "";
        var content = BlogEngine.comments.contentBox.value;
        var notify = BlogEngine.$("cbNotify").checked;
        var captcha = BlogEngine.comments.captchaField.value;
        var replyToId = BlogEngine.comments.replyToId ? BlogEngine.comments.replyToId.value : "";
        
        var recaptchaResponseField = document.getElementById('recaptcha_response_field');        
        var recaptchaResponse = recaptchaResponseField ? recaptchaResponseField.value : "";
        
        var recaptchaChallengeField = document.getElementById('recaptcha_challenge_field');
        var recaptchaChallenge = recaptchaChallengeField ? recaptchaChallengeField.value : "";
 
        var avatarInput = BlogEngine.$("avatarImgSrc");
        var avatar = (avatarInput && avatarInput.value) ? avatarInput.value : "";
 
        var callback = isPreview ? BlogEngine.endShowPreview : BlogEngine.appendComment;
        var argument = author + "-|-" + email + "-|-" + website + "-|-" + country + "-|-" + content + "-|-" + notify + "-|-" + isPreview + "-|-" + captcha + "-|-" + replyToId + "-|-" + avatar + "-|-" + recaptchaResponse + "-|-" + recaptchaChallenge;
 
        WebForm_DoCallback(BlogEngine.comments.controlId, argument, callback, 'comment', BlogEngine.onCommentError, false);
 
        if (!isPreview && typeof (OnComment) != "undefined")
            OnComment(author, email, website, country, content);
    }
appendComment: function(args, context) {
        if (context == "comment") {
        
            if( document.getElementById('recaptcha_response_field') )
            {
               Recaptcha.reload();
            }
        
            if( args == "RecaptchaIncorrect" )
            {
               if( document.getElementById("spnCaptchaIncorrect") ) document.getElementById("spnCaptchaIncorrect").style.display = "";
               BlogEngine.toggleCommentSavingIndicators(false);
            }
            else
            {
            
                if( document.getElementById("spnCaptchaIncorrect") ) document.getElementById("spnCaptchaIncorrect").style.display = "none";
 
                var commentList = BlogEngine.$("commentlist");
                if (commentList.innerHTML.length < 10)
                    commentList.innerHTML = "<h1 id='comment'>" + BlogEngine.i18n.comments + "</h1>"
 
                // add comment html to the right place
                var id = BlogEngine.comments.replyToId ? BlogEngine.comments.replyToId.value : '';
 
                if (id != '') {
                    var replies = BlogEngine.$('replies_' + id);
                    replies.innerHTML += args;
                } else {
                    commentList.innerHTML += args;
                    commentList.style.display = 'block';
                }
 
                // reset form values
                BlogEngine.comments.contentBox.value = "";
                BlogEngine.comments.contentBox = BlogEngine.$(BlogEngine.comments.contentBox.id);
                BlogEngine.toggleCommentSavingIndicators(false);
                BlogEngine.$("status").className = "success";
 
                if (!BlogEngine.comments.moderation)
                    BlogEngine.$("status").innerHTML = BlogEngine.i18n.commentWasSaved;
                else
                    BlogEngine.$("status").innerHTML = BlogEngine.i18n.commentWaitingModeration;
 
                // move form back to bottom
                var commentForm = BlogEngine.$('comment-form');
                commentList.appendChild(commentForm);
                // reset reply to
                if (BlogEngine.comments.replyToId) BlogEngine.comments.replyToId.value = '';
                if (BlogEngine.$('cancelReply')) BlogEngine.$('cancelReply').style.display = 'none';
            
            }
        }
 
        BlogEngine.$("btnSaveAjax").disabled = false;
    }

/User controls/CommentView.ascx.cs

One method in this file needs to be updated:

/// <summary>
    /// Processes a callback event that targets a control.
    /// </summary>
    /// <param name="eventArgument">A string that represents an event argument to pass to the event handler.</param>
    public void RaiseCallbackEvent(string eventArgument)
    {
        if (!BlogSettings.Instance.IsCommentsEnabled)
            return;
 
        string[] args = eventArgument.Split(new string[] { "-|-" }, StringSplitOptions.None);
        string author = args[0];
        string email = args[1];
        string website = args[2];
        string country = args[3];
        string content = args[4];
        bool notify = bool.Parse(args[5]);
        bool isPreview = bool.Parse(args[6]);
        string sentCaptcha = args[7];
        //If there is no "reply to" comment, args[8] is empty
        Guid replyToCommentID = String.IsNullOrEmpty(args[8]) ? Guid.Empty : new Guid(args[8]);
        string avatar = args[9];
 
        string recaptchaResponse = args[10];
        string recaptchaChallenge = args[11];
 
        if (!isPreview && recaptcha.RecaptchaEnabled && recaptcha.RecaptchaNecessary)
        {
            if (!recaptcha.ValidateAsync(recaptchaResponse, recaptchaChallenge))
            {
                _Callback = "RecaptchaIncorrect";
                return;
            }
        }
 
        string storedCaptcha = hfCaptcha.Value;
 
        if (sentCaptcha != storedCaptcha)
            return;
 
        Comment comment = new Comment();
        comment.Id = Guid.NewGuid();
        comment.ParentId = replyToCommentID;
        comment.Author = Server.HtmlEncode(author);
        comment.Email = email;
        comment.Content = Server.HtmlEncode(content);
        comment.IP = Request.UserHostAddress;
        comment.Country = country;
        comment.DateCreated = DateTime.Now;
        comment.Parent = Post;
        comment.IsApproved = !BlogSettings.Instance.EnableCommentsModeration;
        comment.Avatar = avatar.Trim();
 
        if (Page.User.Identity.IsAuthenticated)
            comment.IsApproved = true;
 
        if (website.Trim().Length > 0)
        {
            if (!website.ToLowerInvariant().Contains("://"))
                website = "http://" + website;
 
            Uri url;
            if (Uri.TryCreate(website, UriKind.Absolute, out url))
                comment.Website = url;
        }
 
        if (!isPreview)
        {
            if (notify && !Post.NotificationEmails.Contains(email))
                Post.NotificationEmails.Add(email);
            else if (!notify && Post.NotificationEmails.Contains(email))
                Post.NotificationEmails.Remove(email);
 
            Post.AddComment(comment);
            SetCookie(author, email, website, country);
        }
 
        string path = Utils.RelativeWebRoot + "themes/" + BlogSettings.Instance.Theme + "/CommentView.ascx";
 
        CommentViewBase control = (CommentViewBase)LoadControl(path);
        control.Comment = comment;
        control.Post = Post;
 
        using (StringWriter sw = new StringWriter())
        {
            control.RenderControl(new HtmlTextWriter(sw));
            _Callback = sw.ToString();
        }
    }

/User controls/CommentView.ascx

Finally, the following line needs to be added to this file, at the location you would like the Recaptcha control to appear. Remember to update your TabIndexes for proper tab button navigation.

<blog:RecaptchaControl ID="recaptcha" runat="server" TabIndex="8" />

Recaptcha Settings

You can edit the Recaptcha settings via the Extension Manager. You probably should enter in your own Public and Private keys, as the provided keys are for this site ( they are global, so they will work on other sites ).

Recaptcha Theming

There are 4 built-in themes that you can change via the ExtensionManager. You can also create your own theme by adding it in the following way to the Recaptcha control:

<blog:RecaptchaControl ID="recaptcha" runat="server" TabIndex="8" Theme="MyCustomTheme" />

For detailed instructions on what your theme needs to look like, visit the Recaptcha site.

Tags: , , , , , ,

Web Development

Comments

  • Trackbacks (2)
  • Comments (11)

+0 Vote Up     Vote Down # adrian on 2/21/2010 5:32:24 AM

adrian

Hello Filip,

I've added your recaptcha solution to my blog and it seems to run great. Many thanks for your work. Smile
I've modified it a little bit for my blog, as I have a SSL side on the blog too. In order to get rid of browser warnings in the Recaptcha.cs file I've modified as:
recaptchaAjaxScript.Attributes.Add("src", "api-secure.recaptcha.net/.../...ha_ajax.js");
and
urlBuilder.Append(Context.Request.IsSecureConnection ? RECAPTCHA_SECURE_HOST : RECAPTCHA_SECURE_HOST);

As a small observation, with the recaptcha in place, when clicking on a blog post link, in goes straight to the comments, which may not be what an user wants, maybe it just wants to read the blog post.

Cheers!
--Adrian

Reply

+0 Vote Up     Vote Down # Filip United States on 2/21/2010 4:36:43 PM

Filip

Adrian,
I've put in a fix to the issue you were seeing with the focus on the comments ( the focus was actually going on the response field in the recaptcha ).  The following changes are needed to fix the problem.

In Recaptcha.cs, the following lines:

output.WriteLine("tabindex: {0},", TabIndex.ToString());
output.WriteLine("callback: Recaptcha.focus_response_field  });");


need to be replaced with:

output.WriteLine("tabindex: {0}", TabIndex.ToString());
output.WriteLine("})");


I have updated the files on this page with this latest fix.

Reply

+0 Vote Up     Vote Down # adrian on 2/22/2010 4:05:20 AM

adrian

Thanks, Filip, I've made the changes, and looks good now.
The recaptcha already made a huge impact on my blog regarding the amount of spam received, so I think it's a great addition to BlogEngine.NET.

Cheers!
--Adrian

Reply

+0 Vote Up     Vote Down # Speed dating New York United States on 2/27/2010 5:06:37 AM

Speed dating New York

The installation was easy. We use it at http : // www [DOT] nyminutedating [dot]com/tellafriend [dot]aspx

Reply

+0 Vote Up     Vote Down # Filip United States on 2/27/2010 6:27:58 AM

Filip

Nice try. Generally, I will delete SPAM on sight, but I will give you some points for creativity here. I actually find your post very funny.

a: I wrote the code to integrate this into BlogEngine.NET.  Wouldn't you think I'd know if someone used this code on their own webpage? I can tell pretty easily by looking at your page source that you did not.

b: Didn't I mention that this was for BlogEngine.NET?

c: Some free advice: ditch Dreamweaver and learn about theming and skinning in ASP.NET

P.S. Yes, I did change your URL. Sorry, but no Google rank for you from this site.

Reply

+0 Vote Up     Vote Down # plc programming United States on 5/3/2010 7:16:20 PM

plc programming

thanks for the installation guidelines and codes

Reply

+0 Vote Up     Vote Down # annuaire France on 8/26/2010 9:09:34 AM

annuaire

This is useful for an easy and fast installation. Thanks

Reply

+0 Vote Up     Vote Down # HostGator United States on 9/1/2010 2:15:33 AM

HostGator

The recaptcha already made a huge impact on my blog regarding the amount of spam received, so I think it's a great addition to BlogEngine.NET.

Reply

+0 Vote Up     Vote Down # meeting brazilian women United States on 9/1/2010 10:24:00 AM

meeting brazilian women

Instead of using generic websites such as Harmony and Match go straight to brazilianhouse.com. They are specializing in Brazilian partners. What best to find everything you are looking for in a single place?

Reply

+0 Vote Up     Vote Down # coach bags People's Republic of China on 9/4/2010 2:49:51 AM

coach bags

http://www.coach-bags-outlet.com/ coach bags outlet
http://www.chanelbags2010.com/ chanel bags
www.coach-bags-outlet.com/coach-handbags-c-9.html   coach handbags
www.coach-bags-outlet.com/...baby-bags-c-9_40.html   Coach Baby Bags
www.coach-bags-outlet.com/...pack-bags-c-9_42.html   Coach Backpack Bags
www.coach-bags-outlet.com/...arly-bags-c-9_28.html   Coach Backpack Bags
www.coach-bags-outlet.com/...arly-bags-c-9_28.html   Coach Carly Bags
www.coach-bags-outlet.com/...aire-bags-c-9_29.html   Coach Claire Bags
www.coach-bags-outlet.com/...ergo-bags-c-9_38.html     Coach Ergo Bags
www.coach-bags-outlet.com/...rnet-bags-c-9_30.html  Coach Garnet Bags
www.coach-bags-outlet.com/...pton-bags-c-9_31.html  Coach Hampton Bags
www.coach-bags-outlet.com/...hobo-bags-c-9_39.html   Coach HOBO Bags
www.coach-bags-outlet.com/...-handbags-c-9_32.html   Coach Leather Handbags
www.coach-bags-outlet.com/...gage-bags-c-9_43.html    Coach Luggage Bags
www.coach-bags-outlet.com/...ggie-bags-c-9_41.html   Coach Maggie Bags
www.coach-bags-outlet.com/...ork-purse-c-9_26.html   Coach Patchwork Purse
www.coach-bags-outlet.com/...rina-bags-c-9_33.html   Coach Sabrina Bags
www.coach-bags-outlet.com/...lder-bags-c-9_25.html    Coach Shoulder Bags
www.coach-bags-outlet.com/...ling-bags-c-9_44.html   Coach Sling Bags
www.coach-bags-outlet.com/...ight-bags-c-9_34.html   Coach Spotlight Bags
www.coach-bags-outlet.com/...tote-bags-c-9_27.html   Coach Tote Bags
www.coach-bags-outlet.com/...avel-bags-c-9_35.html   Coach Travel Bags
www.coach-bags-outlet.com/...beca-bags-c-9_36.html   Coach Tribeca Bags
www.coach-bags-outlet.com/...-handbags-c-9_37.html  New Coach Handbags
www.chanelbags2010.com/chanel-handbags-c-10.html/  Chanel Handbags
www.chanelbags2010.com/.../  Chanel Luggage
www.chanelbags2010.com/.../  Chanel Backpack Bags
www.chanelbags2010.com/.../  Chanel Cambon Bags
www.chanelbags2010.com/.../  Chanel Flap Bags
www.chanelbags2010.com/.../  New Chanel Handbags
www.chanelbags2010.com/.../  Chanel Hobo Bags
www.chanelbags2010.com/.../  Chanel Tote Bags
www.chanelbags2010.com/.../  Chanel Travel Bags
www.chanelbags2010.com/chanel-wallets-c-37.html/  Chanel Wallets

Reply

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading




Tag cloud

About Filip Stanek

Death Note Pic I'm a developer at ACG Multimedia in Cincinnati, OH. Besides working with ASP.NET, Flash, and other web technologies, I enjoy playing chess, video games, etc.

Currently playing:
- Final Fantasy XIII
E-mail me Send mail

Recent Comments

Comment RSS

Month List

Page List