trusted-setup-server/server/controllers/authorize.js

187 lines
5.4 KiB
JavaScript
Raw Normal View History

/* eslint-disable no-console */
const crypto = require('crypto')
2020-01-29 12:30:50 +01:00
const express = require('express')
const router = express.Router()
const oauth = require('oauth')
2020-02-07 16:21:34 +01:00
const {
TWITTER_CONSUMER_KEY,
TWITTER_CONSUMER_SECRET,
TWITTER_CALLBACK_URL,
GITHUB_CLIEND_ID,
GITHUB_CLIENT_SECRET,
GITHUB_CALLBACK_URL
} = process.env
const providers = ['github', 'twitter']
2020-02-08 19:47:21 +01:00
const signInPages = ['/make-contribution', '/authorize-contribution']
2020-02-07 16:21:34 +01:00
// twitter uses OAuth1
const twitter = new oauth.OAuth(
2020-01-29 12:30:50 +01:00
'https://twitter.com/oauth/request_token',
'https://twitter.com/oauth/access_token',
2020-02-07 16:21:34 +01:00
TWITTER_CONSUMER_KEY,
TWITTER_CONSUMER_SECRET,
2020-01-29 12:30:50 +01:00
'1.0A',
2020-02-07 16:21:34 +01:00
TWITTER_CALLBACK_URL,
2020-01-29 12:30:50 +01:00
'HMAC-SHA1'
)
2020-02-07 16:21:34 +01:00
// github uses OAuth2
const github = new oauth.OAuth2(
GITHUB_CLIEND_ID,
GITHUB_CLIENT_SECRET,
'https://github.com/',
'login/oauth/authorize',
'login/oauth/access_token'
)
github.useAuthorizationHeaderforGET(true)
2020-01-30 13:15:42 +01:00
function validateProvider(req, res, next) {
2020-02-07 16:21:34 +01:00
const { provider } = req.params
if (!providers.includes(provider)) {
res.status(404).send('Wrong provider')
} else {
next()
2020-02-07 16:21:34 +01:00
}
}
2020-02-08 19:47:21 +01:00
function validateRefferer(req, res, next) {
let referrer
try {
referrer = new URL(req.get('Referrer'))
} catch (e) {
res.status(403).send('Access forbidden')
return
}
if (!signInPages.includes(referrer.pathname)) {
res.status(403).send('Access forbidden')
return
}
next()
}
function restrictSymbols(value) {
2020-05-01 12:32:02 +02:00
if (value) {
const regExpression = new RegExp('[^0-9a-zA-Z\\x20]', 'g')
return value.toString().replace(regExpression, '')
} else {
return ''
}
}
2020-02-08 19:47:21 +01:00
router.get('/connect/:provider', validateProvider, validateRefferer, (req, res) => {
const { provider } = req.params
2020-02-08 19:47:21 +01:00
const referrer = new URL(req.get('Referrer'))
req.session.pageToReturn = referrer.pathname // the page a user will be redirected after signIn
if (referrer.pathname === '/authorize-contribution') {
req.session.pageToReturn += referrer.search // to add `token` parameter for authorize-contribution page
}
2020-01-29 12:30:50 +01:00
2020-02-07 16:21:34 +01:00
if (provider === 'github') {
const CSRFToken = crypto.randomBytes(32).toString('hex')
2020-02-07 16:21:34 +01:00
const authorizeUrl = github.getAuthorizeUrl({
redirect_uri: GITHUB_CALLBACK_URL,
scope: [], // 'gist' - https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/
state: CSRFToken
2020-02-07 16:21:34 +01:00
})
req.session.CSRFToken = CSRFToken
2020-02-07 16:21:34 +01:00
res.redirect(authorizeUrl)
} else if (provider === 'twitter') {
twitter.getOAuthRequestToken(function(error, oauthToken, oauthTokenSecret) {
2020-01-29 12:30:50 +01:00
if (error) {
res.status(500).send(error)
} else {
2020-02-07 16:21:34 +01:00
req.session.oauthRequestToken = oauthToken
req.session.oauthRequestTokenSecret = oauthTokenSecret
res.redirect(
'https://twitter.com/oauth/authorize?oauth_token=' + req.session.oauthRequestToken
)
}
})
}
})
router.get('/oauth_callback/:provider', validateProvider, (req, res) => {
2020-02-07 16:21:34 +01:00
const { provider } = req.params
if (provider === 'github') {
const { code, state } = req.query
if (state !== req.session.CSRFToken) {
res.status(404).send('Malformed request')
return
}
github.getOAuthAccessToken(code, {}, function(error, accessToken, refreshToken, results) {
2020-02-07 16:21:34 +01:00
if (error || results.error) {
console.error('getOAuthAccessToken error', error || results.error)
2020-02-07 16:21:34 +01:00
res.status(500).send(error || results.error)
} else {
req.session.refreshToken = refreshToken
req.session.accessToken = accessToken
2020-02-08 19:47:21 +01:00
res.redirect(req.session.pageToReturn)
2020-01-29 12:30:50 +01:00
}
2020-02-07 16:21:34 +01:00
})
} else if (provider === 'twitter') {
twitter.getOAuthAccessToken(
req.query.oauth_token,
req.session.oauthRequestTokenSecret,
req.query.oauth_verifier,
(error, oauthAccessToken, oauthAccessTokenSecret) => {
if (error) {
console.error('getOAuthAccessToken error', error)
2020-02-07 16:21:34 +01:00
res.status(500).send(error)
} else {
req.session.oauthAccessToken = oauthAccessToken
req.session.oauthAccessTokenSecret = oauthAccessTokenSecret
2020-02-08 19:47:21 +01:00
res.redirect(req.session.pageToReturn)
2020-02-07 16:21:34 +01:00
}
}
)
}
})
router.get('/user_data/', (req, res) => {
let userData = { name: 'Anonymous' }
if (req.session.accessToken) {
github.get('https://api.github.com/user', req.session.accessToken, function(error, data) {
if (!error) {
userData = JSON.parse(data)
userData.name = restrictSymbols(userData.name)
2020-02-07 16:21:34 +01:00
userData.handle = userData.login
userData.socialType = 'github'
req.session.handle = userData.login
req.session.socialType = 'github'
}
res.json(userData)
})
} else if (req.session.oauthAccessToken && req.session.oauthAccessTokenSecret) {
twitter.get(
'https://api.twitter.com/1.1/account/verify_credentials.json',
req.session.oauthAccessToken,
req.session.oauthAccessTokenSecret,
function(error, data) {
if (!error) {
userData = JSON.parse(data)
userData.name = restrictSymbols(userData.name)
2020-02-07 16:21:34 +01:00
userData.handle = userData.screen_name
userData.socialType = 'twitter'
req.session.handle = userData.screen_name
req.session.socialType = 'twitter'
}
res.json(userData)
}
)
} else {
res.json(userData)
}
2020-01-29 12:30:50 +01:00
})
2020-02-06 16:32:24 +01:00
router.get('/logout', (req, res) => {
req.session.destroy()
res.send('OK')
2020-02-06 16:32:24 +01:00
})
2020-01-29 12:30:50 +01:00
module.exports = router