fix(gist-export): validate OAuth2 state and redirect URI
The state of the OAuth2 response was not verified. In theory an attacker could use this to extract the contents of a note. Co-authored-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
114
lib/response.js
114
lib/response.js
@@ -65,69 +65,73 @@ function githubActions (req, res, next) {
|
||||
function githubActionGist (req, res, note) {
|
||||
const code = req.query.code
|
||||
const state = req.query.state
|
||||
if (!code || !state) {
|
||||
const sessionsState = req.session.githubGistState
|
||||
const redirectUri = req.session.githubGistRedirectUri
|
||||
delete req.session.githubGistState
|
||||
delete req.session.githubGistRedirectUri
|
||||
if (!code || !state || sessionsState !== state) {
|
||||
return errors.errorForbidden(res)
|
||||
} else {
|
||||
const data = {
|
||||
client_id: config.github.clientID,
|
||||
client_secret: config.github.clientSecret,
|
||||
code,
|
||||
state
|
||||
}
|
||||
|
||||
const data = {
|
||||
client_id: config.github.clientID,
|
||||
client_secret: config.github.clientSecret,
|
||||
code,
|
||||
redirect_uri: redirectUri
|
||||
}
|
||||
const authUrl = 'https://github.com/login/oauth/access_token'
|
||||
fetch(authUrl, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
}
|
||||
const authUrl = 'https://github.com/login/oauth/access_token'
|
||||
fetch(authUrl, {
|
||||
}).then(resp => {
|
||||
if (!resp.ok) {
|
||||
throw new Error('forbidden')
|
||||
}
|
||||
return resp.json()
|
||||
}).then(body => {
|
||||
const accessToken = body.access_token
|
||||
if (!accessToken) {
|
||||
throw new Error('forbidden')
|
||||
}
|
||||
const content = note.content
|
||||
const title = models.Note.decodeTitle(note.title)
|
||||
const filename = title.replace('/', ' ') + '.md'
|
||||
const gist = {
|
||||
files: {}
|
||||
}
|
||||
gist.files[filename] = {
|
||||
content
|
||||
}
|
||||
const gistUrl = 'https://api.github.com/gists'
|
||||
return fetch(gistUrl, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
body: JSON.stringify(gist),
|
||||
headers: {
|
||||
'User-Agent': 'HedgeDoc',
|
||||
Authorization: 'token ' + accessToken,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
}
|
||||
}).then(resp => {
|
||||
if (!resp.ok) {
|
||||
throw new Error('forbidden')
|
||||
}
|
||||
return resp.json()
|
||||
}).then(body => {
|
||||
const accessToken = body.access_token
|
||||
if (!accessToken) {
|
||||
throw new Error('forbidden')
|
||||
}
|
||||
const content = note.content
|
||||
const title = models.Note.decodeTitle(note.title)
|
||||
const filename = title.replace('/', ' ') + '.md'
|
||||
const gist = {
|
||||
files: {}
|
||||
}
|
||||
gist.files[filename] = {
|
||||
content
|
||||
}
|
||||
const gistUrl = 'https://api.github.com/gists'
|
||||
return fetch(gistUrl, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(gist),
|
||||
headers: {
|
||||
'User-Agent': 'HedgeDoc',
|
||||
Authorization: 'token ' + accessToken,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
}
|
||||
})
|
||||
}).then(resp => {
|
||||
if (resp.status !== 201) {
|
||||
throw new Error('forbidden')
|
||||
}
|
||||
return resp.json()
|
||||
}).then(body => {
|
||||
res.setHeader('referer', '')
|
||||
res.redirect(body.html_url)
|
||||
}).catch(error => {
|
||||
if (error.message === 'forbidden') {
|
||||
return errors.errorForbidden(res)
|
||||
}
|
||||
logger.error('GitHub Gist auth failed: ' + error)
|
||||
return errors.errorInternalError(res)
|
||||
})
|
||||
}
|
||||
}).then(resp => {
|
||||
if (resp.status !== 201) {
|
||||
throw new Error('forbidden')
|
||||
}
|
||||
return resp.json()
|
||||
}).then(body => {
|
||||
res.setHeader('referer', '')
|
||||
res.redirect(body.html_url)
|
||||
}).catch(error => {
|
||||
if (error.message === 'forbidden') {
|
||||
return errors.errorForbidden(res)
|
||||
}
|
||||
logger.error('GitHub Gist auth failed: ' + error)
|
||||
return errors.errorInternalError(res)
|
||||
})
|
||||
}
|
||||
|
||||
function gitlabActions (req, res, next) {
|
||||
|
||||
Reference in New Issue
Block a user