fix: complete marketplace client remediation
This commit is contained in:
@@ -322,16 +322,67 @@ export function verifyMarketplaceClientArtifact(appAsarContents, productionTrust
|
||||
* Checkout sources are not evidence of what an installed app will trust.
|
||||
*/
|
||||
export async function readPackagedMarketplaceTrustSource(appAsar) {
|
||||
const candidates = listPackage(appAsar, { isPack: false })
|
||||
.filter((entry) => /\.(?:js|mjs|cjs)$/u.test(entry));
|
||||
for (const entry of candidates) {
|
||||
const filename = entry.replace(/^[/\\]+/u, '');
|
||||
const entries = new Set(listPackage(appAsar, { isPack: false })
|
||||
.map((entry) => entry.replace(/^[/\\]+/u, '').replaceAll('\\', '/')));
|
||||
const readArchiveText = (entry) => Buffer.from(
|
||||
extractFile(appAsar, entry.replaceAll('/', sep)),
|
||||
).toString('utf8');
|
||||
let packageJson;
|
||||
try {
|
||||
packageJson = JSON.parse(readArchiveText('package.json'));
|
||||
} catch {
|
||||
throw new Error('Packaged app.asar package.json is unreadable');
|
||||
}
|
||||
if (typeof packageJson.main !== 'string' || packageJson.main.trim().length === 0) {
|
||||
throw new Error('Packaged app.asar package.json.main is missing');
|
||||
}
|
||||
|
||||
const normalizeAsarPath = (value) => {
|
||||
const result = [];
|
||||
for (const segment of value.replaceAll('\\', '/').split('/')) {
|
||||
if (!segment || segment === '.') continue;
|
||||
if (segment === '..') {
|
||||
if (result.length === 0) return null;
|
||||
result.pop();
|
||||
} else result.push(segment);
|
||||
}
|
||||
return result.join('/');
|
||||
};
|
||||
const resolveModule = (from, specifier) => {
|
||||
if (!specifier.startsWith('.')) return null;
|
||||
const base = normalizeAsarPath(`${dirname(from).replaceAll('\\', '/')}/${specifier}`);
|
||||
if (!base) return null;
|
||||
const candidates = [base, `${base}.js`, `${base}.mjs`, `${base}.cjs`, `${base}/index.js`];
|
||||
return candidates.find((candidate) => entries.has(candidate)) ?? null;
|
||||
};
|
||||
const main = normalizeAsarPath(packageJson.main);
|
||||
if (!main || !entries.has(main)) throw new Error('Packaged app.asar package.json.main is not present');
|
||||
const pending = [main];
|
||||
const reachable = [];
|
||||
const seen = new Set();
|
||||
while (pending.length > 0) {
|
||||
const entry = pending.shift();
|
||||
if (!entry || seen.has(entry)) continue;
|
||||
seen.add(entry);
|
||||
let source;
|
||||
try {
|
||||
source = extractFile(appAsar, filename).toString('utf8');
|
||||
source = readArchiveText(entry);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
reachable.push({ entry, source });
|
||||
const specifiers = [];
|
||||
const importPattern = /(?:import|export)\s+(?:[\s\S]*?\sfrom\s*)?['"]([^'"]+)['"]/gu;
|
||||
const requirePattern = /\brequire\(\s*['"]([^'"]+)['"]\s*\)/gu;
|
||||
for (const match of source.matchAll(importPattern)) specifiers.push(match[1]);
|
||||
for (const match of source.matchAll(requirePattern)) specifiers.push(match[1]);
|
||||
for (const specifier of specifiers) {
|
||||
const resolved = resolveModule(entry, specifier);
|
||||
if (resolved) pending.push(resolved);
|
||||
}
|
||||
}
|
||||
|
||||
for (const { source } of reachable) {
|
||||
const trustAssignment = source.match(
|
||||
/CODE_OWNED_PLUGIN_SIGNING_KEYS\s*=\s*Object\.freeze\(\s*\{\}\s*(?:as\s+[^)]*)?\)/u,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user