http://ido.nu/kuma/2007/06/29/mixi%e3%81%ae%e3%81%82%e3%81%97%e3%81%82%e3%81%a8api%e7%99%ba%e6%8e%98/をみて、WSSEってなんだ?*1、って思ったので、mixiの足跡をみるやつをつくってみた。RubyでのWSSEについてははてなブックマークをダウンロードするスクリプト - 趣味的にっきを参考にさせていただきました。*2

#!/usr/bin/ruby -Ku                                                                                                                                          
                                                                                                                                                             
require 'open-uri'                                                                                                                                           
require 'digest/sha1'                                                                                                                                        
require 'base64'                                                                                                                                             
require 'rexml/document'                                                                                                                                     
                                                                                                                                                             
class MixiTracks                                                                                                                                             
                                                                                                                                                             
  def initialize(user,pass,id=nil)                                                                                                                           
    @user = user                                                                                                                                             
    @pass = pass                                                                                                                                             
    @wsse = get_wsse                                                                                                                                         
    @uri = "http://mixi.jp/atom/tracks/r=2/"                                                                                                                 
    id ? @id = "member_id=#{id}" : @id = get_id                                                                                                              
  end                                                                                                                                                        
                                                                                                                                                             
  def get_wsse                                                                                                                                               
    created = Time.now.iso8601                                                                                                                               
                                                                                                                                                             
    nonce = ''                                                                                                                                               
    20.times do                                                                                                                                              
      nonce << rand(256).chr                                                                                                                                 
    end                                                                                                                                                      
                                                                                                                                                             
    passdigest = Digest::SHA1.digest(nonce + created + @pass)                                                                                                
                                                                                                                                                             
    return  "UsernameToken Username=\"#{@user}\", " +                                                                                                        
      "PasswordDigest=\"#{Base64.encode64(passdigest).chomp}\", " +                                                                                          
      "Nonce=\"#{Base64.encode64(nonce).chomp}\", " +                                                                                                        
      "Created=\"#{created}\""                                                                                                                               
  end                                                                                                                                                        
                                                                                                                                                             
  def http_get(uri)                                                                                                                                          
    open(uri, 'X-WSSE' => @wsse)do |http|                                                                                                                    
      return http.read                                                                                                                                       
    end                                                                                                                                                      
  end                                                                                                                                                       
                                                                                                                                                            
  def get_id                                                                                                                                                
    feed = http_get(@uri)                                                                                                                                   
    doc = REXML::Document.new(feed)                                                                                                                         
    doc.elements.each('//collection') do |elem|                                                                                                             
      return $1 if elem.attributes['href'] =~ /(member_id=\d+)/
    end                                                                                                                                                      
    return nil                                                                                                                                               
  end                                                                                                                                                        
                                                                                                                                                             
  def get_tracks                                                                                                                                             
    tracks = []                                                                                                                                              
    title = ""                                                                                                                                               
    updated = ""                                                                                                                                            
                                                                                                                                                            
    feed = http_get("#{@uri}#{@id}")                                                                                                                        
    doc = REXML::Document.new(feed)                                                                                                                         
                                                                                                                                                            
    doc.elements.each('feed/entry') do |elem|                                                                                                               
      elem.elements.each('title') do |el|                                                                                                                   
        title = el.text                                                                                                                                     
      end                                                                                                                                                   
      elem.elements.each('updated') do |el|                                                                                                                 
        updated = el.text                                                                                                                                   
      end                                                                                                                                                   
      tracks << [title,updated]                                                                                                                             
    end                                                                                                                                                    
    tracks                                                                                                                         
  end

  private :get_wsse, :http_get                                                                                                                               
                                                                                                                                                             
end                                                                                                                                                          
                                                                                                                                                             
if ARGV.size < 2                                                                                                                                             
  $stderr.puts "usage: mixi [mail] [pass] ([id])"                                                                                                            
  exit 1                                                                                                                                                     
end                                                                                                                                                          
                                                                                                                                                             
user = ARGV[0]                                                                                                                                               
pass = ARGV[1]                                                                                                                                               
id = ARGV[2]                                                                                                                                                 
                                                                                                                                                             
ashiato = MixiTracks.new(user,pass)                                                                                                                          
puts ashiato.get_tracks

実行するときには、1つめの引数が登録したメールアドレスで、2つめがパスワード。3つめがidだけど、これはなくてもいい*3
idがわかんない場合は2回アクセスしちゃってて、そこらへんがちょっとかっこわるいなーと思う、が、よい方法が思い付かない。
とりあえず、open-uriはハッシュを引数にとっていろいろヘッダフィールドが指定できる、ということがわかった。

*1:無知過ぎる

*2:認証のあたりとかはほとんどそのままです。ありがとうございます。勉強になります。

*3:普通にmixiやってるぶんには知らないし。調べるのもちょっとめんどくさいし