-
-
Notifications
You must be signed in to change notification settings - Fork 278
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(build): add security check to build
- Loading branch information
Showing
20 changed files
with
257 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/** | ||
* Jest configuration for web packages. | ||
* Keeping this file next to the package.json file instead of providing configuration | ||
* with `-c ../../jest.config.base` option in package.json scripts | ||
* allows us to run jest tests directly from IDEs. | ||
*/ | ||
const { ...baseConfig } = require('../../jest.config.base'); | ||
|
||
module.exports = { | ||
...baseConfig, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "@trezor/bundler-security", | ||
"version": "1.0.0", | ||
"private": true, | ||
"license": "See LICENSE.md in repo root", | ||
"sideEffects": false, | ||
"main": "src/index", | ||
"scripts": { | ||
"depcheck": "yarn g:depcheck", | ||
"lint:js": "yarn g:eslint '**/*.{ts,tsx,js}'", | ||
"type-check": "yarn g:tsc --build", | ||
"test:unit": "yarn g:jest" | ||
}, | ||
"dependencies": { | ||
"webpack": ">=5.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* eslint-disable no-console */ | ||
import webpack from 'webpack'; | ||
|
||
import { checkSecurityViolation } from './metroSecureResolver'; | ||
|
||
export class WebpackSecurityCheckPlugin { | ||
private logError(message: string) { | ||
console.error(`\x1b[1;31m${message}\x1b[0m`); | ||
} | ||
|
||
apply(compiler: webpack.Compiler) { | ||
compiler.hooks.normalModuleFactory.tap('SecurityCheckPlugin', factory => { | ||
factory.hooks.resolve.tap('SecurityCheckPlugin', resolveData => { | ||
const { request, context, contextInfo } = resolveData; | ||
|
||
const { isViolation, normalizedPath } = checkSecurityViolation({ | ||
moduleName: request, | ||
originModulePath: context, | ||
}); | ||
|
||
if (isViolation) { | ||
console.log('\n\n'); | ||
this.logError( | ||
`SECURITY ALERT: A third-party package is trying to import internal Trezor package! ` + | ||
`\nRequesting module: ${request}` + | ||
`\nNormalized path: ${normalizedPath}` + | ||
`\nImmediate importer: ${context}` + | ||
`\nOriginal issuer: ${contextInfo.issuer}`, | ||
); | ||
// Manually exit othewise webpack will only print error and happily continue building | ||
process.exit(1); | ||
} | ||
}); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const TREZOR_PACKAGES_SCOPES = ['@trezor', '@suite-common', '@suite-native']; | ||
const PACKAGES_PATHS = ['/packages/', '/suite-common/', '/suite-native/']; | ||
|
||
const RELATIVE_PATH_REGEX = new RegExp( | ||
`(?:\\.\\./){2,}(?:${PACKAGES_PATHS.map(p => p.slice(1, -1)).join('|')})`, | ||
); | ||
|
||
module.exports = { | ||
TREZOR_PACKAGES_SCOPES, | ||
RELATIVE_PATH_REGEX, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { WebpackSecurityCheckPlugin } from './WebpackSecurityPlugin'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Metro doesn't support TS and ES modules, so this file must be in plain JS and CommonJS | ||
const path = require('path'); | ||
|
||
const { RELATIVE_PATH_REGEX, TREZOR_PACKAGES_SCOPES } = require('./constants'); | ||
|
||
/** | ||
* @typedef {Object} SecurityCheckParams | ||
* @property {string} moduleName | ||
* @property {string} originModulePath | ||
*/ | ||
|
||
/** | ||
* @param {SecurityCheckParams} params | ||
* @returns {{isViolation: boolean, normalizedPath: string}} | ||
*/ | ||
const checkSecurityViolation = ({ moduleName, originModulePath }) => { | ||
// Normalize path to remove some crazy relative paths like `../../scripts/..packages/connect` etc. | ||
const normalizedPath = path.normalize(moduleName); | ||
|
||
// Check if file is in node_modules | ||
const isNodeModules = originModulePath.includes('node_modules'); | ||
// prevent standarts imports like `from '@trezor/connect'` or `require('@trezor/connect')` etc. | ||
const isScopedPackage = TREZOR_PACKAGES_SCOPES.some(scope => normalizedPath.includes(scope)); | ||
// 3rd party package can import Connect from node_modules using relative path like `../../../packages/connect` | ||
// check tests for more examples | ||
const isRelativePath = RELATIVE_PATH_REGEX.test(normalizedPath); | ||
|
||
return { | ||
isViolation: (isScopedPackage || isRelativePath) && isNodeModules, | ||
normalizedPath, | ||
}; | ||
}; | ||
|
||
/** | ||
* @param {SecurityCheckParams} params | ||
*/ | ||
const metroSecureResolver = ({ moduleName, originModulePath }) => { | ||
const { isViolation, normalizedPath } = checkSecurityViolation({ | ||
moduleName, | ||
originModulePath, | ||
}); | ||
|
||
if (isViolation) { | ||
throw new Error( | ||
`SECURITY ALERT: Some 3rd party package is trying to import internal packages or Connect!\n` + | ||
`Module: ${moduleName}\n` + | ||
`Normalized: ${normalizedPath}\n` + | ||
`From file: ${originModulePath}`, | ||
); | ||
} | ||
}; | ||
|
||
module.exports = { | ||
checkSecurityViolation, | ||
metroSecureResolver, | ||
}; |
75 changes: 75 additions & 0 deletions
75
packages/bundler-security/tests/metroSecureResolver.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { checkSecurityViolation } from '../src/metroSecureResolver'; | ||
|
||
describe('checkSecurityViolation', () => { | ||
it('should detect violation when accessing @trezor scoped package from node_modules', () => { | ||
const result = checkSecurityViolation({ | ||
moduleName: '@trezor/connect', | ||
originModulePath: 'path/to/node_modules/some-package/index.js', | ||
}); | ||
|
||
expect(result.isViolation).toBe(true); | ||
}); | ||
|
||
it('should detect violation when using relative path inside node_modules', () => { | ||
const result = checkSecurityViolation({ | ||
moduleName: '../../@trezor/connect/src/utils', | ||
originModulePath: 'path/to/node_modules/external-lib/index.js', | ||
}); | ||
|
||
expect(result.isViolation).toBe(true); | ||
}); | ||
|
||
it('should detect violation when using relative path inside node_modules 2', () => { | ||
const result = checkSecurityViolation({ | ||
moduleName: '../../../node_modules/@trezor/connect/src/utils', | ||
originModulePath: 'path/to/node_modules/external-lib/index.js', | ||
}); | ||
|
||
expect(result.isViolation).toBe(true); | ||
}); | ||
|
||
it('should detect violation when using relative path from node_modules', () => { | ||
const result = checkSecurityViolation({ | ||
moduleName: '../../../packages/connect/src/utils', | ||
originModulePath: 'path/to/node_modules/external-lib/index.js', | ||
}); | ||
|
||
expect(result.isViolation).toBe(true); | ||
}); | ||
|
||
it('should detect violation when using crazy relative path from node_modules', () => { | ||
const result = checkSecurityViolation({ | ||
moduleName: '../../scripts/../packages/connect/src/utils', | ||
originModulePath: 'path/to/node_modules/external-lib/index.js', | ||
}); | ||
|
||
expect(result.isViolation).toBe(true); | ||
}); | ||
|
||
it('should allow @trezor imports from non-node_modules location', () => { | ||
const result = checkSecurityViolation({ | ||
moduleName: '@trezor/connect', | ||
originModulePath: 'path/to/src/components/index.ts', | ||
}); | ||
|
||
expect(result.isViolation).toBe(false); | ||
}); | ||
|
||
it('should allow relative imports from non-node_modules location', () => { | ||
const result = checkSecurityViolation({ | ||
moduleName: '../utils', | ||
originModulePath: 'path/to/src/components/index.ts', | ||
}); | ||
|
||
expect(result.isViolation).toBe(false); | ||
}); | ||
|
||
it('should allow regular node_modules imports', () => { | ||
const result = checkSecurityViolation({ | ||
moduleName: 'react', | ||
originModulePath: 'path/to/node_modules/some-package/index.js', | ||
}); | ||
|
||
expect(result.isViolation).toBe(false); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"extends": "../../tsconfig.base.json", | ||
"compilerOptions": { "outDir": "libDev" }, | ||
"references": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.