juice-shop
90 строк · 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 } from 'express'
8import challengeUtils = require('../lib/challengeUtils')
9import config from 'config'
10import * as utils from '../lib/utils'
11import { AllHtmlEntities as Entities } from 'html-entities'
12import { challenges } from '../data/datacache'
13
14const pug = require('pug')
15const themes = require('../views/themes/themes').themes
16const entities = new Entities()
17
18exports.getVideo = () => {
19return (req: Request, res: Response) => {
20const path = videoPath()
21const stat = fs.statSync(path)
22const fileSize = stat.size
23const range = req.headers.range
24if (range) {
25const parts = range.replace(/bytes=/, '').split('-')
26const start = parseInt(parts[0], 10)
27const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1
28const chunksize = (end - start) + 1
29const file = fs.createReadStream(path, { start, end })
30const head = {
31'Content-Range': `bytes ${start}-${end}/${fileSize}`,
32'Accept-Ranges': 'bytes',
33'Content-Length': chunksize,
34'Content-Location': '/assets/public/videos/owasp_promo.mp4',
35'Content-Type': 'video/mp4'
36}
37res.writeHead(206, head)
38file.pipe(res)
39} else {
40const head = {
41'Content-Length': fileSize,
42'Content-Type': 'video/mp4'
43}
44res.writeHead(200, head)
45fs.createReadStream(path).pipe(res)
46}
47}
48}
49
50exports.promotionVideo = () => {
51return (req: Request, res: Response) => {
52fs.readFile('views/promotionVideo.pug', function (err, buf) {
53if (err != null) throw err
54let template = buf.toString()
55const subs = getSubsFromFile()
56
57challengeUtils.solveIf(challenges.videoXssChallenge, () => { return utils.contains(subs, '</script><script>alert(`xss`)</script>') })
58
59const theme = themes[config.get<string>('application.theme')]
60template = template.replace(/_title_/g, entities.encode(config.get<string>('application.name')))
61template = template.replace(/_favicon_/g, favicon())
62template = template.replace(/_bgColor_/g, theme.bgColor)
63template = template.replace(/_textColor_/g, theme.textColor)
64template = template.replace(/_navColor_/g, theme.navColor)
65template = template.replace(/_primLight_/g, theme.primLight)
66template = template.replace(/_primDark_/g, theme.primDark)
67const fn = pug.compile(template)
68let compiledTemplate = fn()
69compiledTemplate = compiledTemplate.replace('<script id="subtitle"></script>', '<script id="subtitle" type="text/vtt" data-label="English" data-lang="en">' + subs + '</script>')
70res.send(compiledTemplate)
71})
72}
73function favicon () {
74return utils.extractFilename(config.get('application.favicon'))
75}
76}
77
78function getSubsFromFile () {
79const subtitles = config.get<string>('application.promotion.subtitles') ?? 'owasp_promo.vtt'
80const data = fs.readFileSync('frontend/dist/frontend/assets/public/videos/' + subtitles, 'utf8')
81return data.toString()
82}
83
84function videoPath () {
85if (config.get<string>('application.promotion.video') !== null) {
86const video = utils.extractFilename(config.get<string>('application.promotion.video'))
87return 'frontend/dist/frontend/assets/public/videos/' + video
88}
89return 'frontend/dist/frontend/assets/public/videos/owasp_promo.mp4'
90}
91