diff options
Diffstat (limited to 'modules/ext')
| -rw-r--r-- | modules/ext/wpm.js | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/modules/ext/wpm.js b/modules/ext/wpm.js index 314e124..68ac9cb 100644 --- a/modules/ext/wpm.js +++ b/modules/ext/wpm.js @@ -57,11 +57,39 @@ class WpmModule { if (this.installed[name]) return this.terminal.print(`Package "${name}" already installed. Use wpm update to reinstall.`, 'warning'); this.terminal.print(`Installing ${pkg.name} v${pkg.version}...`, 'info'); this.terminal.print(` ${pkg.desc}`, 'info'); - const success = await this.terminal.moduleManager.loadModuleFromURL(pkg.url); - if (success) { - this.installed[name] = { version: pkg.version, installed: new Date().toISOString() }; - this.saveInstalled(); - this.terminal.print(`"${name}" installed successfully!`, 'success'); + // P0: SRI — fetch source, compute SHA-256, verify integrity before loading + try { + const res = await fetch(pkg.url); + if (!res.ok) throw new Error('HTTP ' + res.status); + const source = await res.text(); + // Compute SHA-256 via Web Crypto API + const encoder = new TextEncoder(); + const data = encoder.encode(source); + const hashBuffer = await crypto.subtle.digest('SHA-256', data); + const hashHex = Array.from(new Uint8Array(hashBuffer)) + .map(b => b.toString(16).padStart(2, '0')).join(''); + // Verify if package declares a hash + if (pkg.hash) { + if (hashHex !== pkg.hash) { + this.terminal.print(`❌ INTEGRITY CHECK FAILED: hash mismatch!`, 'error'); + this.terminal.print(` Expected: ${pkg.hash}`, 'error'); + this.terminal.print(` Got: ${hashHex}`, 'error'); + this.terminal.print(` Package may have been tampered with. Aborting.`, 'error'); + return; + } + this.terminal.print(`✅ Integrity verified (SHA-256: ${hashHex.substring(0, 16)}...)`, 'success'); + } else { + this.terminal.print(`⚠ No hash declared. Computed SHA-256: ${hashHex.substring(0, 24)}...`, 'warning'); + } + // Load the verified source + const success = await this.terminal.moduleManager.loadModuleFromURL(pkg.url); + if (success) { + this.installed[name] = { version: pkg.version, installed: new Date().toISOString(), hash: hashHex }; + this.saveInstalled(); + this.terminal.print(`"${name}" installed successfully!`, 'success'); + } + } catch (e) { + this.terminal.print(`Install failed: ${e.message}`, 'error'); } } async list() { @@ -143,7 +171,10 @@ class WpmModule { this.terminal.print(`Commands: ${pkg.commands.join(', ')}`); this.terminal.print(`URL: ${pkg.url}`); const installed = this.installed[name]; - if (installed) this.terminal.print(`Installed: ${installed.installed}`, 'success'); + if (installed) { + this.terminal.print(`Installed: ${installed.installed}`, 'success'); + if (installed.hash) this.terminal.print(`Hash: ${installed.hash.substring(0, 24)}...`, 'info'); + } else this.terminal.print('Not installed. Use: wpm install ' + name, 'info'); } |