mirror of
https://codeberg.org/keyoxide/keyoxide-web.git
synced 2024-12-22 14:59:29 -07:00
feat: improve param escaping
This commit is contained in:
parent
255e99af39
commit
a57d24ad6a
3 changed files with 63 additions and 28 deletions
|
@ -28,12 +28,11 @@ if any, to sign a "copyright disclaimer" for the program, if necessary. For
|
||||||
more information on this, and how to apply and follow the GNU AGPL, see <https://www.gnu.org/licenses/>.
|
more information on this, and how to apply and follow the GNU AGPL, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { param } from 'express-validator'
|
|
||||||
import bodyParserImport from 'body-parser'
|
import bodyParserImport from 'body-parser'
|
||||||
import { rateLimit } from 'express-rate-limit'
|
import { rateLimit } from 'express-rate-limit'
|
||||||
import { generateSignatureProfile, utils, generateWKDProfile, generateHKPProfile, generateAutoProfile, generateKeybaseProfile } from '../server/index.js'
|
import { generateSignatureProfile, utils, generateWKDProfile, generateHKPProfile, generateAutoProfile, generateKeybaseProfile } from '../server/index.js'
|
||||||
import { Profile } from 'doipjs'
|
import { Profile } from 'doipjs'
|
||||||
import { generateProfileTheme, getMetaFromReq } from '../server/utils.js'
|
import { generateProfileTheme, getMetaFromReq, escapedParam } from '../server/utils.js'
|
||||||
import logger from '../log.js'
|
import logger from '../log.js'
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
@ -87,7 +86,7 @@ router.post('/sig',
|
||||||
|
|
||||||
router.get('/wkd/:id',
|
router.get('/wkd/:id',
|
||||||
profileRateLimiter,
|
profileRateLimiter,
|
||||||
param('id').escape(),
|
escapedParam('id'),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const data = await generateWKDProfile(req.params.id)
|
const data = await generateWKDProfile(req.params.id)
|
||||||
const title = utils.generatePageTitle('profile', data)
|
const title = utils.generatePageTitle('profile', data)
|
||||||
|
@ -103,7 +102,7 @@ router.get('/wkd/:id',
|
||||||
|
|
||||||
router.get('/hkp/:id',
|
router.get('/hkp/:id',
|
||||||
profileRateLimiter,
|
profileRateLimiter,
|
||||||
param('id').escape(),
|
escapedParam('id'),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const data = await generateHKPProfile(req.params.id)
|
const data = await generateHKPProfile(req.params.id)
|
||||||
const title = utils.generatePageTitle('profile', data)
|
const title = utils.generatePageTitle('profile', data)
|
||||||
|
@ -119,8 +118,8 @@ router.get('/hkp/:id',
|
||||||
|
|
||||||
router.get('/hkp/:server/:id',
|
router.get('/hkp/:server/:id',
|
||||||
profileRateLimiter,
|
profileRateLimiter,
|
||||||
param('server').escape(),
|
escapedParam('server'),
|
||||||
param('id').escape(),
|
escapedParam('id'),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const data = await generateHKPProfile(req.params.id, req.params.server)
|
const data = await generateHKPProfile(req.params.id, req.params.server)
|
||||||
const title = utils.generatePageTitle('profile', data)
|
const title = utils.generatePageTitle('profile', data)
|
||||||
|
@ -136,8 +135,8 @@ router.get('/hkp/:server/:id',
|
||||||
|
|
||||||
router.get('/keybase/:username/:fingerprint',
|
router.get('/keybase/:username/:fingerprint',
|
||||||
profileRateLimiter,
|
profileRateLimiter,
|
||||||
param('username').escape(),
|
escapedParam('username'),
|
||||||
param('fingerprint').escape(),
|
escapedParam('fingerprint'),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const data = await generateKeybaseProfile(req.params.username, req.params.fingerprint)
|
const data = await generateKeybaseProfile(req.params.username, req.params.fingerprint)
|
||||||
const title = utils.generatePageTitle('profile', data)
|
const title = utils.generatePageTitle('profile', data)
|
||||||
|
@ -153,7 +152,7 @@ router.get('/keybase/:username/:fingerprint',
|
||||||
|
|
||||||
router.get('/:id',
|
router.get('/:id',
|
||||||
profileRateLimiter,
|
profileRateLimiter,
|
||||||
param('id').escape(),
|
escapedParam('id'),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const data = await generateAutoProfile(req.params.id)
|
const data = await generateAutoProfile(req.params.id)
|
||||||
const theme = generateProfileTheme(data)
|
const theme = generateProfileTheme(data)
|
||||||
|
|
|
@ -28,7 +28,7 @@ if any, to sign a "copyright disclaimer" for the program, if necessary. For
|
||||||
more information on this, and how to apply and follow the GNU AGPL, see <https://www.gnu.org/licenses/>.
|
more information on this, and how to apply and follow the GNU AGPL, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { getMetaFromReq } from '../server/utils.js'
|
import { escapedParam, getMetaFromReq } from '../server/utils.js'
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
|
@ -38,43 +38,55 @@ router.get('/', function (req, res) {
|
||||||
router.get('/profile-url', function (req, res) {
|
router.get('/profile-url', function (req, res) {
|
||||||
res.render('util/profile-url', { meta: getMetaFromReq(req) })
|
res.render('util/profile-url', { meta: getMetaFromReq(req) })
|
||||||
})
|
})
|
||||||
router.get('/profile-url/:input', function (req, res) {
|
router.get('/profile-url/:input',
|
||||||
res.render('util/profile-url', { input: req.params.input, meta: getMetaFromReq(req) })
|
escapedParam('input'),
|
||||||
})
|
function (req, res) {
|
||||||
|
res.render('util/profile-url', { input: req.params.input, meta: getMetaFromReq(req) })
|
||||||
|
})
|
||||||
|
|
||||||
router.get('/qr', function (req, res) {
|
router.get('/qr', function (req, res) {
|
||||||
res.render('util/qr', { meta: getMetaFromReq(req) })
|
res.render('util/qr', { meta: getMetaFromReq(req) })
|
||||||
})
|
})
|
||||||
router.get('/qr/:input', function (req, res) {
|
router.get('/qr/:input',
|
||||||
res.render('util/qr', { input: req.params.input, meta: getMetaFromReq(req) })
|
escapedParam('input'),
|
||||||
})
|
function (req, res) {
|
||||||
|
res.render('util/qr', { input: req.params.input, meta: getMetaFromReq(req) })
|
||||||
|
})
|
||||||
|
|
||||||
router.get('/qrfp', function (req, res) {
|
router.get('/qrfp', function (req, res) {
|
||||||
res.render('util/qrfp', { meta: getMetaFromReq(req) })
|
res.render('util/qrfp', { meta: getMetaFromReq(req) })
|
||||||
})
|
})
|
||||||
router.get('/qrfp/:input', function (req, res) {
|
router.get('/qrfp/:input',
|
||||||
res.render('util/qrfp', { input: req.params.input, meta: getMetaFromReq(req) })
|
escapedParam('input'),
|
||||||
})
|
function (req, res) {
|
||||||
|
res.render('util/qrfp', { input: req.params.input, meta: getMetaFromReq(req) })
|
||||||
|
})
|
||||||
|
|
||||||
router.get('/wkd', function (req, res) {
|
router.get('/wkd', function (req, res) {
|
||||||
res.render('util/wkd', { meta: getMetaFromReq(req) })
|
res.render('util/wkd', { meta: getMetaFromReq(req) })
|
||||||
})
|
})
|
||||||
router.get('/wkd/:input', function (req, res) {
|
router.get('/wkd/:input',
|
||||||
res.render('util/wkd', { input: req.params.input, meta: getMetaFromReq(req) })
|
escapedParam('input'),
|
||||||
})
|
function (req, res) {
|
||||||
|
res.render('util/wkd', { input: req.params.input, meta: getMetaFromReq(req) })
|
||||||
|
})
|
||||||
|
|
||||||
router.get('/argon2', function (req, res) {
|
router.get('/argon2', function (req, res) {
|
||||||
res.render('util/argon2', { meta: getMetaFromReq(req) })
|
res.render('util/argon2', { meta: getMetaFromReq(req) })
|
||||||
})
|
})
|
||||||
router.get('/argon2/:input', function (req, res) {
|
router.get('/argon2/:input',
|
||||||
res.render('util/argon2', { input: req.params.input, meta: getMetaFromReq(req) })
|
escapedParam('input'),
|
||||||
})
|
function (req, res) {
|
||||||
|
res.render('util/argon2', { input: req.params.input, meta: getMetaFromReq(req) })
|
||||||
|
})
|
||||||
|
|
||||||
router.get('/bcrypt', function (req, res) {
|
router.get('/bcrypt', function (req, res) {
|
||||||
res.render('util/bcrypt', { meta: getMetaFromReq(req) })
|
res.render('util/bcrypt', { meta: getMetaFromReq(req) })
|
||||||
})
|
})
|
||||||
router.get('/bcrypt/:input', function (req, res) {
|
router.get('/bcrypt/:input',
|
||||||
res.render('util/bcrypt', { input: req.params.input, meta: getMetaFromReq(req) })
|
escapedParam('input'),
|
||||||
})
|
function (req, res) {
|
||||||
|
res.render('util/bcrypt', { input: req.params.input, meta: getMetaFromReq(req) })
|
||||||
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -30,6 +30,7 @@ more information on this, and how to apply and follow the GNU AGPL, see <https:/
|
||||||
import { webcrypto as crypto } from 'crypto'
|
import { webcrypto as crypto } from 'crypto'
|
||||||
import { Profile } from 'doipjs'
|
import { Profile } from 'doipjs'
|
||||||
import Color from 'colorjs.io'
|
import Color from 'colorjs.io'
|
||||||
|
import { param } from 'express-validator'
|
||||||
|
|
||||||
export async function computeWKDLocalPart (localPart) {
|
export async function computeWKDLocalPart (localPart) {
|
||||||
const localPartEncoded = new TextEncoder().encode(localPart.toLowerCase())
|
const localPartEncoded = new TextEncoder().encode(localPart.toLowerCase())
|
||||||
|
@ -152,3 +153,26 @@ export function generateProfileTheme (/** @type {Profile} */ profile) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reEmailLike = /(<[^\s@<>]+@[^\s@<>]+>)/
|
||||||
|
|
||||||
|
export function escapedParam(name) {
|
||||||
|
return param(name).customSanitizer(value => {
|
||||||
|
return value.split(reEmailLike).map(token => {
|
||||||
|
if (reEmailLike.test(token)) return token
|
||||||
|
return escape(token)
|
||||||
|
}).join('')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from https://github.com/validatorjs/validator.js/blob/b958bd7d1026a434ad3bf90064d3dcb8b775f1a9/src/lib/escape.js
|
||||||
|
function escape(input) {
|
||||||
|
return (input.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/\//g, '/')
|
||||||
|
.replace(/\\/g, '\')
|
||||||
|
.replace(/`/g, '`'))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue