How I learned to stop worrying and love the plugins

July 22nd, 2010 by Michael Pryor

I noticed that FogBugz spam on public discussion groups started heating up recently.  Apparently someone who has zombie bots (coming from all different IPs) has added them to its attack vector. Unfortunately most of the posts are ‘similar’ but not 100%, and the Bayesian filter doesn’t pick up all of them.  We’re helping this some in the next release of FogBugz by using honeypots, but the bot makers are getting smarter and that’s becoming less effective.  We really need captchas.
I have not written any code in probably six months and the dev team is working on our next major release with the interns, so I didn’t want to interrupt them to handle this.   Lucky for me, you don’t really need to know that much to implement this plugin.
  1. Start with the bare bones instructions on making a “hello world” plugin.   Your code should end up looking like so: 

     

    public class Recaptcha : Plugin
    {
    public Recaptcha(CPluginApi api)
    : base(api)
    {
    }
    }

     

  2. Make your class inherit from the IPluginDiscussTopicCommit interface (we want to make sure posts are not created if the captcha is not correct) and the IPluginDiscussTopicDisplay interface (so we can show the captcha on the page). 

     

    public class Recaptcha : Plugin, IPluginDiscussTopicCommit, IPluginDiscussTopicDisplay
    {
    public Recaptcha(CPluginApi api)
    : base(api)
    {
    }
    }

    Note: Visual Studio and Visual C# Express make adding these methods easy. Once you type IPluginDiscussTopicCommit as an interface to implement, hover over IPluginDiscussTopicCommit and the “I” will be underlined. Hover over that and a menu appears. Click the menu and choose “Implement Interface ‘IPluginDiscussTopicCommit‘” and it will create the method stubs for you!

     

  3. Head on over to the ReCaptcha site (now owned by Google) and sign up to get your private and public key.
  4. In DiscussTopicDisplayPostCreate we just return a new CDialogItem with the HTML from the ReCaptcha site.
  5. In DiscussTopicCommitBefore we just check the captcha form variables match using the ReCaptcha API.  If it matches, return true.  Else return false.
Two tricks: First, FogBugz makes it a bit obscureto read form variables that aren’t prefixed with api.GetPluginPrefix.  Thisisn’t for security; it’s so people don’t rely on FogBugz form variables as anunpublished API.  In our case, we can’t mess with the names of the inputs thatReCaptcha uses because they are tweaked at run time by a JS file downloaded fromGoogle’s servers.  But we do have jQuery in FogBugz,  so I added two linesof jQuery that rename the input fields after the Google script has run to have theAPI prefix in their name.  The other trick was just to not use the ReCaptcha ifit’s a logged in user.
Download the source:

Recaptcha.cs (4.14kb)