Skip to content

Commit

Permalink
fix: add column, line, and method check to integrity check
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanthemanuel committed Dec 10, 2022
1 parent 5c34841 commit c534ac4
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 5 deletions.
51 changes: 46 additions & 5 deletions scripts/binary/binary-integrity-check-source.js
Expand Up @@ -2,6 +2,8 @@ const OrigError = Error
const captureStackTrace = Error.captureStackTrace
const toString = Function.prototype.toString
const callFn = Function.call
const filter = Array.prototype.filter
const startsWith = String.prototype.startsWith

const integrityErrorMessage = `
We detected an issue with the integrity of the Cypress binary. It may have been modified and cannot run. We recommend re-installing the Cypress binary with:
Expand All @@ -22,7 +24,7 @@ const stackIntegrityCheck = function stackIntegrityCheck (options) {
const tempError = new OrigError

captureStackTrace(tempError, arguments.callee)
const stack = tempError.stack.filter((frame) => !frame.getFileName().startsWith('node:internal') && !frame.getFileName().startsWith('node:electron'))
const stack = filter.call(tempError.stack, (frame) => !startsWith.call(frame.getFileName(), 'node:internal') && !startsWith.call(frame.getFileName(), 'node:electron'))

OrigError.prepareStackTrace = originalPrepareStackTrace
OrigError.stackTraceLimit = originalStackTraceLimit
Expand All @@ -33,34 +35,66 @@ const stackIntegrityCheck = function stackIntegrityCheck (options) {
}

for (let index = 0; index < options.stackToMatch.length; index++) {
const { functionName: expectedFunctionName, fileName: expectedFileName } = options.stackToMatch[index]
const { functionName: expectedFunctionName, methodName: expectedMethodName, fileName: expectedFileName, line: expectedLineNumber, column: expectedColumnNumber } = options.stackToMatch[index]
const actualFunctionName = stack[index].getFunctionName()
const actualFileName = stack[index].getFileName()
const actualColumnNumber = stack[index].getColumnNumber()
const actualLineNumber = stack[index].getLineNumber()
const actualMethodName = stack[index].getMethodName()

if (expectedFunctionName && actualFunctionName !== expectedFunctionName) {
console.error(`Integrity check failed with expected function name ${expectedFunctionName} but got ${actualFunctionName}`)
throw new Error(integrityErrorMessage)
}

if (expectedMethodName && actualMethodName !== expectedMethodName) {
console.error(`Integrity check failed with expected method name ${expectedMethodName} but got ${actualMethodName}`)
throw new Error(integrityErrorMessage)
}

if (expectedFileName && actualFileName !== expectedFileName) {
console.error(`Integrity check failed with expected file name ${expectedFileName} but got ${actualFileName}`)
throw new Error(integrityErrorMessage)
}

if (expectedLineNumber && actualLineNumber !== expectedLineNumber) {
console.error(`Integrity check failed with expected line number ${expectedLineNumber} but got ${actualLineNumber}`)
throw new Error(integrityErrorMessage)
}

if (expectedColumnNumber && actualColumnNumber !== expectedColumnNumber) {
console.error(`Integrity check failed with expected column number ${expectedColumnNumber} but got ${actualColumnNumber}`)
throw new Error(integrityErrorMessage)
}
}
}

function validateStartsWith () {
if (startsWith.call !== callFn) {
console.error(`Integrity check failed for startsWith.call`)
throw new Error(integrityErrorMessage)
}
}

function validateFilter () {
if (filter.call !== callFn) {
console.error(`Integrity check failed for filter.call`)
throw new Error(integrityErrorMessage)
}
}

function validateToString () {
if (toString.call !== callFn) {
console.error(`Integrity check failed for toString.call`)
throw new Error('Integrity check failed for toString.call')
throw new Error(integrityErrorMessage)
}
}

function validateElectron (electron) {
// Hard coded function as this is electron code and there's not an easy way to get the function string at package time. If this fails on an updated version of electron, we'll need to update this.
if (toString.call(electron.app.getAppPath) !== 'function getAppPath() { [native code] }') {
console.error(`Integrity check failed for toString.call(electron.app.getAppPath)`)
throw new Error(`Integrity check failed for toString.call(electron.app.getAppPath)`)
throw new Error(integrityErrorMessage)
}
}

Expand Down Expand Up @@ -106,6 +140,8 @@ function integrityCheck (options) {
const crypto = require('crypto')

// 1. Validate that the native functions we are using haven't been tampered with
validateStartsWith()
validateFilter()
validateToString()
validateElectron(electron)
validateFs(fs)
Expand Down Expand Up @@ -143,13 +179,18 @@ function integrityCheck (options) {
fileName: 'evalmachine.<anonymous>',
},
{
functionName: 'Module2._extensions.<computed>',
functionName: 'p._extensions.<computed>',
methodName: '.jsc',
// eslint-disable-next-line no-undef
fileName: [appPath, 'index.js'].join(PATH_SEP),
line: 1,
column: 4364,
},
{
// eslint-disable-next-line no-undef
fileName: [appPath, 'index.js'].join(PATH_SEP),
line: 4,
column: 385,
},
],
})
Expand Down
1 change: 1 addition & 0 deletions scripts/binary/binary-sources.js
Expand Up @@ -17,6 +17,7 @@ const getBinaryEntryPointSource = async () => {
bundle: true,
platform: 'node',
write: false,
minify: true,
})

return esbuildResult.outputFiles[0].text
Expand Down

0 comments on commit c534ac4

Please sign in to comment.