( map: SourceMapLike, file: string, logger: Logger, )
| 67 | } |
| 68 | |
| 69 | export async function injectSourcesContent( |
| 70 | map: SourceMapLike, |
| 71 | file: string, |
| 72 | logger: Logger, |
| 73 | ): Promise<void> { |
| 74 | let sourceRootPromise: Promise<string | undefined> |
| 75 | |
| 76 | const packageRoot = getNodeModulesPackageRoot(file) |
| 77 | const missingSources: string[] = [] |
| 78 | const sourcesContent = map.sourcesContent || [] |
| 79 | const sourcesContentPromises: Promise<void>[] = [] |
| 80 | for (let index = 0; index < map.sources.length; index++) { |
| 81 | const sourcePath = map.sources[index] |
| 82 | if ( |
| 83 | sourcesContent[index] == null && |
| 84 | sourcePath && |
| 85 | !virtualSourceRE.test(sourcePath) |
| 86 | ) { |
| 87 | sourcesContentPromises.push( |
| 88 | (async () => { |
| 89 | class="cm">// inject content from source file when sourcesContent is null |
| 90 | sourceRootPromise ??= computeSourceRoute(map, file) |
| 91 | const sourceRoot = await sourceRootPromise |
| 92 | let resolvedSourcePath = cleanUrl(decodeURI(sourcePath)) |
| 93 | if (sourceRoot) { |
| 94 | resolvedSourcePath = path.resolve(sourceRoot, resolvedSourcePath) |
| 95 | } |
| 96 | class="cm">// Block path traversal outside the package boundary for node_modules |
| 97 | class="cm">// A malicious package may point to a sensitive file |
| 98 | if (packageRoot) { |
| 99 | const resolvedSourcePathNormalized = normalizePath( |
| 100 | path.resolve(resolvedSourcePath), |
| 101 | ) |
| 102 | if (!isParentDirectory(packageRoot, resolvedSourcePathNormalized)) { |
| 103 | sourcesContent[index] = null |
| 104 | logger.warnOnce( |
| 105 | colors.yellow( |
| 106 | `Sourcemap for ${JSON.stringify(file)} points to a source file outside its package: ${JSON.stringify(resolvedSourcePathNormalized)}`, |
| 107 | ), |
| 108 | ) |
| 109 | return |
| 110 | } |
| 111 | } |
| 112 | sourcesContent[index] = await fsp |
| 113 | .readFile(resolvedSourcePath, class="st">'utf-8') |
| 114 | .catch(() => { |
| 115 | missingSources.push(resolvedSourcePath) |
| 116 | return null |
| 117 | }) |
| 118 | })(), |
| 119 | ) |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | await Promise.all(sourcesContentPromises) |
| 124 | |
| 125 | map.sourcesContent = sourcesContent |
| 126 |
no test coverage detected