SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|

2012-07-07(Sat) tDiary用簡易CAPTCHA

  よく考えたら、こういうのをCAPTCHAといっていいのかわからんが、まぁ、コメントスパムを拒否するのに十分な効果はあるのでよしとする。

  まずは、フィルタ側。

 ・/usr/local/share/tdiary/misc/filter/tcaptcha.rb
 
 # -*- coding: utf-8; -*-
 
 require 'digest/md5'
 
 module TDiary
     module Filter
         class TcaptchaFilter < Filter
             def comment_filter( diary, comment )
 
                 common_key = 'abc'              # 任意の文字列(プラグイン側と合わせる)
 
                 rw = @cgi.params['tcaptcha'].dup
                 dm = Digest::MD5.hexdigest((rw << common_key).sort.join(':'))
 
                 $stdout.sync = 1
 
                 if(result = (@cgi.params['tcaptcha_digest'][0] == dm))
 # =begin            # 強引なメッセージの出し方をするので、クッキーを食わせられなくなる
                     print "Content-Type: text/html\n\n"
                     print "<HTML><HEAD><META http-equiv='Content-Type' content='text/html; charset=UTF-8'></HEAD><BODY>\n"
                     print "<H1>Thank you for your comment</H1>\n"
                     print "<P>コメントありがとうございました。</P>\n"
                     sleep 5
 # =end
                 else
                     print "Status: 406 Not Acceptable\n"
                     print "Content-Type: text/html\n\n"
                     print "<HTML><HEAD><META http-equiv='Content-Type' content='text/html; charset=UTF-8'></HEAD><BODY>\n"
                     print "<H1>Tiny CAPTCHA challenge failed</H1>\n"
                     print "<P>Tiny CAPTCHA 認証に失敗しました。</P>\n"
                     print "<FONT color='white'><!--\n"  # 以降を強引に不可視にしようとする努力
                     sleep 5
                     raise 'Tiny CAPTCHA challenge failed'
                 end
 
                 comment.show = false            # 要査閲にするなら
 
                 result
             end
         end
     end
 end
 
 __END__

  つぎが、プラグイン側。

 ・/usr/local/share/tdiary/misc/plugin/tcaptcha.rb
 
 # -*- coding: utf-8; -*-
 
 require 'digest/md5'
 
 def comment_body_label
 
     common_key = 'abc'                          # 任意の文字列(フィルタ側と合わせる)
 
     q = @options['tcaptcha.question'] ||= '質問: 鳥の鳴き声'
     r = @options['tcaptcha.rights'] ||= ['チュンチュン', 'コケコッコ', 'ピヨピヨ', 'カァー', 'ホーホケキョ', 'ガァガァ']
     w = @options['tcaptcha.wrongs'] ||= ['ワン', 'ニャー', 'ブゥブゥ', 'ヒヒーン', 'パォーン', 'ガォー']
 
     rs = r.shuffle
     rw = ([rs.shift] + (rs + w).shuffle[0, 5]).shuffle
     dm = Digest::MD5.hexdigest(((r & rw) << common_key).sort.join(':'))
 
     h = ''; id = 0; rw.each {|i|
         h << "\t\t\t\t\t<INPUT type='checkbox' id='tc%d' name='tcaptcha' value='%s'><LABEL for='tc%d'>%s</LABEL>\n" % [id += 1, i, id, i]
     }
     h << "\t\t\t\t\t<INPUT type='hidden' name='tcaptcha_digest' value='%s'>\n" % dm
 
     tcaptcha = <<-FORM
 #{q}
 #{h}                </div>
                 <div class="textarea">
                     コメント
     FORM
     tcaptcha.chomp
 end
 
 def comment_body_label_short
     '本文'                                      # 未対応
 end
 
 __END__

  よく見れば「なんと強引な」という実装方法だが、アドイン形式では、私の要望を満たす実装方法は、これしかなさそうだ、という結論になった。

  ついでに、もひとつ。tDiaryをバージョン3に上げたからか、counterプラグインがおかしくなり、カウンタが景気よく回りすぎる症状が出てしまう。再訪問のカウント回避機能が効いていない。

  どうも再訪問のカウントは、基本クッキーを使って回避しているらしいのだが、調べるとブラウザまでクッキーが届いていない。仕方ないので、counterプラグインのみならず、tDiary本体にもデバッグ行を入れまくり、動作をトレースする。すると、なんだかコメントスパム等に対するフィルタ処理の関係で、各プラグインが2回ずつ呼ばれるようになってしまっている。counterプラグインは関数定義だけでなく、ロードされただけで実行される処理を持っており、2回連続で呼ばれると副作用でクッキーを吐かなくなってしまうようだ。

  いろいろ対処の仕方を考えたものの、結局「グローバル変数」を使って、1回目はスルー、2回目以降は動作するという「ハブ」みたいなパッチでごまかすことにした。


www.itline.jp /usr/local/share/tdiary/misc/plugin # diff -U 4 counter.rb.org counter.rb
--- counter.rb.org	2012-04-29 20:27:26.000000000 +0900
+++ counter.rb	2012-07-08 02:44:54.290040583 +0900
@@ -476,16 +503,19 @@
 	def kiriban_today?
 		TDiaryCounter.kiriban_today?
 	end
 
+if($q_meet_again_q)
 	tdiary_counter_cookie = TDiaryCounter.run(@cache_path, @cgi, @options)
 	if tdiary_counter_cookie
 		if defined?(add_cookie)
 			add_cookie(tdiary_counter_cookie)
 		else
 			@cookie = tdiary_counter_cookie if tdiary_counter_cookie
 		end
 	end
+end
+$q_meet_again_q = true
 
 	def kiriban
 		if kiriban?
 			msg = @options["counter.kiriban_msg"] ? @options["counter.kiriban_msg"] : ""

  いずれも、裏技的なコードで、コミュニティに還元できそうなコードではない。たはっ。