twitter.c ー ①ー3

twitterAPI利用プログラム作成に向けて。

 

① httpメッセージの作成

② tcpでtwitterAPI提供サーバにつなぎ、(https用ポート)sslコネクションも作る

③ リクエストの送信

④ RestAPIではメッセージを全て受信し、解析

  StreamingAPIではメッセージを随時読み込み、解析

 

①ー1 oauth_nonce を作る

①ー2 oauth_timestamp を作る

①ー3 oauth_signature を作る(一番大変)

①ー4 ちょちょいのちょいでできる

 


なお、全て説明したら全体のソースコードも掲載する予定です。

今回はもろくそめんどいです。
詳しくは、こちらを参照。
https://dev.twitter.com/docs/auth/creating-signature


まず必要なものを挙げると、
①POSTかGETか
②baseurl(リクエストパラメータの部分を抜いたurl)
③リクエストパラメータおよびoauthのパラメータ(oauth_signatureを除く)

となります。
ここでは、リクエストパラメータのリストおよびoauthのパラメータのリストは外で作ってもらって、
その全て入った配列を受け取ることとします。(url.c用いて下みたいな感じで。)
   int k;
   char *pn = twi_mk_nonce();
   char *pt = itoa(time(NULL));
   printf("[time]\n%s\n", pt);
   char *oauth_key[7] = {"oauth_consumer_key", "oauth_nonce", "oauth_signature", "oauth_signature_method", "oauth_timestamp", "oauth_token", "oauth_version"};
   char *oauth_val[7] = {CONSUMER_KEY, pn, NULL, "HMAC-SHA1", pt, TOKEN, "1.0"};
   char base[100], host[100], pass[100], param[100];
   url_parse(url, NULL, base, host, pass, param);
   char *key[100], *value[100];
   int pnum = 0;
   url_parse_parameter(param, &pnum, key, value);
   url_parse_parameter(content, &pnum, key, value);
   for(k = 0; k < 7; ++k){
      key[pnum] = oauth_key[k];
      value[pnum] = oauth_val[k];
      pnum++;
   }
   char *ps = twi_mk_signature(GorP, base, &pnum, key, value);
   oauth_val[2] = ps;
このtwi_mk_signature関数を作るわけです。
まず、関数を先にのせることにします。
// make signature, key and value must be percent encoded
char *twi_mk_signature(int GorP, char *base, int *pnum, char **key, char **value){
   printf("[make_signature]\n");
// sort parameters
   twi_ssort(*pnum, key, value);
// make parameter string
   char ps[5000];
   int k, ofst = 0;
   for(k = 0; k < *pnum; ++k){
      if(value[k] == NULL) continue;
      ofst += sprintf(ps + ofst, "%s=%s%s", key[k], value[k], (k == *pnum - 1) ? "" : "&");
   }
   printf("parameter string : \n%s\n", ps);
// make signature base string
   char sbs[5000];
   char *base_en = url_encode(base, strlen(base));
   char *para_en = url_encode(ps, strlen(ps));
   sprintf(sbs, "%s&%s&%s", (GorP == 0) ? "GET" : "POST", base_en, para_en);
   printf("signature base string : \n%s\n", sbs);
   free(base_en);
   free(para_en);
// make signing key
   char sk[strlen(CONSUMER_SEC) + strlen(TOKEN_SEC) + 2];
   sprintf(sk, "%s&%s", CONSUMER_SEC, TOKEN_SEC);
   printf("signing key : \n%s\n", sk);
// HMAC
   char res[20];
   unsigned int reslen;
   HMAC(EVP_sha1(), sk, strlen(sk), (unsigned char *)sbs, strlen(sbs), (unsigned char *)res, &reslen);
   printf("signature : \n  20Byte : ");
   for(k = 0; k < 20; ++k) printf("%02X ", (unsigned char)res[k]);
   char *res_ben = b64_encode(res, 20);
   printf("\n  b64_en : %s\n", res_ben);
   char *res_pen = url_encode(res_ben, strlen(res_ben));
   printf("  url_en : %s\n", res_pen);
   free(res_ben);
   return res_pen;
}

void twi_ssort(int n, char **key, char **value){
   int k1, k2;
   char *tmpk, *tmpv;
   printf("sort : from{");
      for(k1 = 0; k1 < n; ++k1) printf("(%c|%c)%s", key[k1][0], (value[k1] != NULL)? value[k1][0] : ' ', (k1 == n - 1) ? "" : ",");
   printf("}\n");
   for(k1 = 0; k1 < n - 1; ++k1){
      for(k2 = k1 + 1; k2 < n; ++k2){
   if(strcmp(key[k1], key[k2]) > 0){
      tmpk = key[k1];
      tmpv = value[k1];
      key[k1] = key[k2];
      value[k1] = value[k2];
      key[k2] = tmpk;
      value[k2] = tmpv;
   }
      }
   }
   printf("     :   to{");
   for(k1 = 0; k1 < n; ++k1) printf("(%c|%c)%s", key[k1][0], (value[k1] != NULL)? value[k1][0] : ' ', (k1 == n - 1) ? "" : ",");
   printf("}\n");
}

やることは4つ。
 ①parameter stringの作成
 ②signature base stringの作成
 ③signing key の作成
 ④上のパラメータをもとにHMACしてでてきた20byteのやつをbase64エンコーディングしてurlエンコーディング
これで、oauth_signatureができるわけです。
ひとつずつ説明していきます。

①parameter stringの作成
パラメータをkeyでソートしてつなげます。
ここでは数も少ないですし、適当にsimplesort関数を作ってしています。

oauth_consumer_key=2B------------------mQ&oauth_nonce=P6---------------------------------------------9o&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1391867636&oauth_token=16----------12-RE--------------------------------------------iY&oauth_version=1.0&replies=all
みたいなのを作ればOKです。

②signature base stringの作成
上で作ったのとbaseURLをurlエンコードし、GETまたはPOSTと&でつなぎます。
下のような感じになります。

GET&https%3A%2F%2Fuserstream.twitter.com%2F1.1%2Fuser.json&oauth_consumer_key%3D2B------------------mQ%26oauth_nonce%3DP6---------------------------------------------9o%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1391867636%26oauth_token%3D16----------12-RE--------------------------------------------iY%26oauth_version%3D1.0%26replies%3Dall

③signing keyの作成
twitter Developers でアプリの登録をしたら発行できる、
Consumer secret と OAuth token secret
を&でつなげるだけです。

④HMACでsignatureを発行
よくわかりませんが、ぐぐったらうまくできました。

openssl/hmac.hをインクルードしたら使える関数、
HMAC(EVP_sha1(), sk, strlen(sk), (unsigned char *)sbs, strlen(sbs), (unsigned char *)res, &reslen);
(sk : signing key, sbs : signature base string)

で、resに20バイトのものが格納されます。
あとはこれをbase64.cでbase64エンコード、url.cでurlエンコードすれば、oauth_signatureの完成です!やったね!

ちゃんと実行できれば、下のような出力が得られます。
[make_signature]
sort : from{(r|a),(o|2),(o|P),(o| ),(o|H),(o|1),(o|1),(o|1)}
     :   to{(o|2),(o|P),(o| ),(o|H),(o|1),(o|1),(o|1),(r|a)}
parameter string : 
oauth_consumer_key=2B------------------mQ&oauth_nonce=P6---------------------------------------------9o&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1391867636&oauth_token=16----------12-RE--------------------------------------------iY&oauth_version=1.0&replies=all
signature base string : 
GET&https%3A%2F%2Fuserstream.twitter.com%2F1.1%2Fuser.json&oauth_consumer_key%3D2B------------------mQ%26oauth_nonce%3DP6---------------------------------------------9o%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1391867636%26oauth_token%3D16----------12-RE--------------------------------------------iY%26oauth_version%3D1.0%26replies%3Dall
signing key : 
wc-------------------------------------------co&BV------------------------------------------------QC
signature : 
  20Byte : F3 F5 2F 3E 98 DE 6D C3 1E E7 D8 FB A7 AB BC 32 2E B3 C2 9E 
  b64_en : 8/UvPpjebcMe59j7p6u8Mi6zwp4=
  url_en : 8%2FUvPpjebcMe59j7p6u8Mi6zwp4%3D