RubyではてなのWSSE認証をしてはてブにブクマをポストする
ReadItLaterの続きをやろうと思ったのですが、GitHubにはてブスクリプトをコミットしたので先にまとめる。
結構前に作ったので、OAuthではなくWSSE認証を使っています。
手順
- X-WSSEヘッダを作成する
- ブックマークするUrl・コメントを記述したxmlデータと、X-WSSEヘッダを含めたリクエストをhttp://b.hatena.ne.jp/atom/postへPOSTする
手順はこれだけ。次に詳細を…。
ヘッダを作成する
以下のデータを用意します
Username | はてなID |
---|---|
Nonce | HTTPリクエスト毎に生成したセキュリティ・トークンをBASE64エンコードしたもの*1 |
Created | Nonce作成時のタイムスタンプをISO-8601表記で記述したもの |
PasswordDigest | 「Nonce+Created+はてなのパスワード」をSHA1でダイジェスト化しBASE64エンコードしたもの |
これらのデータをX-WSSEヘッダに以下の形式で格納します。
UsernameToken Username="USERNAME", PasswordDigest="PASSWORDDIGEST", Nonce="NONCE", Created="CREATED"
POSTする
ヘッダは完成したので、次にブックマークする情報を用意します。形式はxmlで以下のようなフォーマットで作成します。*2
<entry xmlns="http://purl.org/atom/ns#"> <title>dummy</title> <link rel="related" type="text/html" href="ブックマークするURL" /> <summary type="text/plain">ブックマークコメント</summary> </entry>
作成されたヘッダとデータはこんな感じになります。
最後に作成したヘッダとブックマークデータをhttp://b.hatena.ne.jp/atom/postへポストすると。
おお。
正常に作成された場合は、ステータスコードは201が返ってくるようです。
ソース
Gistは直接貼れるけどGitHubは貼れないのね…。ここにあります。gosyujin/hatena · GitHub
require 'rubygems' require 'pit' require 'time' require 'digest/sha1' require 'net/http' require 'uri' require 'nkf' # wsse認証を行う def wsse(hatena_id, password) # 一意な値(仮実装) nonce = [Time.now.to_i.to_s].pack('m').gsub(/\n/, '') # nonce作成時のタイムスタンプをISO-8601表記で記述したもの now = Time.now.utc.iso8601 # SHA1ダイジェスト化した文字列をBase64エンコード digest = [Digest::SHA1.digest(nonce + now + password)].pack("m").gsub(/\n/, '') { 'X-WSSE' => sprintf( %Q<UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s">, hatena_id, digest, nonce, now) } end # はてブ登録用xmlを生成する def getXml(link, summary) %Q( <entry xmlns="http://purl.org/atom/ns#"> <title>dummy</title> <link rel="related" type="text/html" href="#{link}" /> <summary type="text/plain">#{summary}</summary> </entry> ) end b_url = ARGV.shift || abort("Usage: hatenabookmark.rb <url> <comment>") b_comment = ARGV.shift # エンドポイント url = "http://b.hatena.ne.jp/atom/post" # ユーザ情報読み込み hatena = Pit.get("hatena", :require => { # はてなIDとパスワード "hatena_id" => "your hatena_id", "password" => "your password", }) # pitを使わずにべた書き用 # hatena = { # hatena_id => HATENA_ID, # password = PASSWORD # } # WSSE認証 header = wsse(hatena["hatena_id"], hatena["password"]) uri = URI.parse(url) proxy_class = Net::HTTP::Proxy(ENV["PROXY"], 8080) http = proxy_class.new(uri.host) http.start do |http| # 読み込んだ文字列をutf-8に変換 # b_url = NKF.nkf('-w', b_url) # b_comment = NKF.nkf('-w', b_comment) # エンドポイントへPOST res = http.post(uri.path, getXml(b_url, b_comment), header) if res.code == "201" then print "Bookmark success: #{b_url}\n" else print "#{res.code} Error: #{b_url}\n" end end
参考にしたサイトにトラックバック打とうと思ったけど前すぎて忘れた>< 見つけたら追記します。