| 1 | # A plugin for filtering Comment and TBPing Spams |
|---|
| 2 | # |
|---|
| 3 | # Release 0.20 (Apr 8, 2005) |
|---|
| 4 | # |
|---|
| 5 | # This software is provided as-is. You may use it for commercial or |
|---|
| 6 | # personal use. If you distribute it, please keep this notice intact. |
|---|
| 7 | # |
|---|
| 8 | # Copyright (c) 2005 Hirotaka Ogawa |
|---|
| 9 | |
|---|
| 10 | package MT::Plugin::Quasi_SpamFilter; |
|---|
| 11 | use strict; |
|---|
| 12 | use vars qw($COMMENT_PATTERN $COMMENT_METHOD |
|---|
| 13 | $TBPING_PATTERN $TBPING_METHOD |
|---|
| 14 | $ENABLE_LOGGING |
|---|
| 15 | $URL %comment_methods %tbping_methods); |
|---|
| 16 | |
|---|
| 17 | # Set your spam pattern |
|---|
| 18 | $COMMENT_PATTERN = '<h1>|<a\s'; # H1 or A elements |
|---|
| 19 | $TBPING_PATTERN = '<h1>|<a\s'; # H1 or A elements |
|---|
| 20 | |
|---|
| 21 | # Choose a method for rejecting Spam Comments from: |
|---|
| 22 | # 'CommentFilter', 'CommentThrottleFilter', 'CommentError', |
|---|
| 23 | # 'CommentLongError', 'CommentRedirect', 'CommentEvilRedirect' |
|---|
| 24 | $COMMENT_METHOD = 'CommentError'; |
|---|
| 25 | |
|---|
| 26 | # Choose a method for rejecting Spam Pings from: |
|---|
| 27 | # 'TBPingFilter', 'TBPingThrottleFilter', 'TBPingError' |
|---|
| 28 | $TBPING_METHOD = 'TBPingError'; |
|---|
| 29 | |
|---|
| 30 | # Set your Redirect URL (for 'CommentRedirect' and 'CommentEvilRedirect') |
|---|
| 31 | $URL = 'http://www.2ch.net/'; |
|---|
| 32 | |
|---|
| 33 | # Enable logging? (1/0) |
|---|
| 34 | $ENABLE_LOGGING = 1; |
|---|
| 35 | |
|---|
| 36 | eval("use Storable;"); |
|---|
| 37 | if (!$@ && MT->can('add_plugin')) { |
|---|
| 38 | require MT::Plugin; |
|---|
| 39 | my $plugin = new MT::Plugin(); |
|---|
| 40 | $plugin->name("Quasi Spam Filter Plugin 0.20"); |
|---|
| 41 | $plugin->description("A Simple filter for Comment & TBPing Spams"); |
|---|
| 42 | $plugin->doc_link("http://as-is.net/hacks/2005/01/quasi_spam_filter_plugin.html"); |
|---|
| 43 | MT->add_plugin($plugin); |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | %comment_methods = ( |
|---|
| 47 | 'CommentFilter' => 'comment_filter', |
|---|
| 48 | 'CommentThrottleFilter' => 'comment_throttle_filter', |
|---|
| 49 | 'CommentError' => 'comment_error', |
|---|
| 50 | 'CommentLongError' => 'comment_long_error', |
|---|
| 51 | 'CommentRedirect' => 'comment_redirect', |
|---|
| 52 | 'CommentEvilRedirect' => 'comment_evil_redirect' |
|---|
| 53 | ); |
|---|
| 54 | |
|---|
| 55 | %tbping_methods = ( |
|---|
| 56 | 'TBPingFilter' => 'tbping_filter', |
|---|
| 57 | 'TBPingThrottleFilter' => 'tbping_throttle_filter', |
|---|
| 58 | 'TBPingError' => 'tbping_error' |
|---|
| 59 | ); |
|---|
| 60 | |
|---|
| 61 | if (defined(my $method = $comment_methods{$COMMENT_METHOD})) { |
|---|
| 62 | if ($COMMENT_METHOD =~ /Filter$/ && MT->can('add_callback')) { |
|---|
| 63 | MT->add_callback($COMMENT_METHOD, 10, 'Reject Spam Comments', \&$method); |
|---|
| 64 | } else { |
|---|
| 65 | *MT::App::Comments::pre_run = \&$method; |
|---|
| 66 | } |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | if (defined(my $method = $tbping_methods{$TBPING_METHOD})) { |
|---|
| 70 | if ($TBPING_METHOD =~ /Filter$/ && MT->can('add_callback')) { |
|---|
| 71 | MT->add_callback($TBPING_METHOD, 10, 'Reject Spam TBPings', \&$method); |
|---|
| 72 | } else { |
|---|
| 73 | *MT::App::Trackback::pre_run = \&$method; |
|---|
| 74 | } |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | use MT::Comment; |
|---|
| 78 | use MT::TBPing; |
|---|
| 79 | |
|---|
| 80 | sub is_comment_spam { |
|---|
| 81 | my $comment = shift; |
|---|
| 82 | return ($comment->text =~ /$COMMENT_PATTERN/i); |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | sub is_tbping_spam { |
|---|
| 86 | my $tbping = shift; |
|---|
| 87 | return ($tbping->excerpt =~ /$TBPING_PATTERN/i); |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | sub _make_pseudo_comment { |
|---|
| 91 | my $app = shift; |
|---|
| 92 | my $q = $app->{query}; |
|---|
| 93 | my $comment = MT::Comment->new; |
|---|
| 94 | $comment->author($q->param('author') || ''); |
|---|
| 95 | $comment->email($q->param('email') || ''); |
|---|
| 96 | $comment->url($q->param('url') || ''); |
|---|
| 97 | $comment->text($q->param('text') || ''); |
|---|
| 98 | $comment->ip($app->remote_ip || ''); |
|---|
| 99 | return $comment; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | sub _make_pseudo_tbping { |
|---|
| 103 | my $app = shift; |
|---|
| 104 | my $q = $app->{query}; |
|---|
| 105 | my $tbping = MT::TBPing->new; |
|---|
| 106 | $tbping->title($q->param('title') || ''); |
|---|
| 107 | $tbping->excerpt($q->param('excerpt') || ''); |
|---|
| 108 | $tbping->source_url($q->param('url') || ''); |
|---|
| 109 | $tbping->blog_name($q->param('blog_name') || ''); |
|---|
| 110 | $tbping->ip($app->remote_ip || ''); |
|---|
| 111 | return $tbping; |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | sub comment_filter { |
|---|
| 115 | my ($eh, $app, $comment) = @_; |
|---|
| 116 | if (is_comment_spam($comment)) { |
|---|
| 117 | $app->log("[QSF] drop a spam comment from " . $comment->author) if $ENABLE_LOGGING; |
|---|
| 118 | return 0; |
|---|
| 119 | } |
|---|
| 120 | return 1; |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | sub comment_throttle_filter { |
|---|
| 124 | my ($eh, $app, $entry) = @_; |
|---|
| 125 | my $comment = _make_pseudo_comment($app); |
|---|
| 126 | if (is_comment_spam($comment)) { |
|---|
| 127 | $app->log("[QSF] drop a spam comment from " . $comment->author) if $ENABLE_LOGGING; |
|---|
| 128 | return 0; |
|---|
| 129 | } |
|---|
| 130 | return 1; |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | sub comment_error { |
|---|
| 134 | my $app = shift; |
|---|
| 135 | my $q = $app->{query}; |
|---|
| 136 | my $mode = $q->param('__mode') || $app->{default_mode}; |
|---|
| 137 | return if $mode ne 'post'; |
|---|
| 138 | my $comment = _make_pseudo_comment($app); |
|---|
| 139 | if (is_comment_spam($comment)) { |
|---|
| 140 | $app->add_methods(post => sub { }); |
|---|
| 141 | $app->error("Spam Comment!"); |
|---|
| 142 | $app->log("[QSF] drop a spam comment from " . $comment->author) if $ENABLE_LOGGING; |
|---|
| 143 | } |
|---|
| 144 | } |
|---|
| 145 | |
|---|
| 146 | sub comment_long_error { |
|---|
| 147 | my $app = shift; |
|---|
| 148 | my $q = $app->{query}; |
|---|
| 149 | my $mode = $q->param('__mode') || $app->{default_mode}; |
|---|
| 150 | return if $mode ne 'post'; |
|---|
| 151 | my $comment = _make_pseudo_comment($app); |
|---|
| 152 | if (is_comment_spam($comment)) { |
|---|
| 153 | $app->add_methods(post => sub { $_[0]->handle_error("Spam Comments!") }); |
|---|
| 154 | $app->log("[QSF] drop a spam comment from " . $comment->author) if $ENABLE_LOGGING; |
|---|
| 155 | } |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | sub comment_redirect { |
|---|
| 159 | my $app = shift; |
|---|
| 160 | my $q = $app->{query}; |
|---|
| 161 | my $mode = $q->param('__mode') || $app->{default_mode}; |
|---|
| 162 | return if $mode ne 'post'; |
|---|
| 163 | my $comment = _make_pseudo_comment($app); |
|---|
| 164 | if (is_comment_spam($comment)) { |
|---|
| 165 | $app->add_methods(post => sub { }); |
|---|
| 166 | $app->redirect($URL); |
|---|
| 167 | $app->log("[QSF] drop a spam comment from " . $comment->author) if $ENABLE_LOGGING; |
|---|
| 168 | } |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | sub comment_evil_redirect { |
|---|
| 172 | my $app = shift; |
|---|
| 173 | my $q = $app->{query}; |
|---|
| 174 | my $mode = $q->param('__mode') || $app->{default_mode}; |
|---|
| 175 | return if $mode ne 'post'; |
|---|
| 176 | my $comment = _make_pseudo_comment($app); |
|---|
| 177 | if (is_comment_spam($comment)) { |
|---|
| 178 | $app->add_methods(post => sub { }); |
|---|
| 179 | $app->redirect($q->param('url') || $URL); |
|---|
| 180 | $app->log("[QSF] drop a spam comment from " . $comment->author) if $ENABLE_LOGGING; |
|---|
| 181 | } |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | sub tbping_filter { |
|---|
| 185 | my ($eh, $app, $tbping) = @_; |
|---|
| 186 | if (is_tbping_spam($tbping)) { |
|---|
| 187 | $app->log("[QSF] drop a spam tbping from " . $tbping->blog_name) if $ENABLE_LOGGING; |
|---|
| 188 | return 0; |
|---|
| 189 | } |
|---|
| 190 | return 1; |
|---|
| 191 | } |
|---|
| 192 | |
|---|
| 193 | sub tbping_throttle_filter { |
|---|
| 194 | my ($eh, $app, $tb) = @_; |
|---|
| 195 | my $tbping = _make_pseudo_tbping($app); |
|---|
| 196 | if (is_tbping_spam($tbping)) { |
|---|
| 197 | $app->log("[QSF] drop a spam tbping from " . $tbping->blog_name) if $ENABLE_LOGGING; |
|---|
| 198 | return 0; |
|---|
| 199 | } |
|---|
| 200 | return 1; |
|---|
| 201 | } |
|---|
| 202 | |
|---|
| 203 | sub tbping_error { |
|---|
| 204 | my $app = shift; |
|---|
| 205 | my $q = $app->{query}; |
|---|
| 206 | my $mode = $q->param('__mode') || $app->{default_mode}; |
|---|
| 207 | return if $mode ne 'ping'; |
|---|
| 208 | my $tbping = _make_pseudo_tbping($app); |
|---|
| 209 | if (is_tbping_spam($tbping)) { |
|---|
| 210 | $app->add_methods('ping' => sub { }); |
|---|
| 211 | $app->_response(Error => 'Spam TBPing!', Code => 403); |
|---|
| 212 | $app->log("[QSF] drop a spam tbping from " . $tbping->blog_name) if $ENABLE_LOGGING; |
|---|
| 213 | } |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | 1; |
|---|