Preventing Comment Spam, Gallery's use of Captcha

jayp

Joined: 2005-10-24
Posts: 52
Posted: Mon, 2005-10-24 15:49

First, I hope this is the right forum to post in. Mainly I'll be throwing out suggestions, but if my understanding of something is flawed (or limited), then I could probably use some "support".

These two paragraphs are probably support related issues

The first thing I wanted to talk about is the Gallery Captcha module. I was hoping to use Captcha on guests who wanted to leave comments. From trying everything I can think of, and searching high and low in support and documentation, do I understand that is only used on the user login screen? Is there no way to have captchas show up in other places (particularly when an unregistered user wants to leave a comment)?

Another question about the Captcha module. You can set how many tries a user is allowed before a captcha is displayed. How does the browser keep track of this? (cookies, IP?). My question is really this: If over the life of an account, a user get's 3 logins incorrect, do they see a captcha from then, every time they try to login? Or, will the "counter" reset itself after different sessions? I'm asking because I tested it out and now, in internet explorer, every time I go to login, I'm presented with a captcha. That means eventually, all the users I'm setting it up for, would start seeing a captcha everytime they came to login, after (in time), they'd exceeded the number of failed attempts allowed.

These thoughts are definitely general development questions...

Here's my gripes with captcha as I see it implemented in Gallery. First, apparently I can only use it with user logins. Secondly, it's too small and unreadable! For example, the captcha that I used to register for these forums was very nice. The letters were much much larger, bold, easy to read.

This rambling of mine about Gallery's captcha is really about a larger issue - preventing comment spam.

First, Gallery is pretty dang good (I don't want to sound like I'm complaining and whining), but for me, anything that has comments and doesn't have ways to prevent comment spam is just asking to give the owner a miserable headache down the road...

There are a couple of plugins for Wordpress (open source blogging software) that I'm aware of that allow for excellent comment spam prevention.

One is called Bad Behavior (http://www.ioerror.us/software/bad-behavior/), and really isn't specific to Wordpress. I would imagine that it could be easily implemented in Gallery. It analyses the http headers to stop bots dead in their tracks. It would probably be enough to stop most comment spam dead in it's tracks.

The other is called Spam Karma 2 (http://unknowngenius.com/blog/wordpress/spam-karma/). Because it required an administrative backend, it would take some word to integrate with Gallery. But it's pretty dang cool at stopping comment spam. It basically analyses a bunch of different factors to come up with a weighted score if something's comment spam. If that score indicates the comment is questionable, it can then prompt the user for a captcha. It's a little bit of work for the admin user to configure, but it's probably the most unobtrusive for the user trying to leave a comment.

So, if anybody knows of good measures Gallery can use to prevent comment spam, I'd love to hear it. I also think that the minimum amount of work to present a good comment spam prevention measure in gallery would be to add Bad Behavior, and have a good, easy to read Captcha at the Add Comment screen.

Any thoughts from those who've been using Gallery for a while?

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Mon, 2005-10-24 18:11

the captcha module is written to be used as a plugin by other modules/views.. we'd welcome a patch to make use of the plugin from the comment module.

 
robert070612

Joined: 2003-08-05
Posts: 565
Posted: Fri, 2005-10-28 10:52

Bad Behavior and Spam Karma 2 are WordPress plugins. There is a G2 plugin to couple G2 with WordPress here. Combining the two might resolve things for you... do let us know.
----best wishes, Robert

 
kedoin

Joined: 2004-01-22
Posts: 6
Posted: Wed, 2005-11-02 18:01

I was trying out G2 yesterday for the first time and noticed that the Captcha module wasn't being used for anonymous comments. I've taken a stab at getting it to work. This is my first time trying to modify G2, so please use this modification at your own risk.

This modification will display a Captcha when the "guest" user attempts to add a comment. The Captcha will not be displayed for users who login and which to add comments.

This implementation seems to have (at least) these problems:

1) When the Captcha is displayed for the comment, if "enter" is pressed after entering the Captcha word, the page refreshes rather than saving the comment. However, if you click on "Save" the comment Captcha is validated and the comment is saved.

2) I haven't been able to reproduce this problem, but there was one time that I saw the Captcha show up when the user login screen was displayed even though I didn't think I had entered any wrong passwords. (It's supposed to show up after 3 failures, I gather) When I saw the problem occur is was in Safari, but I have no idea if that's relevant. I imagine that this could be a problem since when I use Captcha in the comment module, I set "security" to 'HIGH', but the UserLogin module uses it at 'MEDIUM'.

3) If another ValidationPlugin subclass is created, it will also be used to add the comment in addition to the Captcha.

4) I don't know if it handles Captcha not being installed gracefully. I works fine if the Captcha module is present, and disabled. But I'm not sure what will happen since I have the two relativeRequireOnce statements at the top.

Also, I could not find the proper way to submit patches, so below are "diff -c" of my changes to modules/comment/AddComment.inc and modules/comment/templates/AddComment.tpl .
-Rob

*** AddComment.inc.orig	Wed Nov  2 10:33:04 2005
--- AddComment.inc	Wed Nov  2 12:22:11 2005
***************
*** 28,33 ****
--- 28,39 ----
   */
  
  /**
+  * require necessary classes
+  */
+ GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryValidationPlugin.class');
+ GalleryCoreApi::relativeRequireOnce('modules/captcha/CaptchaValidationPlugin.inc');
+ 
+ /**
   * Add a comment to an item.
   *
   * @package Comment
***************
*** 64,69 ****
--- 70,106 ----
  	    }
  
  	    if (empty($error)) {
+ 	        /* Get all the login plugins */
+ 	        list ($ret, $pluginInstances) =
+ 		    GalleryCoreApi::getAllFactoryImplementationIds('ValidationPlugin');
+ 		if ($ret->isError()) {
+ 		    return array($ret->wrap(__FILE__, __LINE__), null);
+ 		}
+ 
+ 		foreach (array_keys($pluginInstances) as $pluginId) {
+ 		    list ($ret, $pluginInstances[$pluginId]) =
+ 		        GalleryCoreApi::newFactoryInstanceById('ValidationPlugin', $pluginId);
+ 		    if ($ret->isError()) {
+ 		        return array($ret->wrap(__FILE__, __LINE__), null);
+ 		    }
+ 		}
+ 
+ 		/* Let each plugin do its verification */
+ 		foreach ($pluginInstances as $pluginId => $plugin) {
+ 		    list ($ret, $pluginErrors, $continue) = $plugin->performValidation($form);
+ 		    if ($ret->isError()) {
+ 			return array($ret->wrap(__FILE__, __LINE__), null);
+ 		    }
+ 
+ 		    $error = array_merge($error, $pluginErrors);
+ 
+ 		    if (!$continue) {
+ 			break;
+ 		    }
+ 		}
+ 	    }
+ 
+ 	    if (empty($error)) {
  		/* Add the comment */
  		list ($ret, $comment) =
  		    GalleryCoreApi::newFactoryInstance('GalleryEntity', 'GalleryComment');
***************
*** 140,145 ****
--- 177,184 ----
       * @see GalleryView::loadTemplate
       */
      function loadTemplate(&$template, &$form) {
+ 	global $gallery;
+ 
  	/* Load our item */
  	list ($ret, $item) = $this->_getItem();
  	if ($ret->isError()) {
***************
*** 168,174 ****
  	$AddComment['host'] = GalleryUtilities::getRemoteHostAddress();
  	$AddComment['itemId'] = $item->getId();
  
- 	$template->setVariable('AddComment', $AddComment);
  	$template->setVariable('controller', 'comment.AddComment');
  
  	list($ret, $module) = GalleryCoreApi::loadPlugin('module', 'comment');
--- 207,212 ----
***************
*** 178,183 ****
--- 216,268 ----
  
  	$template->title($module->translate('Add Comment'));
  
+ 	/* Check if we are the anonymous user. If so, load up captcha */
+ 	$activeUserId = $gallery->getActiveUserId();
+ 
+ 	$userId = GalleryUtilities::getRequestVariables('userId');
+ 	if (empty($userId)) {
+ 	    $userId = $activeUserId;
+ 	}
+ 
+ 	list ($ret, $anonymousUserId) =
+ 	    GalleryCoreApi::getPluginParameter('module', 'core', 'id.anonymousUser');
+ 	if ($ret->isError()) {
+ 	    return array($ret->wrap(__FILE__, __LINE__), null);
+ 	}
+ 	if ($userId == $anonymousUserId) {
+ 	    /* See if the CaptchaValidationPlugin is installed */
+ 	    /* Get all the login plugins */
+ 	    list ($ret, $allPluginIds) =
+ 	        GalleryCoreApi::getAllFactoryImplementationIds('ValidationPlugin');
+ 	    if (! $ret->isError()) {
+ 	        /* Let Captcha load it's template data. Set security to HIGH so
+ 		 * Captcha will display immediately */
+ 	        /* Let each plugin load its template data */
+ 	        $AddComment['plugins'] = array();
+ 		foreach (array_keys($allPluginIds) as $pluginId) {
+ 		    list ($ret, $plugin) =
+ 		        GalleryCoreApi::newFactoryInstanceById('ValidationPlugin', $pluginId);
+ 		    if ($ret->isError()) {
+ 		        return array($ret->wrap(__FILE__, __LINE__), null);
+ 		    }
+ 
+ 		    list ($ret, $data['file'], $data['l10Domain']) =
+ 		        $plugin->loadTemplate($template, $form, 'HIGH');
+ 		    if ($ret->isError()) {
+ 		        return array($ret->wrap(__FILE__, __LINE__), null);
+ 		    }
+ 
+ 		    if (isset($data['file'])) {
+ 		        $AddComment['plugins'][] = $data;
+ 		    }
+ 		}
+ 	    }
+ 	    else {
+ 	      /* Ignore if Captcha not intalled */
+ 	    }
+ 	}
+ 	$template->setVariable('AddComment', $AddComment);
+ 	
  	return array(GalleryStatus::success(),
  		     array('body' => 'modules/comment/templates/AddComment.tpl'));
      }
*** templates/AddComment.tpl	Tue Jul 12 06:07:38 2005
--- templates/local/AddComment.tpl	Wed Nov  2 12:13:54 2005
***************
*** 71,76 ****
--- 71,81 ----
      {/if}
    </div>
  
+ {* Include our extra ItemAddOptions *}
+ {foreach from=$AddComment.plugins item=plugin}
+   {include file="gallery:`$plugin.file`" l10Domain=$plugin.l10Domain}
+ {/foreach}
+ 
    <div class="gbBlock gcBackground1">
      <input type="submit" class="inputTypeSubmit"
        name="{g->formVar var="form[action][preview]"}" value="{g->text text="Preview"}"/>
 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Wed, 2005-11-02 19:52

cool! i didn't look through in detail, but try it without the relativeRequireOnce calls.. the factory should load up any classes that are needed.

 
kedoin

Joined: 2004-01-22
Posts: 6
Posted: Fri, 2005-11-04 20:12

I just tried it without the relativeRequireOnce calls and it fails with the error message, "[04-Nov-2005 15:07:11] PHP Fatal error: Class captchavalidationplugin: Cannot inherit from undefined class validationplugin in /path/to/gallery/modules/captcha/CaptchaValidationPlugin.inc on line 36"

I don't know enough about how G2 works to know whether this means there's an include missing in the CaptchaValidationPlugin or if I need to make some other modifications to the AddComment.inc (or comment module)

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Fri, 2005-11-04 21:21

hm, IMO CaptchaValidationPlugin.class should have the require for its dependent class, yes.
however, other places using captcha currently have a require for GalleryValidationPlugin.class... so I'd say keep that one and remove just your require for CaptchaValidationPlugin.class

 
kedoin

Joined: 2004-01-22
Posts: 6
Posted: Sat, 2005-11-05 01:34

Success! It works fine with just the one require for GalleryValidationPlugin.

Thank you for the suggestions.

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Sat, 2005-11-05 02:29

ah, when I looked at this I noticed the file GalleryValidationPlugin defines a class called ValidationPlugin.. I renamed the class and updated the require calls too. when you get latest cvs or tomorrow's nightly snapshot you shouldn't need either require call in your file.

 
jschmittat

Joined: 2005-08-28
Posts: 25
Posted: Fri, 2005-11-11 18:32

Cool feature!

I just had to change the "ValidationPlugin" to "GalleryValidationPlugin" to make it work, don't know why but know it works:-)

mindless, it also works without the require calls. http://www.schmittat.com/gallery2/main.php

kedoin, if no ValidationPlugin is activated, it is not the if/else part that keeps it from loading. The foreach (array_keys($allPluginIds) as $pluginId) will just not be exercised. So it still works but you can delete the empty "else" part.

I also added an option in the Site Admin area where you can now decide whether you want captcha to be used or not. I included that option in the changes I made for the "Latest Comments" feature: http://gallery.menalto.com/node/39802

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Wed, 2005-11-16 20:40

This code is now integrated into comment module.. thanks!

 
jayp

Joined: 2005-10-24
Posts: 52
Posted: Mon, 2005-11-21 18:36

So here's a dumb question. (I'm still trying to understand what the procedures are for G2). When you say this code is now integrated into the comment module, does that mean I can download a newer version of the comment module and install it over my old version? Or does it mean that the next release of Gallery2 will have these changes in it?

Again, sorry if the question's a little dumb.

 
jschmittat

Joined: 2005-08-28
Posts: 25
Posted: Mon, 2005-11-21 19:25

The code is now integrated into the latest CVS Version. On the download page (http://gallery.menalto.com/downloads) look for "Nightly snapshots".

You should update your whole gallery since new and updated modules sometimes require newer versions of other modules.

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Mon, 2005-11-21 19:25

this means you can get the current nightly release of G2 from the downloads page -> nightly snapshots and it's in there.
you can also wait for the next official, super stable release, which is due early february.