feat: enhance plugin download handling with validation and extraction improvements

This commit is contained in:
2026-04-23 05:11:10 +10:00
parent ed85051480
commit c38dc7bbf6

View File

@@ -956,6 +956,11 @@ ipcMain.handle('plugin:download', async (event, { pluginId, downloadUrl, name })
return { success: false, error: 'Plugin already installed' }; return { success: false, error: 'Plugin already installed' };
} }
// Validate downloadUrl
if (!downloadUrl || typeof downloadUrl !== 'string' || downloadUrl.trim() === '') {
return { success: false, error: 'Plugin metadata missing downloadUrl field' };
}
// Download the zip file // Download the zip file
const tempZipPath = path.join(app.getPath('temp'), `${pluginId}.zip`); const tempZipPath = path.join(app.getPath('temp'), `${pluginId}.zip`);
@@ -986,13 +991,43 @@ ipcMain.handle('plugin:download', async (event, { pluginId, downloadUrl, name })
}); });
}); });
// Extract the zip file // Extract the zip file to temp location first
const zip = new AdmZip(tempZipPath); const tempExtractDir = path.join(app.getPath('temp'), `${pluginId}-extract`);
zip.extractAllTo(pluginDir, true); if (fs.existsSync(tempExtractDir)) {
fs.rmSync(tempExtractDir, { recursive: true, force: true });
}
fs.mkdirSync(tempExtractDir, { recursive: true });
// Clean up temp file const zip = new AdmZip(tempZipPath);
zip.extractAllTo(tempExtractDir, true);
// Clean up temp zip
fs.unlinkSync(tempZipPath); fs.unlinkSync(tempZipPath);
// GitHub archives extract to repo-name-branch/ folder, flatten it
const extractedContents = fs.readdirSync(tempExtractDir);
let sourceDir = tempExtractDir;
// If single folder exists, move contents up one level
if (extractedContents.length === 1) {
const singleItem = path.join(tempExtractDir, extractedContents[0]);
if (fs.statSync(singleItem).isDirectory()) {
sourceDir = singleItem;
}
}
// Move contents to final plugin directory
fs.mkdirSync(pluginDir, { recursive: true });
const files = fs.readdirSync(sourceDir);
for (const file of files) {
const srcPath = path.join(sourceDir, file);
const destPath = path.join(pluginDir, file);
fs.renameSync(srcPath, destPath);
}
// Clean up temp extract dir
fs.rmSync(tempExtractDir, { recursive: true, force: true });
// Store metadata // Store metadata
const metadataPath = path.join(pluginDir, 'plugin-metadata.json'); const metadataPath = path.join(pluginDir, 'plugin-metadata.json');
fs.writeFileSync(metadataPath, JSON.stringify({ fs.writeFileSync(metadataPath, JSON.stringify({