日々是好日

プログラミングについてのあれこれ、ムダ知識など

VSCode 拡張機能開発で OAuth 認証 - 3 <終>

最終的にこんな形になりました。Promise ベースで Http リクエストを送れるrequest-promiseモジュールを新たに導入しました。

startOAuth = async () => {
    const oauth = new OAuth.OAuth(...);

    //RequestTokenの取得
    oauth.getOAuthRequestToken({
        'scope': ...
    }, async (err, request_token, request_token_secret, results) => {
        if (err !== null){
            console.log(err);
        } else {
            //はてなログイン処理
            this.getRK()
            .then((rk) => {
                //許可ボタン押下のためrkmを取得
                return this.getRKM(request_token, rk as string);
            })
            .then((arr) => {
                ...
                //verifierを取得。arr = {'rk': rk, 'rkm': rkm}が格納
                return this.getVerifier(request_token, arr.rk, arr.rkm);
            })
            .then((verifier) => {
                ...
                //AccessTokenを取得
                oauth.getOAuthAccessToken(..., (...) => {
                    ...
                    console.log(">>>Congraturations!!<<<");
                    console.log('AccessToken: ' + accessToken);
                    console.log('AccessTokenSecret: ' + accessTokenSecret);
                    console.log('ParsedQueryString: ' + parsedQueryString);
                });
            })
            .catch((err) => {
                console.log(err);
            });
        }
    };

Promise チェーンを作って非同期処理を順次実行するようにしました。

oauth.getOAuthRequestToken及びoauth.getOAuthAccessTokenはコールバックで値を返すため、返り値がvoidです。
どうにか Promise チェーンに絡めたかったのですが、諦めてコールバック形式にしました。

以下各ステップのメソッド実装。なおrprequest-promiseモジュールのインスタンスです。

import * as rp from 'request-promise';

//はてなログイン処理
private getRK = async () => {
    //ヘッダーを定義
    const headers = {'Content-Type':'application/json'};

    //オプションを定義
    const loginOptions = {
        url: api.LOGIN_URL,
        method: 'POST',
        headers: headers,
        json: true,
        form: this.user,
        resolveWithFullResponse: true
    };

    return await rp(loginOptions)
    .then((response) => {
        const cookie = response.headers['set-cookie'];
        if (cookie !== undefined){
            const _rk = (cookie as string[])[5].match("(rk=.*); domain");
            if (_rk !== null){
                const rk = _rk[1];
                console.log('rk: ' + rk);
                return rk;
            }
        } else {
            return null;
        }
    });
}

//許可ボタン押下のためrkm取得
private getRKM = async (requestToken: string, rk: string) => {
    const reqTokenOptions = {
        url: api.RES_OWNER_AUTH_URL,
        qs: { oauth_token: requestToken },
        method: 'GET',
        headers: { cookie: rk }
    };

    return await rp(reqTokenOptions)
    .then((response) => {
        const _rkm = response.match("name=\"rkm\" value=\"(.*)\"");
        if (_rkm !== null){
            const rkm = _rkm[1];
            console.log('rkm: ' + rkm);
            return {'rk': rk, 'rkm': rkm as string};
        } else {
            return null;
        }
    });
}

//verifier取得
private getVerifier = async (requestToken: string, rk: string, rkm: string) => {
    const verifierOptions = {
        url: api.RES_OWNER_AUTH_URL,
        qs: { oauth_token: requestToken, rkm: rkm },
        method: 'POST',
        headers: { cookie: rk }
    };

    return await rp(verifierOptions)
    .then((response) => {
        const _verifier = response.match("<div class=verifier><pre>(.*)</pre></div>");
        if (_verifier !== null){
            const verifier = _verifier[1];
            console.log('verifier: ' + verifier);
            return verifier as string;
        } else {
            return null;
        }
    });
}

ひとつ注意点ですが、getRKMの返り値は{'rk': rk, 'rkm': rkm as string}となっています。
これは次のgetVerifierにおいて、rkrkmの2つの値が必要となるためです。

まあまあいい形に収まったと思いますので、本連載はこれで終了とします。次は API を叩く実装か Kotlin ネタに戻るか……。