2003-10-01
_ PingProxy α版 (20:18)
※注意書き
- PingProxyを利用するいしだなおとさんによる「htmlによるTrackBackクライアント実装(http://www.ksky.ne.jp/~naoto/39_akiary/n3/200310.html#20031010_1065724154)」が公開されています。
- urlsパラメータで送信するべき文字列は、TrackBack Ping URLではなく、記事URL(いわゆるPermalink)の方です。TrackBack Ping URLが送られてもそこへのPing送信は代行しませんのでご注意ください。
- Perlのサンプルが間違っていたので修正しました。
日記やらblogやらwikiやらCMSやらの連携について議論するMLの、
- [intersite:133 Re: TrackBack の本質とは? - http://kobit.zive.net/intersite/20040114.html
あたりで書いたTrackBack送信代行サーバーPingProxyをテスト実装してみた。
概要
TrackBack、PingBackなどの送信を代行する専用サーバーを用意することによって、ユーザーの使い勝手を向上させる仕組み。TrackBack Ping URLの存在を気にすることなく、PingBackと同等の操作でTrackBackが気軽に送れるようになる。
重複チェック(同じTrackBackを複数回送ってしまう)、存在チェック(間違ったURLに送ってしまう=タイムアウトまで待つ?)、文字コードチェック(送り先の文字コードを確認して、その文字コードに変換した上で、charsetパラメータもつけて送る)などもサーバーサイドで代行する。
詳細
TrackBackを一般ユーザーとして利用する際の、私が思うところの弱点は、
- 言及したい記事URLとTrackBack Ping URLを結びつけることを意識するのがうざい(bookmarkletを使ったところで)
- できれば、PingBackみたいに含まれるURL一通りに対して自動的に(相手が対応していれば)Pingを送って欲しい
- でも、PingBackはサーバー負荷&時間がかかるから、記事更新時のレスポンスが悪くなるのがうざい
- ただのTrackBackの場合でも、相手先サーバーが重ければレスポンスが悪くてうざい
というあたりなんで、そのあたりを解消するために、
- PingProxy I/F(http://pingproxy.ishinao.net/ping)がすべてのPing投稿をうけつける
- PingProxyにはHTTP POSTで以下のパラメータを送信する。
- url(必須)……送信元記事の固定URL
- title……送信元記事のタイトル
- blog_name……送信元記事を含むサイト名
- excerpt……送信元記事の要約
- charset……POSTしたパラメータの文字コード
- urls(必須)……言及先URL文字列(複数)を含むテキスト。※ここでいう言及先URL文字列というのは、TrackBack Ping URLではなく、記事URL(いわゆるPermalink)のことです。TrackBack Ping URLを送信してもPingを送りません。
- PingProxyは、上記のPing投稿を受け付けると、ただちに「OK」という文字列を返す。それ以外の文字列が返された場合はエラー。
- PingProxyは、投稿されたurlsに含まれるURL文字列を抽出し、そのURL文字列に対応したPing I/Fが存在するかどうかを確認する
- 埋め込みRDFを使ったTrackBack Ping I/Fを検索する
- はてなダイアリーの記事URL文字列に合致する場合は、末尾にtrackbackをつけたものをPing URLと見なす
- blogmapにそのURLに関する項目がないかを確認し、存在した場合はblogmapのTrackBack Ping URLを返す
- PingBack I/Fを検索する(未実装)
- Ping投稿を実際のPing処理コマンドに分解する
- 投稿元記事URLと、その記事に含まれるターゲットURL、ターゲットURLが持つPing I/F、という組み合わせ分のPing処理コマンドを予約する
- すでに処理が行われた組み合わせのコマンドは重複実行しない
- 各URLに関する情報を収集する
- そのURLは本当に存在するか
- そのURLではどの文字コードを利用しているか
- 実際にPing処理コマンドを実行する
- すべての準備が整ったPing処理コマンドを順次実行していく
- TrackBack Pingを送信する
- 送信先のcharset(だと思われるもの)に合わせてパラメータの文字コードを変換した上で、charsetパラメータ付きで送信する
- pingback.pingを送信する(未実装)
- 各Ping処理コマンドの実行結果をログに記録していく
urlsには、言及先の記事URLを列挙してください。記事本文を丸ごとurlsとして投稿しても、その中に含まれるURLを自動的に抽出するので、通常は記事本文を丸ごと投稿してしまって構いません。
まだほとんどテストも行っていないので、ひとまずは概要説明ってことで。裏タスクは-[まだ自動化していません。もうちょっと試して問題なさそうならば、裏タスクを自動化しつつ、-自動化しました。表側のWebインターフェース(ログ表示とか)も用意します。
α版のURL
直接PingProxy I/Fを叩く場合は、
を。
HTMLフォームから手動で送信する場合は、
を使うと動作します。
PHPによるPingProxy送信サンプルコード
$pingproxy = 'http://pingproxy.ishinao.net/ping'; $charset = 'euc-jp'; $blog_name = 'サイト名'; $url = '記事のURL'; $title = '記事のタイトル'; $body = '記事本文'; $excerpt = '記事の要約'; $query = 'url='.urlencode($url); $query .= '&title='.urlencode($title); $query .= '&blog_name='.urlencode($blog_name); $query .= '&charset='.urlencode($charset); $query .= '&excerpt='.urlencode($excerpt); $query .= '&urls='.urlencode($body); $curl = curl_init($pingproxy); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $query); ob_start(); curl_exec($curl); ob_end_clean(); curl_close($curl);
Perl+LWPによるPingProxy送信サンプルコード
use URI::Escape;
use LWP::UserAgent;
use HTTP::Request;
my $pingproxy = 'http://pingproxy.ishinao.net/ping';
my $url = '記事URL';
my $title = '記事タイトル';
my $blog_name = 'サイト名';
my $excerpt = '記事要約';
my $body = '記事本文';
my $charset = 'euc-jp';
my $ua = new LWP::UserAgent;
my $headers = new HTTP::Headers;
$headers->header('Content-type','application/x-www-form-urlencoded');
my $query = 'url='.uri_escape($url);
$query .= '&title='.uri_escape($title);
$query .= '&blog_name='.uri_escape($blog_name);
$query .= '&charset='.uri_escape($charset);
$query .= '&excerpt='.uri_escape($excerpt);
$query .= '&urls='.uri_escape($body);
my $request = new HTTP::Request('POST', $pingproxy, $headers, $query);
my $response = $ua->request($request);
rubyによるPingProxy送信サンプルコード
require('cgi.rb');
url = '記事URL'
title = '記事タイトル'
blog_name = 'サイト名'
excerpt = '記事要約'
body = '記事本文'
charset = 'euc-jp'
query = 'url='+CGI::escape(url)
query += '&title='+CGI::escape(title);
query += '&blog_name='+CGI::escape(blog_name);
query += '&charset='+CGI::escape(charset);
query += '&excerpt='+CGI::escape(excerpt);
query += '&urls='+CGI::escape(body);
require 'net/http'
http = nil
response = nil
header = {}
header['Content-type' = 'application/x-www-form-urlencoded'
Net::HTTP.start('pingproxy.ishinao.net') {|http|
response ,= http.post('/ping', query, header)
}
※一応動いたけど、rubyはさっぱり分からないんで、そのまま使うのは危険かも
はてなダイアリーとの連携テスト用
はてなダイアリーでは、送信元URLに送信先URL文字列が含まれるかを確認するため、送る前にURLを記述しておかないといけない。
懸案事項
- はてなダイアリーのように、送信元URLに送信先URLが含まれているかを確認した方がいいだろうか?
- 内部EUC-JPなんで、日本語・英語以外の文字コードはサポートできないけれども、本気でやるならば内部UTF-8でやるべきなんだろうなー。
- MovableTypeにPingProxy送信機能を組み込んでみたんだけど、MovableTypeって派生物の配布も許可していないってことは、改変コードの提示も許可されないのかな? それとも、MovableType自身のコードを含まなければいいのか? 微妙だ。
- PingProxyって、MovableTypeでTrackBackをProxy経由で送るときの設定項目名と同じだな。ややこしくなるから変えた方がいいかな。
_ 著作権と「マルC」 (20:18)
- 著作権と「マルC」 - http://jimphelps.at.infoseek.co.jp/circlec.html
もともと結構重要なテーマだったんだけど、最近さらにその重要度を増している著作権に関する基本的な知識のページ。2chのどこぞのスレッドで、「©を使わず(c)と書いたのでは、国外では相手にされない」なんて感じの書き込みを見かけたんだけど、別にそんなこともないみたいだね。というか、「それほど話は単純じゃない」と言った方がいいのかな。
2004-10-01
_ mixiに招待してもらった (13:34)
mixiに招待してもらったんでちょっとだけ触ってみたけど、なんかあんまり好きじゃない感じだなー。システムは結構良さそうだけど、現状の利用のされ方が俺の好みじゃない。
なれ合うならもっと狭く深くなれ合った方がいい。雰囲気しか見てないけど、あの程度の浅いコミュニケーションだったら、わざわざクローズドな場所でやるほどのものでもないと思う。まあmixiを使った深いコミュニケーションは、他人(非友達)には見えないところに隠れてるんだろうけどさ。
個人的な感触(願望)としては、SNSはもっとクローズドな用途でのみ使われるようになって欲しいな。で、ちょっとだけアクセス制御を使いたいけど基本的にオープンでかまわないようなコミュニティは、今までのWikiとか日記とかblogとか掲示板とかに、TypeKeyみたいな外付けシングルサインオンの仕組みを組み合わせて実現する方がいい。
たぶんmixiのアカウントは、単にmixi内のオープンな場所にアクセスする権利としてしか使わない気がする。とかいいつつ、どっぷりmixiにはまって一ヶ月後にはSNSサイコー!とか吠えていたら笑えるな。
_ リファラエディタプラグイン (14:44)
とても便利なんだけど、バグらしきもの発見。その月の日記(というか%Y/%Y%m.tdrファイル)が存在しない状態で、プラグインを呼び出すとエラーが出る。具体的には、10月1日の日記をまだ書かない状態で、9月30日についたREFERER SPAMを削除しようとしたら、編集フォームを表示する前にエラーが出た。
たぶん、refedit_loadの頭にでも、
if File.exist?(path) == false then return {} end
とかつけておけばいいのかな? もう今月の日記を書いちゃったんで、試すのは来月回し。
_ とおんねーなー (15:34)
ひとまずTypeKeyの動作確認だけやっておこうかと、Authen::TypeKeyを使ってみたはいいけど、リダイレクトして戻ってきたパラメータを、
$q = CGI->new; $tk = Authen::TypeKey->new; $res = $tk->verify($q);
とかすると、
TypeKey signature verification failed
とか言われちゃうんですけど。なんか追加設定しないと使えないんだっけ?
ああそうか
verifyを呼ぶ前に、
$tk->token([TypeKeyトークン文字列]);
を入れないとだめなのね。これもちゃんとドキュメントに載っけておいてくれよ。
これで一応PerlでTypeKeyを使う準備はできたけど、PHPでDSAの署名をverifyするにはどう書けばいいんだろう。PEARにCrypt::DSAがあるかと思って見てみたら、まだなかった。TypeKeyのverifyだけPerlを使って、それ以外はPHPで書こうかなー。
_ TypeKeyクライアントサンプルCGI (21:04)
上記リンク先にアクセスして、loginをクリックすると、TypeKeyの認証ページに飛ぶ。そこでログインするとリダイレクトして戻ってきて、名前、ニックネーム、メールアドレス(通知する場合)が表示される。
#!/usr/bin/perl
use CGI;
use Authen::TypeKey;
print "Content-type: text/html\n\n";
print "<h1>TypeKey test</h1>";
my $q = CGI->new;
my $tk = Authen::TypeKey->new;
$tk->key_cache([公開鍵用キャッシュファイルのパス]);
$tk->token([TypeKeyトークン文字列]);
my $res = $tk->verify($q);
if (!$res) {
print "LOGIN FAILURE: ".$tk->errstr;
} else {
my $name = $q->param('name');
my $nick = $q->param('nick');
my $email = $q->param('email');
print 'Your Name: '.$name."<br>";
print 'Your Nickname: '.$nick."<br>";
print 'Your Email Address: '.$email.'<br>';
#以降、$nameと$emailを使って、ローカルの認証を行う
}
ちなみに上記段階は、あくまでもTypeKeyの認証が行われただけの話で、実際に各Webアプリケーション上でそのユーザーにどのような権限を与えるかは、$name(と$email)を使って別途処理する(というか権限データベースを作る)必要がある。あと認証状態の継続(セッション管理)も、自前でやらないといけない。まさかアクションごとにいちいちTypeKeyサーバーにとばすわけにもいかないしね。
これを使ったアクセス制御のパターンとしては、
- 未認証
- TypeKey認証済み
- TypeKey認証済み+メール通知有り
- TypeKey認証済み+ローカルユーザー権限あり
というユーザー権限に対して、それぞれ読み書き権限を振り分けていく感じになるんでしょう。実際には4の段階で、さらに細かい権限設定ができるけど、それはまあ適当に。
そういえば、やっぱり前に書いた微妙な動作はサーバーサイドの挙動に問題があるんだね。
「メールアドレスを通知しない」を選ぶと、最初の1回は確かに仕様通り、メールアドレスとしてSHA1ハッシュを返すんだけど、ブラウザの戻るボタンでTypeKeyの認証ページに戻ると、すでにTypeKeyサーバー上で認証済み(セッション)なんで、ログイン画面なしで自動的にリダイレクトがかかる。で、どうやら認証状態で自動リダイレクトがかかる場合には、無条件でメールアドレスを通知するらしい。
ちゃんと動作させるためには、ユーザー設定で「常時メールアドレスを通知する/しない」とかをつけつつ、後は各サーバーごとにこのセッション中に「する/しない」のどちらを選んだのか覚えておいて、リダイレクト時にはその組み合わせを見ながら、適切に処理する(メールアドレス通知リダイレクト、非通知リダイレクト、メールアドレスを通知するかのみを確認するフォーム表示)感じかなー。



Before...
_ otsune [「儀礼的無関心」の提唱者の松谷氏は、まさにYet Another Webとしての「超簡単な認証付きインターネット」と..]
_ ishinao [そういえば、mixiってむかーし昔のパソコン通信(しかも草の根系)っぽいところがあるかも。そう考えると、あのコミュニ..]
_ ひらた [ドキュメント書く暇がないのですが、隠すものでもないので、とりあえず公開しました。]