Skip to content

Commit

Permalink
test: fix regex rewritter to handle a few other cases of rewriting
Browse files Browse the repository at this point in the history
integrity. Now accurately applies to other broad strokes
  • Loading branch information
AtofStryker committed Sep 17, 2022
1 parent d87af9a commit 18e7e3a
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 79 deletions.
40 changes: 20 additions & 20 deletions packages/proxy/lib/http/util/regex-rewriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,21 @@ const topOrParentLocationOrFramesRe = /([^\da-zA-Z\(\)])?(\btop\b|\bparent\b)([.

const jiraTopWindowGetterRe = /(!function\s*\((\w{1})\)\s*{\s*return\s*\w{1}\s*(?:={2,})\s*\w{1}\.parent)(\s*}\(\w{1}\))/g
const jiraTopWindowGetterUnMinifiedRe = /(function\s*\w{1,}\s*\((\w{1})\)\s*{\s*return\s*\w{1}\s*(?:={2,})\s*\w{1}\.parent)(\s*;\s*})/g
/**
* Matches the word integrity if being set on an object, such as foo.integrity. This MUST be preceded by a valid hash to match. This is replaced with
* foo['cypress-stripped-integrity']
*/
const javaScriptIntegrityReplacementRe = new RegExp(`[\\.](${STRIPPED_INTEGRITY_TAG}|integrity)((\\s?=\\s?)(?:"|')sha(?:256|384|512)-.*?(?:"|'))`, 'g')
/**
* Does a negative lookback to see a variable is being declared, such as var let or const (the nst is back end of const since lookbacks need a fixed width). This can then
* be preceded by any optional character that isn't a period, space, single or double quote. This MUST be preceded by a valid hash to match. A space preceding the integrity tag can still be matched,
* but the match only starts at the word integrity, and not the character preceding it. In these cases, we always replace the word integrity with cypress-stripped-integrity.
* The match for cypress-stripped-integrity is if we are replacing in the stripStream, and the replaced text is rematched no essentially complete a no op
*/
const htmlIntegrityReplacementRe = new RegExp(`(?:(?<!(var|let|nst)\\s)[^\\.\\s'"]?)(${STRIPPED_INTEGRITY_TAG}|integrity)((?:'|")?\\]?(\\s?=|["|'],)\\s?(?:"|')sha(?:256|384|512)-.*?(?:"|'))`, 'g')

const buildIntegrityReplacementRe = (isHtml = true) => {
if (!isHtml) {
// only replace integrity if a trailing period (.) or string exists inside JS/Other resources
return new RegExp(`(${STRIPPED_INTEGRITY_TAG}|[\\.|"|']integrity)((\\s?=\\s?|["|'], )(?:"|')sha(?:256|384|512)-.*?(?:"|'))`, 'g')
}

return new RegExp(`(${STRIPPED_INTEGRITY_TAG}|integrity)((=|["|'], )(?:"|')sha(?:256|384|512)-.*?(?:"|'))`, 'g')
}

const returnReplacedIntegrityExpression = (isHtml = true) => {
return isHtml ? `${STRIPPED_INTEGRITY_TAG}$2` : `['${STRIPPED_INTEGRITY_TAG}']$2`
}

export function strip (html: string, { modifyObstructiveThirdPartyCode, isHtml = true }: Partial<SecurityOpts> = {
export function strip (html: string, { modifyObstructiveThirdPartyCode }: Partial<SecurityOpts> = {
modifyObstructiveThirdPartyCode: false,
isHtml: true,
}) {
let rewrittenHTML = html
.replace(modifyObstructiveThirdPartyCode ? topOrParentExpandedEqualityBeforeRe : topOrParentEqualityBeforeRe, '$1self')
Expand All @@ -42,15 +40,15 @@ export function strip (html: string, { modifyObstructiveThirdPartyCode, isHtml =
.replace(jiraTopWindowGetterUnMinifiedRe, '$1 || $2.parent.__Cypress__$3')

if (modifyObstructiveThirdPartyCode) {
rewrittenHTML = rewrittenHTML.replace(buildIntegrityReplacementRe(isHtml), returnReplacedIntegrityExpression(isHtml))
rewrittenHTML = rewrittenHTML.replace(javaScriptIntegrityReplacementRe, `['${STRIPPED_INTEGRITY_TAG}']$2`)
rewrittenHTML = rewrittenHTML.replace(htmlIntegrityReplacementRe, `${STRIPPED_INTEGRITY_TAG}$3`)
}

return rewrittenHTML
}

export function stripStream ({ modifyObstructiveThirdPartyCode, isHtml = true }: Partial<SecurityOpts> = {
export function stripStream ({ modifyObstructiveThirdPartyCode }: Partial<SecurityOpts> = {
modifyObstructiveThirdPartyCode: false,
isHtml: true,
}) {
return pumpify(
utf8Stream(),
Expand All @@ -62,7 +60,8 @@ export function stripStream ({ modifyObstructiveThirdPartyCode, isHtml = true }:
jiraTopWindowGetterRe,
jiraTopWindowGetterUnMinifiedRe,
...(modifyObstructiveThirdPartyCode ? [
buildIntegrityReplacementRe(isHtml),
javaScriptIntegrityReplacementRe,
htmlIntegrityReplacementRe,
] : []),
],
[
Expand All @@ -72,7 +71,8 @@ export function stripStream ({ modifyObstructiveThirdPartyCode, isHtml = true }:
'$1 || $2.parent.__Cypress__$3',
'$1 || $2.parent.__Cypress__$3',
...(modifyObstructiveThirdPartyCode ? [
returnReplacedIntegrityExpression(isHtml),
`['${STRIPPED_INTEGRITY_TAG}']$2`,
`${STRIPPED_INTEGRITY_TAG}$3`,
] : []),
],
),
Expand Down
85 changes: 26 additions & 59 deletions packages/proxy/test/unit/http/util/regex-rewriter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ const originalWithModifyObstructiveThirdPartyCode = `\
dynamicIntegrityScript.src = 'integrity.js'
dynamicIntegrityScript.setAttribute('crossorigin', "anonymous")
dynamicIntegrityScript.setAttribute('data-script-type', 'dynamic')
dynamicIntegrityScript.setAttribute('integrity', "sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C"
dynamicIntegrityScript.setAttribute('integrity', "sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C")
document.querySelector('head').appendChild(dynamicIntegrityScript)
</script>
<link id="static-set-integrity-link" rel="stylesheet" href="integrity.css" integrity="sha256-MGkilwijzWAi/LutxKC+CWhsXXc6t1tXTMqY1zakP8c=">
Expand All @@ -279,6 +279,17 @@ const originalWithModifyObstructiveThirdPartyCode = `\
dynamicIntegrityScript.setAttribute('integrity', "sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C")
document.querySelector('head').appendChild(dynamicIntegrityScript)
</script>
<script>
(function(){var d=document,po=d.createElement('script');po.type='text/javascript';po.async=true;po.src='https://www.foobar.com/foobar.js';po.crossOrigin='anonymous';po.integrity='sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C';var e=d.querySelector('script[nonce]'),n=e&&(e['nonce']||e.getAttribute('nonce'));if(n){po.setAttribute('nonce',n);}var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(po, s);})();
var integrity = 'sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo.integrity = 'foo-bar'
foo.integrity = 'sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo['integrity'] = 'sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
var integrity='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo.integrity='foo-bar'
foo.integrity='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo['integrity']='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
</script>
</body>
</html>\
`
Expand Down Expand Up @@ -380,7 +391,7 @@ const expectedWithModifyObstructiveThirdPartyCode = `\
dynamicIntegrityScript.src = 'integrity.js'
dynamicIntegrityScript.setAttribute('crossorigin', "anonymous")
dynamicIntegrityScript.setAttribute('data-script-type', 'dynamic')
dynamicIntegrityScript.setAttribute('cypress-stripped-integrity', "sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C"
dynamicIntegrityScript.setAttribute('cypress-stripped-integrity', "sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C")
document.querySelector('head').appendChild(dynamicIntegrityScript)
</script>
<link id="static-set-integrity-link" rel="stylesheet" href="integrity.css" cypress-stripped-integrity="sha256-MGkilwijzWAi/LutxKC+CWhsXXc6t1tXTMqY1zakP8c=">
Expand All @@ -394,49 +405,33 @@ const expectedWithModifyObstructiveThirdPartyCode = `\
dynamicIntegrityScript.setAttribute('cypress-stripped-integrity', "sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C")
document.querySelector('head').appendChild(dynamicIntegrityScript)
</script>
<script>
(function(){var d=document,po=d.createElement('script');po.type='text/javascript';po.async=true;po.src='https://www.foobar.com/foobar.js';po.crossOrigin='anonymous';po['cypress-stripped-integrity']='sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C';var e=d.querySelector('script[nonce]'),n=e&&(e['nonce']||e.getAttribute('nonce'));if(n){po.setAttribute('nonce',n);}var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(po, s);})();
var integrity = 'sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo.integrity = 'foo-bar'
foo['cypress-stripped-integrity'] = 'sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo['cypress-stripped-integrity'] = 'sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
var integrity='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo.integrity='foo-bar'
foo['cypress-stripped-integrity']='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo['cypress-stripped-integrity']='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
</script>
</body>
</html>\
`

const originalScriptWithModifyObstructiveThirdPartyCode = `\
(function(){var d=document,po=d.createElement('script');po.type='text/javascript';po.async=true;po.src='https://www.foobar.com/foobar.js';po.crossOrigin='anonymous';po.integrity='sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C';var e=d.querySelector('script[nonce]'),n=e&&(e['nonce']||e.getAttribute('nonce'));if(n){po.setAttribute('nonce',n);}var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(po, s);})();
var integrity = 'sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo.integrity = 'foo-bar'
foo.integrity = 'sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
var integrity='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo.integrity='foo-bar'
foo.integrity='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'\
`

const expectedScriptWithModifyObstructiveThirdPartyCode = `\
(function(){var d=document,po=d.createElement('script');po.type='text/javascript';po.async=true;po.src='https://www.foobar.com/foobar.js';po.crossOrigin='anonymous';po['cypress-stripped-integrity']='sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C';var e=d.querySelector('script[nonce]'),n=e&&(e['nonce']||e.getAttribute('nonce'));if(n){po.setAttribute('nonce',n);}var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(po, s);})();
var integrity = 'sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo.integrity = 'foo-bar'
foo['cypress-stripped-integrity'] = 'sha384-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
var integrity='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'
foo.integrity='foo-bar'
foo['cypress-stripped-integrity']='sha256-XiV6bRRw9OEpsWSumtD1J7rElgTrNQro4MY/O4IYjhH+YGCf1dHaNGZ3A2kzYi/C'\
`

describe('http/util/regex-rewriter', () => {
context('.strip', () => {
it('replaces obstructive code', () => {
expect(regexRewriter.strip(original)).to.eq(expected)
})

it('replaces additional obstructive code with the "modifyObstructiveThirdPartyCode" set (html)', () => {
it('replaces additional obstructive code with the "modifyObstructiveThirdPartyCode" set', () => {
expect(regexRewriter.strip(originalWithModifyObstructiveThirdPartyCode, {
modifyObstructiveThirdPartyCode: true,
})).to.eq(expectedWithModifyObstructiveThirdPartyCode)
})

it('replaces additional obstructive code with the "modifyObstructiveThirdPartyCode" set (javascript)', () => {
expect(regexRewriter.strip(originalScriptWithModifyObstructiveThirdPartyCode, {
modifyObstructiveThirdPartyCode: true,
isHtml: false,
})).to.eq(expectedScriptWithModifyObstructiveThirdPartyCode)
})

it('replaces jira window getter', () => {
const jira = `\
for (; !function (n) {
Expand Down Expand Up @@ -636,12 +631,11 @@ while (!isTopMostWindow(parentOf) && satisfiesSameOrigin(parentOf.parent)) {
replacer.end()
})

it('replaces additional obstructive code with the "modifyObstructiveThirdPartyCode" set (html)', (done) => {
it('replaces additional obstructive code with the "modifyObstructiveThirdPartyCode" set', (done) => {
const haystacks = originalWithModifyObstructiveThirdPartyCode.split('\n')

const replacer = regexRewriter.stripStream({
modifyObstructiveThirdPartyCode: true,
isHtml: true,
})

replacer.pipe(concatStream({ encoding: 'string' }, (str) => {
Expand All @@ -662,32 +656,5 @@ while (!isTopMostWindow(parentOf) && satisfiesSameOrigin(parentOf.parent)) {

replacer.end()
})

it('replaces additional obstructive code with the "modifyObstructiveThirdPartyCode" set (js)', (done) => {
const haystacks = originalScriptWithModifyObstructiveThirdPartyCode.split('\n')

const replacer = regexRewriter.stripStream({
modifyObstructiveThirdPartyCode: true,
isHtml: false,
})

replacer.pipe(concatStream({ encoding: 'string' }, (str) => {
const string = str.toString().trim()

try {
expect(string).to.eq(expectedScriptWithModifyObstructiveThirdPartyCode)

done()
} catch (err) {
done(err)
}
}))

haystacks.forEach((haystack) => {
replacer.write(`${haystack}\n`)
})

replacer.end()
})
})
})

0 comments on commit 18e7e3a

Please sign in to comment.