Skip to content

Commit

Permalink
fix: verify
Browse files Browse the repository at this point in the history
whes1015 committed Dec 1, 2024
1 parent ee46655 commit 2e88c18
Showing 3 changed files with 119 additions and 3 deletions.
21 changes: 19 additions & 2 deletions src/js/core/plugin.js
Original file line number Diff line number Diff line change
@@ -4,14 +4,23 @@ const { Logger } = require('./utils/logger');
const { app } = require('@electron/remote');
const semver = require('semver');
const path = require('path');
const fs = require('fs');
const fs = require('fs-extra');
const AdmZip = require('adm-zip');
const MixinManager = require('./mixin');
const acorn = require('acorn');
const walk = require('acorn-walk');
const PluginVerifier = require('./verify');

class PluginLoader {
constructor() {
const keysDir = path.join(app.getPath('userData'), 'keys');
fs.mkdirSync(keysDir, { recursive: true });

const officialKey = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzQn1ouv0mfzVKJevJiq+\n6rV9mwCEvQpauQ2QNjy4TiwhqzqNiOPwpM3qo+8+3Ld+DUhzZzSzyx894dmJGlWQ\nwNss9Vs5/gnuvn6PurNXC42wkxY6Dmsnp/M6g08iqGXVcM6ZWmvCZ3BzBvwExxRR\n09KxHZVhwoMcF5Kp9l/hNZqXRgYMn3GLt+m78Hr+ZUjHiF8K9UH2TPxKRa/4ttPX\n6nDBZxZUCwFD7Zh6RePg07JDbO5fI/UYrqZYyDPK8w9xdXtke9LbdXmMuuk/x57h\nfoRArUkhPvUk/77mxo4++3EFnTUxYMnQVuMkDaYNRu7w83abUuhsjNlL/es24HSm\nlwIDAQAB\n-----END PUBLIC KEY-----`;

this.verifier = new PluginVerifier(officialKey);

this.verifier.loadKeysFromDirectory(keysDir);
this.pluginDir = path.join(app.getPath('userData'), 'plugins');
this.tempDir = path.join(app.getPath('temp'), 'trem-plugins');
this.plugins = new Map();
@@ -595,11 +604,16 @@ class PluginLoader {
if (targetPath) {
info = this.readPluginInfo(targetPath);
if (info) {
const verification = this.verifier.verify(targetPath);

const pluginData = {
name: info.name,
version: info.version,
description: info.description,
author: info.author,
verified: verification.valid,
verifyError: verification.error,
keyId: verification.keyId,
ctxDependencies: info.dependencies?.ctx || [],
sensitivity: info.sensitivity || { level: 0, description: '未分析' },
path: targetPath,
@@ -636,6 +650,9 @@ class PluginLoader {

for (const [name, pluginData] of scannedPlugins.entries()) {
if (enabledPlugins.includes(name)) {
if (!pluginData.verified) {
logger.warn(`Loading unverified plugin ${name}: ${pluginData.verifyError}`);
}
this.plugins.set(name, pluginData);
}
}
@@ -715,7 +732,7 @@ const pluginLoader = new PluginLoader();
tempDir: pluginLoader.tempDir,
};

logger.info('Plugin system initialized:', info);
// logger.info('Plugin system initialized:', info);
})();

module.exports = {
99 changes: 99 additions & 0 deletions src/js/core/verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const fs = require('fs-extra');
const path = require('path');
const crypto = require('crypto');

class PluginVerifier {
constructor(officialKey) {
this.officialKey = officialKey;
this.publicKeys = new Map();
}

loadKeysFromDirectory(keysDir) {
try {
if (!fs.existsSync(keysDir)) {
fs.mkdirSync(keysDir, { recursive: true });
return;
}

const files = fs.readdirSync(keysDir);
files.forEach((file) => {
if (file.endsWith('.pem')) {
try {
const keyPath = path.join(keysDir, file);
const keyContent = fs.readFileSync(keyPath, 'utf8');
const keyId = path.basename(file, '.pem');
this.publicKeys.set(keyId, keyContent);
}
catch (error) {
console.error(`Failed to load key ${file}:`, error);
}
}
});
}
catch (error) {
console.error('Failed to load public keys:', error);
}
}

verify(pluginPath) {
try {
const signaturePath = path.join(pluginPath, 'signature.json');
if (!fs.existsSync(signaturePath)) {
return { valid: false, error: 'Missing signature.json' };
}

const signatureData = JSON.parse(fs.readFileSync(signaturePath));
const { fileHashes, signature, keyId } = signatureData;

if (!fileHashes || !signature) {
return { valid: false, error: 'Invalid signature data format' };
}

for (const [file, expectedHash] of Object.entries(fileHashes)) {
if (file === 'signature.json') {
continue;
}

const filePath = path.join(pluginPath, file);
if (!fs.existsSync(filePath)) {
return { valid: false, error: `Missing file: ${file}` };
}

const content = fs.readFileSync(filePath);
const actualHash = crypto.createHash('sha256').update(content).digest('hex');

if (actualHash !== expectedHash) {
return { valid: false, error: `Modified file: ${file}` };
}
}

let publicKey;
if (!keyId) {
publicKey = this.officialKey;
}
else {
publicKey = this.publicKeys.get(keyId);
if (!publicKey) {
return { valid: false, error: `Unknown key ID: ${keyId}` };
}
}

const verify = crypto.createVerify('SHA256');
verify.write(JSON.stringify(fileHashes));
verify.end();

const isValid = verify.verify(publicKey, signature, 'base64');

return {
valid: isValid,
error: isValid ? null : 'Invalid signature',
keyId: keyId || 'official',
};
}
catch (error) {
return { valid: false, error: error.message };
}
}
}

module.exports = PluginVerifier;
2 changes: 1 addition & 1 deletion src/main.js
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ const {
Menu,
} = require('electron');
const path = require('path');
const fs = require('fs');
const fs = require('fs-extra');
const ini = require('ini');

let win;

0 comments on commit 2e88c18

Please sign in to comment.