juice-shop

Форк
0
/
utils.ts 
234 строки · 7.0 Кб
1
/*
2
 * Copyright (c) 2014-2024 Bjoern Kimminich & the OWASP Juice Shop contributors.
3
 * SPDX-License-Identifier: MIT
4
 */
5

6
/* jslint node: true */
7
import packageJson from '../package.json'
8
import fs from 'fs'
9
import logger from './logger'
10
import config from 'config'
11
import jsSHA from 'jssha'
12
import download from 'download'
13
import crypto from 'crypto'
14
import clarinet from 'clarinet'
15
import type { Challenge } from 'data/types'
16

17
import isHeroku from './is-heroku'
18
import isDocker from './is-docker'
19
import isWindows from './is-windows'
20
export { default as isDocker } from './is-docker'
21
export { default as isWindows } from './is-windows'
22
// import isGitpod from 'is-gitpod') // FIXME Roll back to this when https://github.com/dword-design/is-gitpod/issues/94 is resolve
23
const isGitpod = () => false
24

25
const months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
26

27
export const queryResultToJson = <T>(
28
  data: T,
29
  status: string = 'success'
30
): { data: T, status: string } => {
31
  return {
32
    status,
33
    data
34
  }
35
}
36

37
export const isUrl = (url: string) => {
38
  return startsWith(url, 'http')
39
}
40

41
export const startsWith = (str: string, prefix: string) => str ? str.indexOf(prefix) === 0 : false
42

43
export const endsWith = (str?: string, suffix?: string) => (str && suffix) ? str.includes(suffix, str.length - suffix.length) : false
44

45
export const contains = (str: string, element: string) => str ? str.includes(element) : false // TODO Inline all usages as this function is not adding any functionality to String.includes
46

47
export const containsEscaped = function (str: string, element: string) {
48
  return contains(str, element.replace(/"/g, '\\"'))
49
}
50

51
export const containsOrEscaped = function (str: string, element: string) {
52
  return contains(str, element) || containsEscaped(str, element)
53
}
54

55
export const unquote = function (str: string) {
56
  if (str && startsWith(str, '"') && endsWith(str, '"')) {
57
    return str.substring(1, str.length - 1)
58
  } else {
59
    return str
60
  }
61
}
62

63
export const trunc = function (str: string, length: number) {
64
  str = str.replace(/(\r\n|\n|\r)/gm, '')
65
  return (str.length > length) ? str.substr(0, length - 1) + '...' : str
66
}
67

68
export const version = (module?: string) => {
69
  if (module) {
70
    // @ts-expect-error FIXME Ignoring any type issue on purpose
71
    return packageJson.dependencies[module]
72
  } else {
73
    return packageJson.version
74
  }
75
}
76

77
let cachedCtfKey: string | undefined
78
const getCtfKey = () => {
79
  if (!cachedCtfKey) {
80
    if (process.env.CTF_KEY !== undefined && process.env.CTF_KEY !== '') {
81
      cachedCtfKey = process.env.CTF_KEY
82
    } else {
83
      const data = fs.readFileSync('ctf.key', 'utf8')
84
      cachedCtfKey = data
85
    }
86
  }
87
  return cachedCtfKey
88
}
89
export const ctfFlag = (text: string) => {
90
  const shaObj = new jsSHA('SHA-1', 'TEXT') // eslint-disable-line new-cap
91
  shaObj.setHMACKey(getCtfKey(), 'TEXT')
92
  shaObj.update(text)
93
  return shaObj.getHMAC('HEX')
94
}
95

96
export const toMMMYY = (date: Date) => {
97
  const month = date.getMonth()
98
  const year = date.getFullYear()
99
  return months[month] + year.toString().substring(2, 4)
100
}
101

102
export const toISO8601 = (date: Date) => {
103
  let day = '' + date.getDate()
104
  let month = '' + (date.getMonth() + 1)
105
  const year = date.getFullYear()
106

107
  if (month.length < 2) month = '0' + month
108
  if (day.length < 2) day = '0' + day
109

110
  return [year, month, day].join('-')
111
}
112

113
export const extractFilename = (url: string) => {
114
  let file = decodeURIComponent(url.substring(url.lastIndexOf('/') + 1))
115
  if (contains(file, '?')) {
116
    file = file.substring(0, file.indexOf('?'))
117
  }
118
  return file
119
}
120

121
export const downloadToFile = async (url: string, dest: string) => {
122
  try {
123
    const data = await download(url)
124
    fs.writeFileSync(dest, data)
125
  } catch (err) {
126
    logger.warn('Failed to download ' + url + ' (' + getErrorMessage(err) + ')')
127
  }
128
}
129

130
export const jwtFrom = ({ headers }: { headers: any }) => {
131
  if (headers?.authorization) {
132
    const parts = headers.authorization.split(' ')
133
    if (parts.length === 2) {
134
      const scheme = parts[0]
135
      const token = parts[1]
136

137
      if (/^Bearer$/i.test(scheme)) {
138
        return token
139
      }
140
    }
141
  }
142
  return undefined
143
}
144

145
export const randomHexString = (length: number): string => {
146
  return crypto.randomBytes(Math.ceil(length / 2)).toString('hex').slice(0, length)
147
}
148

149
export interface ChallengeEnablementStatus {
150
  enabled: boolean
151
  disabledBecause: string | null
152
}
153

154
type SafetyModeSetting = 'enabled' | 'disabled' | 'auto'
155

156
type isEnvironmentFunction = () => boolean
157

158
export function getChallengeEnablementStatus (challenge: Challenge,
159
  safetyModeSetting: SafetyModeSetting = config.get<SafetyModeSetting>('challenges.safetyMode'),
160
  isEnvironmentFunctions: {
161
    isDocker: isEnvironmentFunction
162
    isHeroku: isEnvironmentFunction
163
    isWindows: isEnvironmentFunction
164
    isGitpod: isEnvironmentFunction
165
  } = { isDocker, isHeroku, isWindows, isGitpod }): ChallengeEnablementStatus {
166
  if (!challenge?.disabledEnv) {
167
    return { enabled: true, disabledBecause: null }
168
  }
169

170
  if (safetyModeSetting === 'disabled') {
171
    return { enabled: true, disabledBecause: null }
172
  }
173

174
  if (challenge.disabledEnv?.includes('Docker') && isEnvironmentFunctions.isDocker()) {
175
    return { enabled: false, disabledBecause: 'Docker' }
176
  }
177
  if (challenge.disabledEnv?.includes('Heroku') && isEnvironmentFunctions.isHeroku()) {
178
    return { enabled: false, disabledBecause: 'Heroku' }
179
  }
180
  if (challenge.disabledEnv?.includes('Windows') && isEnvironmentFunctions.isWindows()) {
181
    return { enabled: false, disabledBecause: 'Windows' }
182
  }
183
  if (challenge.disabledEnv?.includes('Gitpod') && isEnvironmentFunctions.isGitpod()) {
184
    return { enabled: false, disabledBecause: 'Gitpod' }
185
  }
186
  if (challenge.disabledEnv && safetyModeSetting === 'enabled') {
187
    return { enabled: false, disabledBecause: 'Safety Mode' }
188
  }
189

190
  return { enabled: true, disabledBecause: null }
191
}
192
export function isChallengeEnabled (challenge: Challenge): boolean {
193
  const { enabled } = getChallengeEnablementStatus(challenge)
194
  return enabled
195
}
196

197
export const parseJsonCustom = (jsonString: string) => {
198
  const parser = clarinet.parser()
199
  const result: any[] = []
200
  parser.onkey = parser.onopenobject = (k: any) => {
201
    result.push({ key: k, value: null })
202
  }
203
  parser.onvalue = (v: any) => {
204
    result[result.length - 1].value = v
205
  }
206
  parser.write(jsonString)
207
  parser.close()
208
  return result
209
}
210

211
export const toSimpleIpAddress = (ipv6: string) => {
212
  if (startsWith(ipv6, '::ffff:')) {
213
    return ipv6.substr(7)
214
  } else if (ipv6 === '::1') {
215
    return '127.0.0.1'
216
  } else {
217
    return ipv6
218
  }
219
}
220

221
export const getErrorMessage = (error: unknown) => {
222
  if (error instanceof Error) return error.message
223
  return String(error)
224
}
225

226
export const matchesSystemIniFile = (text: string) => {
227
  const match = text.match(/; for 16-bit app support/gi)
228
  return match !== null && match.length >= 1
229
}
230

231
export const matchesEtcPasswdFile = (text: string) => {
232
  const match = text.match(/(\w*:\w*:\d*:\d*:\w*:.*)|(Note that this file is consulted directly)/gi)
233
  return match !== null && match.length >= 1
234
}
235

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.