juice-shop
78 строк · 3.4 Кб
1/*
2* Copyright (c) 2014-2024 Bjoern Kimminich & the OWASP Juice Shop contributors.
3* SPDX-License-Identifier: MIT
4*/
5
6import fs = require('fs')
7import { type Request, type Response, type NextFunction } from 'express'
8import { challenges } from '../data/datacache'
9
10import { UserModel } from '../models/user'
11import challengeUtils = require('../lib/challengeUtils')
12import config from 'config'
13import * as utils from '../lib/utils'
14import { AllHtmlEntities as Entities } from 'html-entities'
15const security = require('../lib/insecurity')
16const pug = require('pug')
17const themes = require('../views/themes/themes').themes
18const entities = new Entities()
19
20module.exports = function getUserProfile () {
21return (req: Request, res: Response, next: NextFunction) => {
22fs.readFile('views/userProfile.pug', function (err, buf) {
23if (err != null) throw err
24const loggedInUser = security.authenticatedUsers.get(req.cookies.token)
25if (loggedInUser) {
26UserModel.findByPk(loggedInUser.data.id).then((user: UserModel | null) => {
27let template = buf.toString()
28let username = user?.username
29if (username?.match(/#{(.*)}/) !== null && utils.isChallengeEnabled(challenges.usernameXssChallenge)) {
30req.app.locals.abused_ssti_bug = true
31const code = username?.substring(2, username.length - 1)
32try {
33if (!code) {
34throw new Error('Username is null')
35}
36username = eval(code) // eslint-disable-line no-eval
37} catch (err) {
38username = '\\' + username
39}
40} else {
41username = '\\' + username
42}
43const theme = themes[config.get<string>('application.theme')]
44if (username) {
45template = template.replace(/_username_/g, username)
46}
47template = template.replace(/_emailHash_/g, security.hash(user?.email))
48template = template.replace(/_title_/g, entities.encode(config.get<string>('application.name')))
49template = template.replace(/_favicon_/g, favicon())
50template = template.replace(/_bgColor_/g, theme.bgColor)
51template = template.replace(/_textColor_/g, theme.textColor)
52template = template.replace(/_navColor_/g, theme.navColor)
53template = template.replace(/_primLight_/g, theme.primLight)
54template = template.replace(/_primDark_/g, theme.primDark)
55template = template.replace(/_logo_/g, utils.extractFilename(config.get('application.logo')))
56const fn = pug.compile(template)
57const CSP = `img-src 'self' ${user?.profileImage}; script-src 'self' 'unsafe-eval' https://code.getmdl.io http://ajax.googleapis.com`
58// @ts-expect-error FIXME type issue with string vs. undefined for username
59challengeUtils.solveIf(challenges.usernameXssChallenge, () => { return user?.profileImage.match(/;[ ]*script-src(.)*'unsafe-inline'/g) !== null && utils.contains(username, '<script>alert(`xss`)</script>') })
60
61res.set({
62'Content-Security-Policy': CSP
63})
64
65res.send(fn(user))
66}).catch((error: Error) => {
67next(error)
68})
69} else {
70next(new Error('Blocked illegal activity by ' + req.socket.remoteAddress))
71}
72})
73}
74
75function favicon () {
76return utils.extractFilename(config.get('application.favicon'))
77}
78}
79