OAuthのリクエストトークンがやっと取れました.

参考にしたページ

http://yuroyoro.hatenablog.com/entry/20100506/1273137673

http://d.hatena.ne.jp/tor_ozaki/20100530/1275166645

(require 'ironclad)    ;暗号化関係
(require 'cl-base64)   ;Base64
(require 'drakma)      ;HTTPリクエスト投げる

(defparameter *key* "foooooooooooooo")
(defparameter *secret* "baaaaaaaaaaaaaaar")
(defparameter *acc-token* nil)
(defparameter *acc-secret* nil)
(defparameter *request-token-uri* "https://api.twitter.com/oauth/request_token") 

(defun make-par ()
  (list
   `("oauth_consumer_key" . ,*key*)
   `("oauth_nonce" . ,(nonce-gen))
   `("oauth_signature_method" . "HMAC-SHA1")
   `("oauth_timestamp" . ,(format nil "~a"(get-unix-time)))
   `("oauth_token" . ,*acc-token*)
   `("oauth_version" . "1.0")))

(defun get-unix-time ()
  (- (get-universal-time) 2208988800))  ;70年早い

(defun nonce-gen ()
  (let ((str "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"))
    (concatenate 'string
         (loop for n to 32
            collect (char str (random 62))))))

(defun hmac-base-gen (method url params)
  (let* ((lst (sort (loop for n in params
              collect (format nil "&~a=~a" (car n) (if (cdr n)
                                   (cdr n)
                                   "")))
           #'string-lessp))
     (str (list method "&" (perenc url) "&" (perenc (format nil "~a" (subseq (car lst) 1)))(perenc (format nil "~{~a~}" (cdr lst)))))) ;ここでハッシュ化する文字列の一部を余分にパーセントエンコードしてしまってハマった
    (format nil "~{~a~}" (loop for s in str collect s))))
  
(defun perenc (str) ;後でちゃんとやります
  (format nil "~{~a~}" (loop for ch across str for index from 0
              collect (cond ((eq ch #\:) "%3A")
                    ((eq ch #\/) "%2F")
                    ((eq ch #\&) "%26")
                    ((eq ch #\=) "%3D")
                    ((eq ch #\+) "%2B")
                    (t ch)))))

(defun hmac-sha1 (key str)
  (let* ((str (string-to-octets str))
     (key (string-to-octets key))
     (hmac (ironclad:make-hmac key 'ironclad:sha1)))
    (ironclad:update-hmac hmac str)
    (ironclad:hmac-digest hmac)))

(defun make-signature (meth url par)
  (cl-base64:usb8-array-to-base64-string 
      (hmac-sha1 (make-key) (hmac-base-gen meth url par))))

(defun make-key ()
  (let ((lst (list *secret* "&" *acc-secret*)))
    (format nil "~{~a~}" (loop for n in lst
                collect (format nil "~a" (if n
                             n
                             ""))))))

(defun make-header (meth url)
  (let* ((par (make-par))
     (par (append (list (car par) (cadr par) (cons "oauth_signature" (perenc (make-signature meth url par)))) (cddr par))))
    (with-output-to-string (strm)
      (princ "OAuth " strm)
      (format strm "~a=~s" (caar par) (cdar par))
      (mapc (lambda (x)
          (format strm ", ~a=~s" (car x) (if (cdr x)
                           (cdr x)
                           "")))
        (cdr par)))))

(setf drakma:*drakma-default-external-format* :utf-8)
(pushnew (cons "application" "xml") drakma:*text-content-types* :test 'equal)

(defun get-token ()
  (format nil "~a"
      (drakma:http-request *request-token-uri*
                   :method :post
                   :additional-headers `(,(cons "Authorization" (make-header "POST" *request-token-uri*))))))

これでget-tokenを呼び出すとoauth-tokenとoauth-secretが帰ってくるから,oauth-tokenをパラメータとしてブラウザで認証ページを開くと見慣れたページが出てくる.

f:id:sek4i:20140830150730p:plain

subseqとformatを使った文字列操作に持っていったのでもっとやりようはありそうな気がしてる.パーセントエンコードする関数はとりあえずここまででは問題ないけれど,ちゃんとした実装しないとTweetできない.

ここまでくればTweetできるまで後少し(多分)