import { ZError } from 'common/ZError' import BaseController, { ROLE_ANON } from 'common/base.controller' import { role, router } from 'decorators/router' import logger from 'logger/logger' import { AuthRecord } from 'modules/AuthRecord' import { exchangeTwitterCodeForToken, getOAuthAccessTokenWith, getOAuthRequestToken, getTwitterUserInfo, } from 'services/twitter.svr' import { parseOauthState } from 'utils/net.util' class TwitterController extends BaseController { @role(ROLE_ANON) @router('get /twitter/redirect_uri') async twitterRedirect(req, res) { // logger.info('twitter redirect: ', req.params) const { code, state } = req.params if (code && state) { const stateArr = parseOauthState(state) const address = stateArr[0].toLowerCase() const record = await AuthRecord.insertOrUpdate( { address, platform: 4 }, { address, platform: 4, $inc: { version: 1 } }, ) const vcode = stateArr[1] || stateArr[0] const tokenResponse = await exchangeTwitterCodeForToken(code, vcode) record.accessToken = tokenResponse.access_token record.refreshToken = tokenResponse.refresh_token record.scope = tokenResponse.scope record.tokenType = tokenResponse.token_type record.expiresIn = (Date.now() / 1000 + tokenResponse.expires_in || 0) | 0 await record.save() if (tokenResponse && tokenResponse.access_token) { const uinfo = await getTwitterUserInfo(tokenResponse.access_token) if (!uinfo.data) { logger.info('twitter user info: ', JSON.stringify(uinfo)) } record.nickname = uinfo.data?.name record.username = uinfo.data?.username record.openId = uinfo.data?.id if (uinfo.data?.profile_image_url) { record.avatar = uinfo.data?.profile_image_url.replace('_normal', '') } await record.save() } if (stateArr.length > 2) { return res.redirect(stateArr[2]) } } if (state) { const stateArr = parseOauthState(state) if (stateArr.length > 2) { return res.redirect(stateArr[2]) } } return res.view('/templates/twitter_redirect.ejs') } @role(ROLE_ANON) @router('get /twitter/oauth/:address') async twitterOauth(req, res) { let method = 'authenticate' let { address } = req.params if (!address) { throw new ZError(10, 'address needed') } address = address.toLowerCase() // @ts-ignore const { oauthRequestToken, oauthRequestTokenSecret } = await getOAuthRequestToken() logger.info( `twitter request token::oauthRequestToken:${oauthRequestToken},oauthRequestTokenSecret:${oauthRequestTokenSecret}`, ) req.session.oauthRequestToken = oauthRequestToken req.session.oauthRequestTokenSecret = oauthRequestTokenSecret req.session.address = address const authorizationUrl = `https://api.twitter.com/oauth/${method}?oauth_token=${oauthRequestToken}` logger.info('redirecting:', authorizationUrl) res.redirect(authorizationUrl) } // for twitter oauth v1.0 @role(ROLE_ANON) @router('get /twitter/callback') async twitterOauth1Callback(req, res) { const { address, oauthRequestToken, oauthRequestTokenSecret } = req.session logger.info('request.query', req.query) const { oauth_verifier: oauthVerifier } = req.query const { oauthAccessToken, oauthAccessTokenSecret, results } = await getOAuthAccessTokenWith({ oauthRequestToken, oauthRequestTokenSecret, oauthVerifier, }) const { user_id: userId /*, screen_name */ } = results logger.info('userId:', userId) const record = await AuthRecord.insertOrUpdate( { address, platform: 4 }, { address, platform: 4, $inc: { version: 1 } }, ) record.nickname = results.screen_name record.username = results.screen_name record.openId = results.user_id record.accessToken = oauthAccessToken record.refreshToken = oauthAccessTokenSecret record.tokenType = 'oauth1' await record.save() return res.view('/templates/twitter_redirect.ejs') } }