ぼくがかんがえたおーぷんそーしゃる その2

  • 前回 から時間が経っていました
  • 淡々と Twixi の実装を説明していきます
  • 改ざんされて困ってしまう OpenSocial JavaScript API ですが、実は、ガジェットがソーシャルデータを取得するときに、コンテナの RESTful API にアクセスをおこなっているのでした

GET /social/data/people/@viewer/@friends?fields=id,name,thumbnailUrl&startIndex=0&count=1000&orderBy=topFriends&filterBy=all&networkDistance=&st=*** HTTP/1.1
Host: b2721bfb3ca713c9e377898ab19ade4d2ffb3a57.app0.mixi-platform.com

HTTP/1.x 200 OK
Content-Type: application/json
{"link":null,"entry":[{"thumbnailUrl":"http://profile.img.mixi.jp/xxx","nickname":"xxx","id":"xxx","updated":"2009-11-07T16:02:15Z","hasApp":"true"},...],"startIndex":0,"itemsPerPage":"1000","author":null,"totalResults":100}

  • mixi は、現時点で OAuth の RESTful API をサポートしていませんが、JavaScript API を提供している OpenSocial コンテナには、既に security token による RESTful API が存在しているということになります
    • 少なくとも shindig を採用しているところは

  • ということなので Twixi では、ソーシャルデータの改ざんを防ぐため、外部サーバにアプリケーションを置き、そこから security token(以下st)を使用して RESTful API に直接アクセスすることにしました
  <Content type="html" view="canvas">
  <![CDATA[
<script type="text/javascript">
    gadgets.util.registerOnLoadHandler(function(){
        location.href = "http://twixi.dyndns.org/sample.cgi?st=" + encodeURIComponent(shindig.auth.getSecurityToken());
    });
</script>
  ]]>
  </Content>
use CGI;
use Net::OpenSocial::Client;
use Net::OpenSocial::Client::Container;
use Net::OpenSocial::Client::Type::Auth qw(ST);
use Net::OpenSocial::Client::Type::Protocol qw(REST);
use Net::OpenSocial::Client::Type::Format qw(JSON);

my $q = CGI->new;
my $client = Net::OpenSocial::Client->new(
    container     => Net::OpenSocial::Client::Container->new(
        rest_endpoint => q{http://app0.mixi-platform.com/social/data},
    ),
    auth_type     => ST,
    st            => $q->param('st'),
    format_type   => JSON,
    protocol_type => REST,
);

print $q->header(-type => 'text/plain', -charset => 'utf-8');

my $person = $client->get_person('@viewer')
    or die $client->errstr;
print 'viewer_id: ' . $person->get_field('id') . "\n";
print 'viewer_nickname: ' . $person->get_field('nickname') . "\n";

my $friends = $client->get_friends('@viewer')
    or die $client->errstr;
for my $friend ( @{ $friends->items } ) {
    print 'friend_id: ' . $friend->get_field('id') . "\n";
    print 'friend_nickname: ' . $friend->get_field('nickname') . "\n";
}

viewer_id: 11325239
viewer_nickname: あさんのう
friend_id: xxx
friend_nickname: xxx
...

    • おめでとうございます!誰かの介入を受けることなく、ソーシャルデータを取得することができました
    • もちろん、Activity を流したり、AppData をいじったりも可能です
  • この方法を採用すると、当然、ガジェットの iframe の src は mixi と関係ない別のドメインになります
    • 普通に、gadget.xml 内で st を外部サーバに gadgets.io.makeReqeust() で渡してもいいですが、アプリケーションをすべて外部に置きたかったので、このようになりました、以下理由
      • 使い慣れた環境で開発できる
      • 既存のサービスを mixi アプリ化するのが簡単
      • ソースコードが隠せる
    • st が URL のパラメーターとして渡されるので、referer などから漏れないように注意してください
    • ガイドライン的にどうなの、という点ですが 駐車戦争 なども、がっつり http://mixi.linno.jp/parking/index とかになっているので、問題ないかと(多分)
    • あと、JavaScript API がまったく使えなくなるので、opensocial.requestShareApp() とか使えなくなるけどどうすんの、という点については次回以降で解決策を書きます
  • 外部サーバ上のアプリケーションでは、ユーザを識別するために上記の例にある viewer_id を使用します
  • しかし、Twixi 以外のアプリに対して発行された st を渡されたとしても、viewer_id を取得できてしまう問題
    • 前述のとおり、アプリ開発者は、そのアプリを利用している任意のユーザの st を得て、それを外部に送ることができます
    • 例えば、私が チャンネー にアクセスしたときに発行された st を使うことで、チャンネーの開発者は Twixi に私としてアクセスすることが可能になります
  • これを防ぐべく次回は、外部サーバ上でどのアプリに対して発行されたものか st を検証する方法の解説です