angular.js+chrome_ex_oauth
angular.jsを使いつつ、chrome_ex_oauthを使ってTwitter APIを使うデモとか出来るんじゃないかなーって思ってやってみた
manifest.json
{
"name": "sample",
"version": "0.1",
"manifest_version": 2,
"background": {
"scripts": [
"js/angular.js",
"js/chrome_ex_oauth.js",
"js/chrome_ex_oauthsimple.js",
"const.js",
"background.js"
]
},
"content_scripts": [
{
"matches": ["https://api.twitter.com/oauth/authorize"],
"js": ["content_script.js"],
"run_at": "document_idle"
}
],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": ["https://api.twitter.com/*"],
"content_security_policy": "script-src 'self' 'unsafe-eval';object-src 'self'"
}
Twitter APIだとoauth_callback?でchrome-extension://な方式が使えない以前に、通常のアプリケーション方式だとリクエストトークンを取得する時点でoauth_callbackパラメーターが許容されない為、authorizeからのアクセストークンを取得する流れをコントロールする必要がある。そこはコンテントスクリプトを使ってアクセストークンを取得して保管する
popup.html
<html ng-app>
<head>
<script src="js/angular.js"></script>
<script src="js/chrome_ex_oauth.js"></script>
<script src="js/chrome_ex_oauthsimple.js"></script>
<script src="const.js"></script>
<script src="popup.js"></script>
<link rel="stylesheet" type="text/css" href="popup.css" />
</head>
<body>
<div ng-controller="TwitterController">
<div ng-repeat="tweet in tweets" class="tweet">
<div class="tweet-icon">
<img ng-src="{% raw %}{{tweet.user.profile_image_url_https}}{% endraw %}" />
</div>
<div class="tweet-text">{% raw %}{{tweet.text}}{% endraw %}</div>
<div style="clear: both"></div>
</div>
</div>
</body>
</html>
まぁ特にangular.js特有なの以外は無いので(ry
popup.js
var TwitterController = (function() {
function TwitterController($scope, $http) {
var bgPage = chrome.extension.getBackgroundPage();
bgPage.authorize(function() {
// APIエンドポイントにOAuthパラメーター関係を付与したURLを作る
bgPage.signURL(
"https://api.twitter.com/1.1/statuses/home_timeline.json",
"GET",
function(url) {
$http.get(url).success(function(tweets) {
$scope.tweets = tweets;
});
}
);
});
}
return TwitterController;
})();
angular.jsなコントローラーにchrome API依存するのもどうかとは思いますけど...
要は認証されていればTwitter APIからタイムラインを取得する。認証されてなければChromeExOAuth方式の認証フローに入るっていう感じ
background.js
var oauth = ChromeExOAuth.initBackgroundPage({
consumer_key: CONSUMER_KEY,
consumer_secret: CONSUMER_SECRET,
request_url: "https://api.twitter.com/oauth/request_token",
authorize_url: "https://api.twitter.com/oauth/authorize",
access_url: "https://api.twitter.com/oauth/access_token",
scope: "_chrome_extension_angularjs_twitter_oauth_demo"
});
oauth.callback_page = "callback.html";
window.authorize = function(callback) {
oauth.authorize(callback);
};
window.signURL = function(url, method, callback) {
var url = oauth.signURL(url, method);
callback(url);
};
chrome.runtime.onMessage.addListener(function(req, sender, res) {
oauth.getAccessToken(oauth.getToken(), req.verifier, function() {
res(true);
});
return true;
});
コンテントスクリプトから来たauthorizeをverifyするPINコードを受け取ったらそれを利用してアクセストークンを取得する
callback.html
<html>
<head>
<script src="js/chrome_ex_oauth.js"></script>
<script src="js/chrome_ex_oauthsimple.js"></script>
</head>
<body>
<script src="callback.js"></script>
</body>
</html>
callback.js
ChromeExOAuth.initCallbackPage();
ただのChromeExOAuthによる認証フロー開始するだけなので(ry
content_script.js
var pin = prompt("Enter the PIN displayed by Twitter");
chrome.runtime.sendMessage({ "verifier": pin }, function(isSuccess) {
if (isSuccess === true) {
alert("Authorized, woot!");
}
});
とここまでがChrome拡張になる訳。あとはビルド(crx生成)するなりで使う訳ですが、そのままでは動かない。chrome_ex_oauth.jsに所々問題があって動かない箇所があるので修正する必要がある
chrome_ex_oauth.jsの修正
487行目辺り
parameters: {
"xoauth_displayname" : this.app_name,
"scope" : this.oauth_scope,
// "oauth_callback" : url_callback
}
oauth_callbackが入ってるとリクエストトークンを取得する時点でエラー起こすのでoauth_callbackをパラメーターとして入れないように
514行目辺り
var token = params["oauth_token"];
this.setToken(token);
コンテントスクリプトからバックグランドページにsendMessageを行なってアクセストークンを取得するフローにおいてトークンが必要となるがトークン鍵はlocalStorageに保管されているが、トークン自体は保管されていないのでフロー上でundefinedになってしまう。なのでトークンもlocalStorageに保管しておく
但し、認証状態がtrueになるのはlocalStorageにトークンとトークン鍵があるかがチェックされるので、認証フローが途中で失敗した場合等にはChromeExOAuth#clearTokensを利用して取得しているリクエストトークンを保管しておかない等の工夫が若干必要になる
あくまでこの修正が必要なのはchrome_ex_oauthでTwitter APIを使う場合にのみ限られるのでは無いかと(もしかしたらDropboxも)
以上を行なって拡張機能をインストールして認証すると
っていうようにchrome_ex_oauthでOAuthを利用したREST API等をChrome Extensionでangular.jsを使いつつ出来るっていう感じで