mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-27 10:19:26 -05:00
113 lines
3.0 KiB
TypeScript
113 lines
3.0 KiB
TypeScript
import * as inject from './inject'
|
|
import * as astRewriter from './ast-rewriter'
|
|
import * as regexRewriter from './regex-rewriter'
|
|
import type { CypressWantsInjection } from '../../types'
|
|
import type { AutomationCookie } from '@packages/server/lib/automation/cookies'
|
|
|
|
export type SecurityOpts = {
|
|
isNotJavascript?: boolean
|
|
url: string
|
|
useAstSourceRewriting: boolean
|
|
modifyObstructiveThirdPartyCode: boolean
|
|
modifyObstructiveCode: boolean
|
|
deferSourceMapRewrite: (opts: any) => string
|
|
}
|
|
|
|
export type InjectionOpts = {
|
|
domainName: string
|
|
wantsInjection: CypressWantsInjection
|
|
wantsSecurityRemoved: any
|
|
simulatedCookies: AutomationCookie[]
|
|
}
|
|
|
|
const doctypeRe = /<\!doctype.*?>/i
|
|
const headRe = /<head(?!er).*?>/i
|
|
const bodyRe = /<body.*?>/i
|
|
const htmlRe = /<html.*?>/i
|
|
|
|
function getRewriter (useAstSourceRewriting: boolean) {
|
|
return useAstSourceRewriting ? astRewriter : regexRewriter
|
|
}
|
|
|
|
function getHtmlToInject (opts: InjectionOpts & SecurityOpts) {
|
|
const {
|
|
domainName,
|
|
wantsInjection,
|
|
modifyObstructiveThirdPartyCode,
|
|
modifyObstructiveCode,
|
|
simulatedCookies,
|
|
} = opts
|
|
|
|
switch (wantsInjection) {
|
|
case 'full':
|
|
return inject.full(domainName)
|
|
case 'fullCrossOrigin':
|
|
return inject.fullCrossOrigin({
|
|
modifyObstructiveThirdPartyCode,
|
|
modifyObstructiveCode,
|
|
simulatedCookies,
|
|
})
|
|
case 'partial':
|
|
return inject.partial(domainName)
|
|
default:
|
|
return
|
|
}
|
|
}
|
|
|
|
const insertBefore = (originalString, match, stringToInsert) => {
|
|
const index = match.index || 0
|
|
|
|
return `${originalString.slice(0, index)}${stringToInsert} ${originalString.slice(index)}`
|
|
}
|
|
|
|
const insertAfter = (originalString, match, stringToInsert) => {
|
|
const index = (match.index || 0) + match[0].length
|
|
|
|
return `${originalString.slice(0, index)} ${stringToInsert}${originalString.slice(index)}`
|
|
}
|
|
|
|
export async function html (html: string, opts: SecurityOpts & InjectionOpts) {
|
|
const htmlToInject = await Promise.resolve(getHtmlToInject(opts))
|
|
|
|
// strip clickjacking and framebusting
|
|
// from the HTML if we've been told to
|
|
if (opts.wantsSecurityRemoved) {
|
|
html = await Promise.resolve(getRewriter(opts.useAstSourceRewriting).strip(html, opts))
|
|
}
|
|
|
|
if (!htmlToInject) {
|
|
return html
|
|
}
|
|
|
|
// TODO: move this into regex-rewriting and have ast-rewriting handle this in its own way
|
|
|
|
const headMatch = html.match(headRe)
|
|
|
|
if (headMatch) {
|
|
return insertAfter(html, headMatch, htmlToInject)
|
|
}
|
|
|
|
const bodyMatch = html.match(bodyRe)
|
|
|
|
if (bodyMatch) {
|
|
return insertBefore(html, bodyMatch, `<head> ${htmlToInject} </head>`)
|
|
}
|
|
|
|
const htmlMatch = html.match(htmlRe)
|
|
|
|
if (htmlMatch) {
|
|
return insertAfter(html, htmlMatch, `<head> ${htmlToInject} </head>`)
|
|
}
|
|
|
|
// if only <!DOCTYPE> content, inject <head> after doctype
|
|
if (doctypeRe.test(html)) {
|
|
return `${html}<head> ${htmlToInject} </head>`
|
|
}
|
|
|
|
return `<head> ${htmlToInject} </head>${html}`
|
|
}
|
|
|
|
export function security (opts: SecurityOpts) {
|
|
return getRewriter(opts.useAstSourceRewriting).stripStream(opts)
|
|
}
|