Dropbox API を curl で叩いてみる
curl で Dropbox の REST API を叩いてみる。
Dropbox APIのドキュメントはこちら
Dropbox Mobile API Documentation
Dropbox APIのドキュメントにはOAuthに関することは何も書かれていないので以下の文書を参考にした。
OAuth Core 1.0 Revision A 日本語訳
アクセストークン/シークレットを取得
仮に、Dropboxのアカウントとアプリ用のConsumer key/secretが以下のようだったとする。
- メールアドレス => foobar@foobar12345.com
- パスワード => foobarpass
- Consumer key => hogehoge
- Consumer secret => fugafuga
まず以下のようにして /token APIからアクセストークン/シークレットを取得
curl -s 'https://api.dropbox.com/0/token?email=foobar@foobar12345.com&password=foobarpass&oauth_consumer_key=hogehoge'
レスポンスはこんな感じ。フォーマットはJSON
{"token": "piyopiyo", "secret": "puyopuyo"} (値はダミー)
これを利用して、その他のAPIもアクセス可能となる。
API にアクセスしてみよう
試しに /account/info APIにアクセスしてみる。
URLはこれ
https://api.dropbox.com/0/account/info
このURLに署名付きリクエストを送る。
署名をするためのベース文字列を生成
OAuth Core 1.0 Revision A 日本語訳 の9.1章参照
出来上がった署名ベース文字列はこちら
GET&https%3A%2F%2Fapi.dropbox.com%2F0%2Faccount%2Finfo&oauth_consumer_key%3Dgly1ffa07jpan24%26oauth_nonce%3DM6mvq3I0d4%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1295511698%26oauth_token%3Dpiyopiyo
ベース文字列に署名をする
OAuth Core 1.0 Revision A 日本語訳 の9.2章参照
署名にはopensslを使用すればOK
echo -n 'GET&https%3A%2F%2Fapi.dropbox.com%2F0%2Faccount%2Finfo&oauth_consumer_key%3Dgly1ffa07jpan24%26oauth_nonce%3DM6mvq3I0d4%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1295511698%26oauth_token%3Dpiyopiyo' | openssl sha1 -hmac 'fugafuga&puyopuyo' -binary | openssl base64 | sed 's/\//%2F/g' | sed 's/=/%3D/g' | sed 's/+/%2B/g'
出力はこんな感じ。これが署名。
syi0AHTbMuVrFYCw5lcYNFuEOXs%3D
Authorizationヘッダの生成
OAuth Core 1.0 Revision A 日本語訳 の5.4章参照
できあがったAuthorizationヘッダがこれ
Authorization: OAuth oauth_consumer_key="hogehoge",oauth_token="piyopiyo",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1295511698",oauth_nonce="M6mvq3I0d4",oauth_signature="syi0AHTbMuVrFYCw5lcYNFuEOXs%3D" (oauth_versionは無くても行けた)
APIにアクセス
ここまで来れば後はAuthorizationヘッダをくっつけて、APIのURLにリクエストを投げるだけ
curl -H 'Authorization: OAuth oauth_consumer_key="hogehoge",oauth_token="piyopiyo",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1295511698",oauth_nonce="M6mvq3I0d4",oauth_signature="syi0AHTbMuVrFYCw5lcYNFuEOXs%3D"' 'https://api.dropbox.com/0/account/info'
するとこのようなレスポンスが返ってくる。
{"referral_link": "https://www.dropbox.com/referrals/◯◯◯◯◯", "display_name": "foo bar", "uid": 12345678, "country": "JP", "quota_info": {"shared": 0, "quota": 2415919104, "normal": 471546692}, "email": "foobar@foobar12345.com"}
パラメータを敢えて間違えるとエラーレスポンスも体験できる。
シェルスクリプトにしてみた
んー。シェルでやるもんじゃあないなぁ(笑)
連想配列のないbashとJSONは相性が悪い。
#!/bin/bash function _dbg() { #echo $1 return 0 } # # ランダム文字列生成 # randstring() { len=$1 rndstr="" while [ $(echo ${rndstr} | wc -m) -le $len ]; do rnd=$[RANDOM % 75 + 48] if [ ${rnd} -ge 58 -a ${rnd} -le 64 -o ${rnd} -ge 91 -a ${rnd} -le 96 ]; then continue fi rndstr=${rndstr}$(printf \\x$(printf %x ${rnd})) done echo ${rndstr} return 0 } # # 状態スタックに状態をプッシュ # function push_stat() { _STAT[${#_STAT[@]}]=$1 _dbg NUM_STAT=${#_STAT[@]}, _STAT=${_STAT[*]} return 0 } # # 状態スタックから状態をポップ # function pop_stat() { unset _STAT[`expr ${#_STAT[@]} - 1`] _dbg NUM_STAT=${#_STAT[@]}, _STAT=${_STAT[*]} return 0 } # # 現在の状態を取得 # function top_stat() { local num=${#_STAT[@]} if [ $num -gt 0 ]; then echo ${_STAT[(($num-1))]} else _dbg "" fi return 0 } # # JSON解析君 # JSONを標準入力から読み取り # JSON_<obj1>_<obj2>_<prop1>=<value> # のような文字列を標準出力に出力するのでevalしてくだしあ # 呼び出し前には unset ${!JSON_*} しておくこと # function json() { local ST_OBJ=0 local ST_KEY=1 local ST_STR=2 local ST_VALUE=3 local KEY="JSON" local VALUE="" local LINE local CHAR push_stat $ST_VALUE while read LINE; do for((i=0; i < ${#LINE}; i++)); do CHAR=${LINE:$i:1} _dbg $CHAR case `top_stat` in $ST_KEY) case $CHAR in \") push_stat $ST_STR _dbg "str start" ;; \:) pop_stat _dbg "key end" _dbg key=$VALUE KEY=$VALUE unset VALUE push_stat $ST_VALUE ;; esac ;; $ST_STR) case $CHAR in \") pop_stat _dbg "str end" ;; " ") ;; *) VALUE=${VALUE}$CHAR ;; esac ;; $ST_VALUE) case $CHAR in \") push_stat $ST_STR _dbg "str start" ;; \,|\}) pop_stat _dbg "value end" _dbg value=$VALUE if [ -n "$KEY" ]; then PROP=`echo ${OBJPATH[@]} | sed -e 's/ /_/g'` if [ -n $PROP ]; then PROP=${PROP}_$KEY fi _dbg "$PROP=$VALUE" echo "$PROP=$VALUE" #eval "$PROP=$VALUE" fi unset VALUE unset KEY case $CHAR in \,) push_stat $ST_KEY _dbg "key start" ;; \}) pop_stat _dbg "object end" unset OBJPATH[`expr ${#OBJPATH[@]} - 1`]; ;; esac ;; \{) push_stat $ST_OBJ _dbg object start # obj start OBJPATH[${#OBJPATH[@]}]=$KEY push_stat $ST_KEY _dbg key start ;; " ") ;; *) VALUE=${VALUE}$CHAR ;; esac ;; esac done done } #main MAIL=$1 PASS=$2 CKEY=$3 CSECRET=$4 if [ -z "$CKEY" -o -z "$CSECRET" -o -z "$MAIL" -o -z "$PASS" ]; then echo usage: `basename $0` '<mail address> <password> <consumer key> <consumer secret>' >&2 exit 1 fi echo retrieve Access token/secret form Dropbox.. TOKEN_RESP=`curl -s "https://api.dropbox.com/0/token?email=$MAIL&password=$PASS&oauth_consumer_key=$CKEY"` echo $TOKEN_RESP unset ${!JSON_*} eval `echo $TOKEN_RESP | json` ATOKEN=$JSON_token ASECRET=$JSON_secret echo "Access token: $ATOKEN" echo "Access token secret: $ASECRET" if [ -z "$ATOKEN" -o -z "$ASECRET" ]; then echo "Can't retrieve Access token/secret" >&2 exit 1 fi NONCE=`randstring 10` TIMESTAMP=`date +%s` echo "creating OAuth Signature Base String.." SIGN_BASE='GET&https%3A%2F%2Fapi.dropbox.com%2F0%2Faccount%2Finfo&oauth_consumer_key%3D'$CKEY'%26oauth_nonce%3D'$NONCE'%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D'$TIMESTAMP'%26oauth_token%3D'$ATOKEN echo "Signature Base String: $SIGN_BASE" echo "Signing.." SIGN=`echo -n $SIGN_BASE | openssl sha1 -hmac $CSECRET'&'$ASECRET -binary | openssl base64 | sed 's/\//%2F/g' | sed 's/=/%3D/g' | sed 's/+/%2B/g'` echo "Signature: $SIGN" echo "Retrieving account info..." RESP=`curl -s -H 'Authorization: OAuth oauth_consumer_key="'$CKEY'",oauth_token="'$ATOKEN'",oauth_signature_method="HMAC-SHA1",oauth_timestamp="'$TIMESTAMP'",oauth_nonce="'$NONCE'",oauth_signature="'$SIGN'"' 'https://api.dropbox.com/0/account/info'` echo $RESP unset ${!JSON_*} eval `echo $RESP | json` for p in ${!JSON_*}; do eval echo $p=\$$p done
使い方
$ dropbox_api.sh