facebook-node-sdk の初期化より先に session を有効化しないといけない
node.js で Facebook API 使うときに facebook-node-sdk つかってるんだけど、 loginRequired() の middleware つかったときに、アプリ新規承認時に redirect_uri に無限ループするということがあったりした。
で、出てたログが
DEBUG: DEBUG: CSRF state token does not match one provided.
で、redirect 前に設定してた CSRF Token が一致してないとのこと。
で、これがどこででてるかというと、
BaseFacebook.prototype.getCode = function() { var code = this.getRequestParam('code'); if (code !== null) { var state = this.getRequestParam('state'); if (this.state !== null && state !== null && this.state === state) { // CSRF state has done its job, so clear it this.state = null; this.clearPersistentData('state'); return code; } else { this.errorLog('CSRF state token does not match one provided.'); return false; } } return false; };
ここで、つまり、state がないか一致しないときに出てる。考えられる原因は、redirect 前にセットしてる state が set できてないか、戻ってきた時に違う state が入ってる or セットしたはずの state がとれてない、とかそういうかんじだとおもうんだけど、このときの state と this.state がどうなってるかというと (console.log !!)、
this.state: null state: 5GluXPtLoAzcvSYMJ1JU6Mm52J5DKd2u
つまり、
BaseFacebook.prototype.establishCSRFTokenState = function() { if (this.state === null) { var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var buf = []; for (var i = 0; i < 32; i++) { buf.push(chars[Math.floor(chars.length * Math.random())]); } this.state = buf.join(''); this.setPersistentData('state', this.state); } };
でセットされてるはずの state が無い。このロジック自体はあまりおかしくないかんじがする。 setPersistentData はというと、
Facebook.prototype.setPersistentData = function(key, value) { if (this.hasSession) { this.request.session[key] = value; } };
ということになってて、この hasSession が false になってた。あれ、session つかってるだけど、
function Facebook(config) { this.hasSession = !!(config.request && config.request.session); BaseFacebook.apply(this, arguments); }
で、中身をみてみると、 config.request はあるけど、 config.request.session がない。
app.js を見てみると、
app.use(facebook.middleware({appId: config.facebook.appId, secret: config.facebook.secret})); app.use(express.session({ secret: config.session.secret }));
あー、ってことで、
app.use(express.session({ secret: config.session.secret })); app.use(facebook.middleware({appId: config.facebook.appId, secret: config.facebook.secret}));
これで、治った。
ちなみに、なんでアプリ新規承認時のみ発生していたかというと、承認済みの場合、JavaScript SDK のほうの cookie でログインが完了しちゃってたからでした。
YAML で UNIQUE INDEX
uniqueConstraints をつかう。
Crocos\HogeBundle\Entity\Fuga: repositoryClass: Crocos\HogeBundle\Entity\FugaRepository type: entity table: hoge_fuga fields: hoge_id: id: true type: integer hoge_key: type: string length: 255 value: type: text uniqueConstraints: hoge_id_hoge_key: columns: [ hoge_id, hoge_key ]
heroku に redmine インストール
node.js から redmine 叩くものをつくっていたけど api のテスト用 redmine が欲しいと思って自分のサーバだと面倒だから heroku でも使ってみるか、ということでさっそくやってみた。
ほとんど以下リンク通りだったのでメモのみ。
- 思考の軌跡 » herokuでRedmine(1.2.1)を動かす(前編)
- 思考の軌跡 » herokuでRedmine(1.2.1)を動かす(後編)
- Gem Bundler – Manage your Ruby gems
- Getting Started with Rails 3.x on Heroku | Heroku Dev Center
- http://devcenter.heroku.com/articles/bamboo
Redmine 1.3 だったので、1.3-stable ブランチから派生した 1.3.0-for-heroku ブランチで作業。 vendor/gems/coderay-1.0.0 が 1.0.0 になってたのと、インストールする rails がのバージョンが違ったくらいで、ほぼ上記の通りでいけた。
で、heroku に push するだけ。migration はちょっと時間かかったな。スペックの問題かしら。
$ git push heroku +1.3.0-for-heroku:master
で、 node-redmine も issues だけ対応できた。テスト書かこう。(そのための redmine ...
facebook-node-sdk のマネして env から redmine の host と apikey 渡すようにして travis.ci でやってみたいと思っているのでそれでテストを書いてみよう。
OAuthException: An active access token must be used to query information about the current user
/me とかを user の access token じゃなくて アプリの access token とかで叩いちゃうと出るんだけど、そもそもその前に getUser() で user_id が 0 じゃないことを確認してから叩いても出ることがあったので調査してた。
- signedRequest から getUser する → user_id だけ persistentData に入る
- その後 API を一度も呼び出さないと accessToken は persistentData (session) に入らない
- 次のページで、signedRequest が無い (つまり、GETで普通にページ遷移)、かつ、session から user_id がとれた、かつ、session から accessToken はとれない、かつ、cookie からもとれない(JS SDK 経由のやつ)場合、userAccessToken がとれない
- こうなると getUser() のゼロチェックはすりぬけて /me を叩いてしまう
(いやそもそも↑の状況は結構発生させにくいんだけどたまにあるのよね)
Signed Request からデータ取得したときに User Access Token を session に入れればいいと思うんだけどなんでそうなってないんだっけ?>SDK
とりあえず override しちゃえとおもったけど Facebook::getUserAccessToken() は protected だったので hasUserAccessToken() をつくってチェックできるようにした。
express.cookieParser()
session つかうときはこれもいっしょにしないとこれが出る。
TypeError: Cannot read property 'connect.sid' of undefined
app.jsとかで。
app.configure(function(){ app.use(express.cookieParser()); .. app.use(express.session({ secret: config.session.secret })); }
php 5.4 debian package memo
わかっているダメな点
debug build
- symbol がやっぱりけされちゃう dh_split しないようにしたんだけど、というか、一応ビルド後のバイナリを見ると symbol あるように思えるんだけどなんでだっけ...
- fpm の debug 方法がわからない... thread だから?
TODO
cron.d にファイル置く場合の注意点
root 権限じゃないとダメ (BAD OWNER) なのは有名な話だけど、permission も 644 じゃないと (というか、owner 以外に w がついてると)だめだった
Sep 12 06:00:02 localhost /usr/sbin/cron[8974]: (*system*xxxxx) WRONG INODE INFO (/etc/cron.d/xxxxx)
symlink で管理してる場合は、ファイル本体の permission と owner を root, 644 にしないとですね。