ということで書いた。
#!/usr/bin/env gosh
(use rfc.http)
(use rfc.sha)
(use rfc.hmac)
(use rfc.base64)
(use www.cgi)
(use math.mt-random)
(use gauche.uvector)
(use sxml.ssax)
(use sxml.sxpath)
;; ------------
;; custom var
;; ------------
;; API-KEY と API-SECRET は事前に、
;; https://www.flickr.com/services/apps/create/apply/
;; で、新しいAPIを作って取得しておく。
(define consumer-key "API-KEY")
(define consumer-secret "API-SECRET") ; client-credentials-secret
;; ------------
;; lib
;; ------------
(define (uri-encode-string str)
(call-with-string-io str
(lambda(in out)
(while (read-byte in) (compose not eof-object?) => ch
(if (char-set-contains? #[a-zA-Z0-9.~_-] (integer->char ch))
(write-char (integer->char ch) out)
(format out "%~2,'0X" (char->integer (integer->char ch))))))))
(define (time-stamp)
(number->string (sys-time)))
(define (random-string)
(let ((random-source
(make <mersenne-twister> :seed (sys-time)))
(v (make-u32vector 10)))
(mt-random-fill-u32vector! random-source v)
(digest-hexify (sha1-digest-string (x->string v)))))
;; !! alphabetical order is needed
(define (param-form-data? param)
(odd? (length param)))
(define (oauth-normalize-parameters params)
(define (param-sorter a b)
(or (string<? (car a) (car b))
(and (string=? (car a) (car b))
(string<? (cadr a) (cadr b)))))
(sort (remove param-form-data? params) param-sorter))
(define (query-compose query)
(string-join (map (cut string-join <> "=")
(oauth-normalize-parameters query) ) "&"))
(define (signature method uri info :optional (token-secret ""))
(let* ((query-string (query-compose info))
(signature-basic-string
(string-append method "&"
(uri-encode-string uri) "&" ; !! this is not '?'
(uri-encode-string query-string))))
(uri-encode-string
(base64-encode-string
(hmac-digest-string signature-basic-string
:key #`",|consumer-secret|&,|token-secret|" ; client-credentials-secret '&' token-credentials-secret
:hasher <sha1>))) ))
(define (string->sxml str)
(call-with-input-string str
(lambda (port)
(ssax:xml->sxml port '()))))
;; ------------
;; Oauth
;; ------------
;; Request Tokenの取得
(define query
`(("oauth_consumer_key" ,consumer-key)
("oauth_nonce" ,(random-string))
("oauth_signature_method" "HMAC-SHA1")
("oauth_timestamp" ,(time-stamp))
("oauth_callback" "oob") ; out of band authentication = not web authentication
("oauth_version" "1.0") ; option
))
(define credential (signature "GET"
"https://www.flickr.com/services/oauth/request_token" ; !! https
query
;; no token-credentials-secret this time
))
(define token
(receive (status header body)
(http-get "www.flickr.com"
(string-append "/services/oauth/request_token?" ; !! you need '?"
(query-compose
`(,@query ("oauth_signature" ,credential)) ))
:secure #t ) ; !! https
(cgi-parse-parameters :query-string body)))
(define oauth-token (cadr (assoc "oauth_token" token)))
(define oauth-token-secret (cadr (assoc "oauth_token_secret" token)))
;; OAuth Verifierの取得
(display "open this url.")
(newline)
(format #t
"https://www.flickr.com/services/oauth/authorize?oauth_token=~A&perms=write"
oauth-token) ; optional perms= parameter, asking for read, write, or delete
(newline)
(newline)
(display "input pin: ")
(flush) ;これが無いと、「input pin: 」と表示されるのがread-lineの後になってしまう。
(define oauth-verifier (read-line))
;; Access Tokenの取得
(define query
`(("oauth_consumer_key" ,consumer-key)
("oauth_nonce" ,(random-string))
("oauth_signature_method" "HMAC-SHA1")
("oauth_timestamp" ,(time-stamp))
("oauth_token" ,oauth-token)
("oauth_verifier" ,oauth-verifier)
("oauth_version" "1.0") ; option
))
(define credential (signature "GET"
"https://www.flickr.com/services/oauth/access_token" ; !! https
query
oauth-token-secret)) ; token-credentials-secret
(define token
(receive (status header body)
(http-get "www.flickr.com"
(string-append "/services/oauth/access_token?" ; !! you need '?"
(query-compose
`(,@query ("oauth_signature" ,credential)) ))
:secure #t)
(cgi-parse-parameters :query-string body)))
;; request_tokenの時と同じ oauth_token というkeyだが、Access Token の値が入ってる
(define access-token (cadr (assoc "oauth_token" token)))
;; request_tokenの時と同じ oauth_token_secret というkeyだが、Access Token Secret の値が入ってる
(define access-token-secret (cadr (assoc "oauth_token_secret" token)))
;; ------------
;; test
;; ------------
(define query
`(("oauth_consumer_key" ,consumer-key)
("oauth_nonce" ,(random-string))
("oauth_signature_method" "HMAC-SHA1")
("oauth_timestamp" ,(time-stamp))
("oauth_token" ,access-token)
("method" "flickr.test.login")
))
(define credential (signature "GET"
"https://api.flickr.com/services/rest" ; !! https
query
access-token-secret) ) ; token-credentials-secret
(define test-login
(receive (status header body)
(http-get "api.flickr.com"
(string-append "/services/rest?"
(query-compose
`(,@query ("oauth_signature" ,credential)) ))
:secure #t)
(sxml:string ((sxpath "rsp/@stat")
(string->sxml body)) )))
(print test-login)
最終更新:2017年12月19日 20:30