Sunday, July 20, 2008

How to use Asirra CAPTCHA in ASP.NET and c#?

Problem

While back I came across Asirra - human interactive proof also known as CAPTCHA from Microsofr research lab. I decided to implement this on our site Asirra live demo. And share the code.

References used to research and learn

Asirra

Assumption

1) The reader is familiar with ASP.NET and c#.
2) Understands JavaScript.

About the project

Download: AsirraDemo.zip

New Age Solution Contact Page is protected using NoBot from Ajax Control Toolkit and Asirra CAPTCHA. This demo shows quick use of Asirra implementation.

Requirements

1) .Net 3.5
2) Visual Studio 2008

Step by step instruction

1) Unzip AsirraDemo.zip and open AsirraDemo.sln in VS2008
2) F5 run.

There are two things I would like to mention:

1) Asirra allows both Client side check and as well as server side check.

Client Side Check

<script type="text/javascript">
        var passThroughFormSubmit = false;
        function MySubmitForm()
        {
            if (passThroughFormSubmit)
            {
                return true;
            }
            // Do site-specific form validation here, then...
            Asirra_CheckIfHuman(HumanCheckComplete);
            return false;
        }
 
        function HumanCheckComplete(isHuman)
        {
            if (!isHuman)
            {
                alert("Please correctly identify the cats.");
            }
            else
            {
                passThroughFormSubmit = true;
                formElt = document.getElementById("mainForm");
                formElt.submit();
            }
        }
    </script>


Server Side Check

private const string ASIRRA_SERVICE_URL = "http://challenge.asirra.com/cgi/Asirra";
 
        private void ValidateAsirraChallenge()
        {
            // Assira restful service
            string ticket = Request.QueryString.GetValues("Asirra_Ticket")[0];
            string validationURL = ASIRRA_SERVICE_URL + "?action=ValidateTicket&ticket=" + ticket;
            System.Xml.XmlTextReader validationTextReader = new System.Xml.XmlTextReader(validationURL);
            System.Xml.XmlDocument validationDocument = new System.Xml.XmlDocument();
            validationDocument.Load(validationTextReader);
 
            // Pass
            string validationValue = validationDocument.GetElementsByTagName("Result")[0].ChildNodes[0].Value;
            if (validationValue == "Pass")
            {
                return;
            }
 
            /// Fail and extract reason
            string result = "unknown captcha failure";
            result = validationDocument.GetElementsByTagName("Debug")[0].ChildNodes[0].Value;
 
            throw (new Exception("Asirra Error: " + result));
        }


2) In order to make 12 animals to fit properly in the box I had to figure out how to resize the bax using CSS.

#asirra_LayoutTable
{
    width: 315px;
}
 
#asirra_InstructionsTextId
{
    color:#af27dd; 
    font-size:10px; 
}


In order to apply better looking CSS you need to dig in deeper into AsirraClientSide.js. Below code is how AsirraClientSide.js renders HTML.

var myHTML = '';
myHTML += '<div  id="asirra_MainDiv" style="text-align: left; width: 400px">\n';
myHTML += '    <table cellpadding="0" cellspacing="0" id="asirra_LayoutTable">\n';
myHTML += '        <tr colspan=2>\n';
myHTML += '            <div class="InstructionsTextClass" id="asirra_InstructionsTextId">\n';
myHTML += '                Please select all the cat photos:\n';
myHTML += '            </div>\n';
myHTML += '        </tr>\n';
myHTML += '        <tr>\n';
myHTML += '            <td>\n';
myHTML += '                <div\n';
myHTML += '                    style="position: relative; border: 1px solid #595959; padding: 3px 3px 3px 3px"\n';
myHTML += '                    id="asirra_ChallengeTableDiv">\n';
myHTML += '                    <!-- top: -20px ignores variable font size. For some reason it just works anyway in IE, and z-index: 10 keeps it on top in FF. Wish IEs z-index actually worked. -->\n';
myHTML += '                        <table cellpadding="0" cellspacing="3" border="0" id="asirra_ChallengeTable" style="position: relative">\n';
myHTML += '                            <tbody align="center" valign="center" cellspacing="0" id="asirra_ChallengeTableBody">\n';
myHTML += '                            </tbody>\n';
myHTML += '                        </table>\n';
myHTML += '                </div>\n';
myHTML += '            </td>\n';
myHTML += '            <td width="15px">\n';
myHTML += '                &nbsp;\n';
myHTML += '            </td>\n';
myHTML += '            <td valign=top>\n';
myHTML += '                <table id="asirra_KnobsTable">\n';
myHTML += '                    <tr>\n';
myHTML += '                        <td>\n';
myHTML += '                            <a href="javascript:asirraState.GetChallenge()"\n';
myHTML += '                                title="Request different images.">\n';
myHTML += '                                <img width="22" height="22" id="asirra_HipReloadImg" border=0>\n';
myHTML += '                            </a>\n';
myHTML += '                        </td>\n';
myHTML += '                    </tr>\n';
myHTML += '                    <tr>\n';
myHTML += '                        <td>\n';
myHTML += '                            <a href="http://research.microsoft.com/asirra/whatsthis.html"\n';
myHTML += '                                title="What is this?"\n';
myHTML += '                                target="_blank" rel="external"><img border=0 width="22" height="22" id="asirra_HipHelpImg"></a>\n';
myHTML += '                        </td>\n';
myHTML += '                    </tr>\n';
myHTML += '                </table>\n';
myHTML += '            </td>\n';
myHTML += '            <td valign=top>\n';
myHTML += '                <div id="asirra_EnlargedPositionRightCell">\n';
myHTML += '                </div>\n';
myHTML += '            </td>\n';
myHTML += '        </tr>\n';
myHTML += '    </table>\n';
myHTML += '    <div id="asirra_EnlargedDivContainer"\n';
myHTML += '        style="z-index: 2; height: 12; width: 0; text-align: center; position: relative">\n';
myHTML += '        <div id="asirra_EnlargedDiv"\n';
myHTML += '            style="visibility: hidden; position: absolute; width: 250; height: 250; border: 1px solid #595959; background-color: #ffffff">\n';
myHTML += '            <div id="asirra_EnlargedDivOverlay"\n';
myHTML += '                style="position: absolute; width: 250; height: 250; background-color: transparent;" >\n';
myHTML += '                <table width="100%" height="100%" border=0\n';
myHTML += '                    style="background-color: transparent;"\n';
myHTML += '                    ><tr><td valign=bottom align=center\n';
myHTML += '                    style="background-color: transparent; vertical-align: bottom;">\n';
myHTML += '                    <img src="//challenge.asirra.com/images/ImageFromPetfinderDotCom.gif" width=246 height=24>\n';
myHTML += '                </td></tr></table>\n';
myHTML += '            </div>\n';
myHTML += '            <img>\n';
myHTML += '        </div>\n';
myHTML += '    </div>\n';
myHTML += '\n';
myHTML += '    <div style="display:None;" id="Asirra_CellPrototypeDiv">\n';
myHTML += '        <div\n';
myHTML += '                onmouseover="asirraState.Enlarge(event)"\n';
myHTML += '                onmouseout="asirraState.Unenlarge()"\n';
myHTML += '                onclick="asirraState.Image_Selected();"\n';
myHTML += '                style="cursor: pointer;"\n';
myHTML += '        >\n';
myHTML += '            <div style="position: relative; top: 0px; left: 0px; width: 40px; height: 40px"\n';
myHTML += '            >\n';
myHTML += '                <div style="position: absolute; top: 0px; left: 0px;">\n';
myHTML += '                    <img id="imgProto">\n';
myHTML += '                </div>\n';
myHTML += '                <div style="position: absolute; top: 0px; left: 0px; display:block">\n';
myHTML += '                    <img id="asirra_borderImgProto">\n';
myHTML += '                </div>\n';
myHTML += '            </div>\n';
myHTML += '            <div style="visibility: hidden">\n';
myHTML += '                <a href="adopt"\n';
myHTML += '                    onclick="javascript:asirraState.GetChallenge();"\n';
myHTML += '                    target="_blank"\n';
myHTML += '                    rel="external"><font size=-1>Adopt me</font></a>\n';
myHTML += '            </div>\n';
myHTML += '        </div>\n';
myHTML += '    </div>\n';
myHTML += '</div>\n';
myHTML += '\n';


Conclusion

One of my dogs, Maggie was rescued from the shelter and I find Asirra great way to expose animals that need home. Also makes your site look way cooler I think!

1 comment:

Anonymous said...

cool - works thanks (apart from te CSS which goes screwy in IE8). Thanks again