mirror of
https://github.com/arduino/Arduino.git
synced 2024-11-29 10:24:12 +01:00
Added core "post install" and "pre uninstall" script support.
If a core has a post/pre install/uninstall script, it will be execute at the appropriate time IF: 1) source (package_*_index) is trusted (GPG signed) 2) or users have explicitly added line "contributions.trust.all=true" to their preferences.txt Some minor refactor and clean up while I was at it
This commit is contained in:
parent
7cc7d47e61
commit
987cad2633
@ -30,6 +30,7 @@
|
||||
package cc.arduino.contributions.packages.ui;
|
||||
|
||||
import cc.arduino.contributions.DownloadableContribution;
|
||||
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
|
||||
import cc.arduino.contributions.packages.ContributedPlatform;
|
||||
import cc.arduino.contributions.packages.ContributionInstaller;
|
||||
import cc.arduino.contributions.packages.ContributionsIndexer;
|
||||
@ -116,7 +117,7 @@ public class ContributionManagerUI extends InstallerJDialog {
|
||||
}
|
||||
|
||||
// Create ConstributionInstaller tied with the provided index
|
||||
installer = new ContributionInstaller(indexer, platform) {
|
||||
installer = new ContributionInstaller(indexer, platform, new GPGDetachedSignatureVerifier()) {
|
||||
@Override
|
||||
public void onProgress(Progress progress) {
|
||||
setProgress(progress);
|
||||
|
@ -24,6 +24,7 @@ package processing.app;
|
||||
|
||||
import cc.arduino.contributions.BuiltInCoreIsNewerCheck;
|
||||
import cc.arduino.contributions.DownloadableContributionVersionComparator;
|
||||
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
|
||||
import cc.arduino.contributions.VersionHelper;
|
||||
import cc.arduino.contributions.libraries.*;
|
||||
import cc.arduino.contributions.libraries.ui.LibraryManagerUI;
|
||||
@ -345,8 +346,8 @@ public class Base {
|
||||
PreferencesData.save();
|
||||
|
||||
if (parser.isInstallBoard()) {
|
||||
ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder(), BaseNoGui.getPlatform());
|
||||
ContributionInstaller installer = new ContributionInstaller(indexer, BaseNoGui.getPlatform()) {
|
||||
ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder(), BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier());
|
||||
ContributionInstaller installer = new ContributionInstaller(indexer, BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier()) {
|
||||
private String lastStatus = "";
|
||||
|
||||
@Override
|
||||
@ -392,7 +393,7 @@ public class Base {
|
||||
System.exit(0);
|
||||
|
||||
} else if (parser.isInstallLibrary()) {
|
||||
LibrariesIndexer indexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder(), new ContributionsIndexer(BaseNoGui.getSettingsFolder(), BaseNoGui.getPlatform()));
|
||||
LibrariesIndexer indexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder(), new ContributionsIndexer(BaseNoGui.getSettingsFolder(), BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier()));
|
||||
LibraryInstaller installer = new LibraryInstaller(indexer, BaseNoGui.getPlatform()) {
|
||||
private String lastStatus = "";
|
||||
|
||||
|
@ -27,9 +27,8 @@
|
||||
* the GNU General Public License.
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.contributions;
|
||||
package cc.arduino.contributions;
|
||||
|
||||
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -27,7 +27,7 @@
|
||||
* the GNU General Public License.
|
||||
*/
|
||||
|
||||
package cc.arduino.contributions.packages;
|
||||
package cc.arduino.contributions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -39,6 +39,7 @@ public class Constants {
|
||||
public static final String PACKAGE_INDEX_URL;
|
||||
|
||||
public static final String PREFERENCES_BOARDS_MANAGER_ADDITIONAL_URLS = "boardsmanager.additional.urls";
|
||||
public static final String PREF_CONTRIBUTIONS_TRUST_ALL = "contributions.trust.all";
|
||||
|
||||
static {
|
||||
String extenalPackageIndexUrl = System.getProperty("PACKAGE_INDEX_URL");
|
@ -1,6 +1,8 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
|
||||
*
|
||||
* Arduino is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
@ -23,8 +25,6 @@
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.contributions;
|
||||
@ -37,7 +37,7 @@ import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
|
||||
import java.io.*;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class GPGDetachedSignatureVerifier {
|
||||
public class GPGDetachedSignatureVerifier extends SignatureVerifier {
|
||||
|
||||
private String keyId;
|
||||
|
||||
@ -49,9 +49,7 @@ public class GPGDetachedSignatureVerifier {
|
||||
this.keyId = keyId;
|
||||
}
|
||||
|
||||
public boolean verify(File signedFile, File signature, File publicKey) throws IOException, PGPException {
|
||||
PGPPublicKey pgpPublicKey = readPublicKey(publicKey, keyId);
|
||||
|
||||
protected boolean verify(File signedFile, File signature, File publicKey) throws IOException {
|
||||
FileInputStream signatureInputStream = null;
|
||||
FileInputStream signedFileInputStream = null;
|
||||
try {
|
||||
@ -71,11 +69,15 @@ public class GPGDetachedSignatureVerifier {
|
||||
assert pgpSignatureList.size() == 1;
|
||||
PGPSignature pgpSignature = pgpSignatureList.get(0);
|
||||
|
||||
PGPPublicKey pgpPublicKey = readPublicKey(publicKey, keyId);
|
||||
|
||||
pgpSignature.init(new BcPGPContentVerifierBuilderProvider(), pgpPublicKey);
|
||||
signedFileInputStream = new FileInputStream(signedFile);
|
||||
pgpSignature.update(IOUtils.toByteArray(signedFileInputStream));
|
||||
|
||||
return pgpSignature.verify();
|
||||
} catch (PGPException e) {
|
||||
throw new IOException(e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(signatureInputStream);
|
||||
IOUtils.closeQuietly(signedFileInputStream);
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
|
||||
*
|
||||
* Arduino is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*/
|
||||
|
||||
package cc.arduino.contributions;
|
||||
|
||||
import processing.app.BaseNoGui;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class SignatureVerifier {
|
||||
|
||||
public boolean isSigned(File indexFile) {
|
||||
File signature = new File(indexFile.getParent(), indexFile.getName() + ".sig");
|
||||
if (!signature.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return verify(indexFile, signature, new File(BaseNoGui.getContentFile("lib"), "public.gpg.key"));
|
||||
} catch (Exception e) {
|
||||
BaseNoGui.showWarning(e.getMessage(), e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean verify(File signedFile, File signature, File publicKey) throws IOException;
|
||||
|
||||
}
|
@ -47,6 +47,8 @@ public abstract class ContributedPackage {
|
||||
|
||||
public abstract ContributedHelp getHelp();
|
||||
|
||||
private boolean trusted;
|
||||
|
||||
public ContributedPlatform findPlatform(String architecture, String version) {
|
||||
if (architecture == null || version == null) {
|
||||
return null;
|
||||
@ -66,6 +68,14 @@ public abstract class ContributedPackage {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isTrusted() {
|
||||
return trusted;
|
||||
}
|
||||
|
||||
public void setTrusted(boolean trusted) {
|
||||
this.trusted = trusted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String res;
|
||||
|
@ -54,19 +54,18 @@ public abstract class ContributedPlatform extends DownloadableContribution {
|
||||
|
||||
public abstract ContributedHelp getHelp();
|
||||
|
||||
private List<ContributedTool> resolvedTools = null;
|
||||
|
||||
private List<ContributedTool> resolvedTools;
|
||||
private ContributedPackage parentPackage;
|
||||
|
||||
public List<ContributedTool> getResolvedTools() {
|
||||
if (resolvedTools == null) {
|
||||
return null;
|
||||
}
|
||||
return new LinkedList<ContributedTool>(resolvedTools);
|
||||
return new LinkedList<>(resolvedTools);
|
||||
}
|
||||
|
||||
public void resolveToolsDependencies(Collection<ContributedPackage> packages) {
|
||||
resolvedTools = new ArrayList<ContributedTool>();
|
||||
resolvedTools = new ArrayList<>();
|
||||
|
||||
// If there are no dependencies return empty list
|
||||
if (getToolsDependencies() == null) {
|
||||
|
@ -29,9 +29,8 @@
|
||||
|
||||
package cc.arduino.contributions.packages;
|
||||
|
||||
import cc.arduino.contributions.DownloadableContribution;
|
||||
import cc.arduino.contributions.DownloadableContributionsDownloader;
|
||||
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
|
||||
import cc.arduino.contributions.*;
|
||||
import cc.arduino.contributions.Constants;
|
||||
import cc.arduino.filters.FileExecutablePredicate;
|
||||
import cc.arduino.utils.ArchiveExtractor;
|
||||
import cc.arduino.utils.MultiStepProgress;
|
||||
@ -41,7 +40,6 @@ import org.apache.commons.exec.CommandLine;
|
||||
import org.apache.commons.exec.DefaultExecutor;
|
||||
import org.apache.commons.exec.Executor;
|
||||
import org.apache.commons.exec.PumpStreamHandler;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.I18n;
|
||||
import processing.app.Platform;
|
||||
import processing.app.PreferencesData;
|
||||
@ -52,6 +50,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
@ -62,9 +61,11 @@ public class ContributionInstaller {
|
||||
private final ContributionsIndexer indexer;
|
||||
private final DownloadableContributionsDownloader downloader;
|
||||
private final Platform platform;
|
||||
private final SignatureVerifier signatureVerifier;
|
||||
|
||||
public ContributionInstaller(ContributionsIndexer contributionsIndexer, Platform platform) {
|
||||
public ContributionInstaller(ContributionsIndexer contributionsIndexer, Platform platform, SignatureVerifier signatureVerifier) {
|
||||
this.platform = platform;
|
||||
this.signatureVerifier = signatureVerifier;
|
||||
File stagingFolder = contributionsIndexer.getStagingFolder();
|
||||
indexer = contributionsIndexer;
|
||||
downloader = new DownloadableContributionsDownloader(stagingFolder) {
|
||||
@ -76,13 +77,13 @@ public class ContributionInstaller {
|
||||
}
|
||||
|
||||
public List<String> install(ContributedPlatform contributedPlatform) throws Exception {
|
||||
List<String> errors = new LinkedList<String>();
|
||||
List<String> errors = new LinkedList<>();
|
||||
if (contributedPlatform.isInstalled()) {
|
||||
throw new Exception("Platform is already installed!");
|
||||
}
|
||||
|
||||
// Do not download already installed tools
|
||||
List<ContributedTool> tools = new LinkedList<ContributedTool>(contributedPlatform.getResolvedTools());
|
||||
List<ContributedTool> tools = new LinkedList<>(contributedPlatform.getResolvedTools());
|
||||
Iterator<ContributedTool> toolsIterator = tools.iterator();
|
||||
while (toolsIterator.hasNext()) {
|
||||
ContributedTool tool = toolsIterator.next();
|
||||
@ -134,11 +135,11 @@ public class ContributionInstaller {
|
||||
DownloadableContribution toolContrib = tool.getDownloadableContribution(platform);
|
||||
File destFolder = new File(toolsFolder, tool.getName() + File.separator + tool.getVersion());
|
||||
|
||||
destFolder.mkdirs();
|
||||
Files.createDirectories(destFolder.toPath());
|
||||
assert toolContrib.getDownloadedFile() != null;
|
||||
new ArchiveExtractor(platform).extract(toolContrib.getDownloadedFile(), destFolder, 1);
|
||||
try {
|
||||
executePostInstallScriptIfAny(destFolder);
|
||||
findAndExecutePostInstallScriptIfAny(destFolder, contributedPlatform.getParentPackage().isTrusted(), PreferencesData.getBoolean(Constants.PREF_CONTRIBUTIONS_TRUST_ALL));
|
||||
} catch (IOException e) {
|
||||
errors.add(_("Error running post install script"));
|
||||
}
|
||||
@ -152,10 +153,16 @@ public class ContributionInstaller {
|
||||
onProgress(progress);
|
||||
File platformFolder = new File(packageFolder, "hardware" + File.separator + contributedPlatform.getArchitecture());
|
||||
File destFolder = new File(platformFolder, contributedPlatform.getParsedVersion());
|
||||
destFolder.mkdirs();
|
||||
Files.createDirectories(destFolder.toPath());
|
||||
new ArchiveExtractor(platform).extract(contributedPlatform.getDownloadedFile(), destFolder, 1);
|
||||
contributedPlatform.setInstalled(true);
|
||||
contributedPlatform.setInstalledFolder(destFolder);
|
||||
try {
|
||||
findAndExecutePostInstallScriptIfAny(destFolder, contributedPlatform.getParentPackage().isTrusted(), PreferencesData.getBoolean(Constants.PREF_CONTRIBUTIONS_TRUST_ALL));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
errors.add(_("Error running post install script"));
|
||||
}
|
||||
progress.stepDone();
|
||||
|
||||
progress.setStatus(_("Installation completed!"));
|
||||
@ -164,20 +171,49 @@ public class ContributionInstaller {
|
||||
return errors;
|
||||
}
|
||||
|
||||
private void executePostInstallScriptIfAny(File folder) throws IOException {
|
||||
Collection<File> postInstallScripts = Collections2.filter(platform.postInstallScripts(folder), new FileExecutablePredicate());
|
||||
private void findAndExecutePostInstallScriptIfAny(File folder, boolean trusted, boolean trustAll) throws IOException {
|
||||
Collection<File> scripts = Collections2.filter(platform.postInstallScripts(folder), new FileExecutablePredicate());
|
||||
|
||||
if (postInstallScripts.isEmpty()) {
|
||||
if (scripts.isEmpty()) {
|
||||
String[] subfolders = folder.list(new OnlyDirs());
|
||||
if (subfolders.length != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
executePostInstallScriptIfAny(new File(folder, subfolders[0]));
|
||||
findAndExecutePostInstallScriptIfAny(new File(folder, subfolders[0]), trusted, trustAll);
|
||||
return;
|
||||
}
|
||||
|
||||
File postInstallScript = postInstallScripts.iterator().next();
|
||||
executeScripts(folder, scripts, trusted, trustAll);
|
||||
}
|
||||
|
||||
private void findAndExecutePreUninstallScriptIfAny(File folder, boolean trusted, boolean trustAll) throws IOException {
|
||||
Collection<File> scripts = Collections2.filter(platform.preUninstallScripts(folder), new FileExecutablePredicate());
|
||||
|
||||
if (scripts.isEmpty()) {
|
||||
String[] subfolders = folder.list(new OnlyDirs());
|
||||
if (subfolders.length != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
findAndExecutePreUninstallScriptIfAny(new File(folder, subfolders[0]), trusted, trustAll);
|
||||
return;
|
||||
}
|
||||
|
||||
executeScripts(folder, scripts, trusted, trustAll);
|
||||
}
|
||||
|
||||
private void executeScripts(File folder, Collection<File> postInstallScripts, boolean trusted, boolean trustAll) throws IOException {
|
||||
File script = postInstallScripts.iterator().next();
|
||||
|
||||
if (!trusted && !trustAll) {
|
||||
System.err.println(I18n.format(_("Warning: non trusted contribution, skipping script execution ({0})"), script));
|
||||
return;
|
||||
}
|
||||
|
||||
if (trustAll) {
|
||||
System.err.println(I18n.format(_("Warning: forced untrusted script execution ({0})"), script));
|
||||
}
|
||||
|
||||
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
|
||||
@ -185,7 +221,7 @@ public class ContributionInstaller {
|
||||
executor.setStreamHandler(new PumpStreamHandler(stdout, stderr));
|
||||
executor.setWorkingDirectory(folder);
|
||||
executor.setExitValues(null);
|
||||
int exitValue = executor.execute(new CommandLine(postInstallScript));
|
||||
int exitValue = executor.execute(new CommandLine(script));
|
||||
executor.setExitValues(new int[0]);
|
||||
|
||||
System.out.write(stdout.toByteArray());
|
||||
@ -198,9 +234,15 @@ public class ContributionInstaller {
|
||||
|
||||
public List<String> remove(ContributedPlatform contributedPlatform) {
|
||||
if (contributedPlatform == null || contributedPlatform.isReadOnly()) {
|
||||
return new LinkedList<String>();
|
||||
return new LinkedList<>();
|
||||
}
|
||||
List<String> errors = new LinkedList<String>();
|
||||
List<String> errors = new LinkedList<>();
|
||||
try {
|
||||
findAndExecutePreUninstallScriptIfAny(contributedPlatform.getInstalledFolder(), contributedPlatform.getParentPackage().isTrusted(), PreferencesData.getBoolean(Constants.PREF_CONTRIBUTIONS_TRUST_ALL));
|
||||
} catch (IOException e) {
|
||||
errors.add(_("Error running post install script"));
|
||||
}
|
||||
|
||||
FileUtils.recursiveDelete(contributedPlatform.getInstalledFolder());
|
||||
contributedPlatform.setInstalled(false);
|
||||
contributedPlatform.setInstalledFolder(null);
|
||||
@ -221,8 +263,8 @@ public class ContributionInstaller {
|
||||
// now try to remove the containing TOOL_NAME folder
|
||||
// (and silently fail if another version of the tool is installed)
|
||||
try {
|
||||
destFolder.getParentFile().delete();
|
||||
} catch (SecurityException e) {
|
||||
Files.delete(destFolder.getParentFile().toPath());
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
@ -233,11 +275,11 @@ public class ContributionInstaller {
|
||||
public List<String> updateIndex() throws Exception {
|
||||
MultiStepProgress progress = new MultiStepProgress(1);
|
||||
|
||||
List<String> downloadedPackageIndexFilesAccumulator = new LinkedList<String>();
|
||||
downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, Constants.PACKAGE_INDEX_URL);
|
||||
List<String> downloadedPackageIndexFilesAccumulator = new LinkedList<>();
|
||||
downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, cc.arduino.contributions.Constants.PACKAGE_INDEX_URL);
|
||||
|
||||
Set<String> packageIndexURLs = new HashSet<String>();
|
||||
String additionalURLs = PreferencesData.get(Constants.PREFERENCES_BOARDS_MANAGER_ADDITIONAL_URLS, "");
|
||||
Set<String> packageIndexURLs = new HashSet<>();
|
||||
String additionalURLs = PreferencesData.get(cc.arduino.contributions.Constants.PREFERENCES_BOARDS_MANAGER_ADDITIONAL_URLS, "");
|
||||
if (!"".equals(additionalURLs)) {
|
||||
packageIndexURLs.addAll(Arrays.asList(additionalURLs.split(",")));
|
||||
}
|
||||
@ -256,13 +298,13 @@ public class ContributionInstaller {
|
||||
downloadedPackagedIndexFilesAccumulator.add(packageIndex.getName());
|
||||
try {
|
||||
File packageIndexSignature = download(progress, packageIndexUrl + ".sig");
|
||||
boolean signatureVerified = new GPGDetachedSignatureVerifier().verify(packageIndex, packageIndexSignature, new File(BaseNoGui.getContentFile("lib"), "public.gpg.key"));
|
||||
boolean signatureVerified = signatureVerifier.isSigned(packageIndex);
|
||||
if (signatureVerified) {
|
||||
downloadedPackagedIndexFilesAccumulator.add(packageIndexSignature.getName());
|
||||
} else {
|
||||
downloadedPackagedIndexFilesAccumulator.remove(packageIndex.getName());
|
||||
packageIndex.delete();
|
||||
packageIndexSignature.delete();
|
||||
Files.delete(packageIndex.toPath());
|
||||
Files.delete(packageIndexSignature.toPath());
|
||||
System.err.println(I18n.format(_("{0} file signature verification failed. File ignored."), packageIndexUrl));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -295,15 +337,15 @@ public class ContributionInstaller {
|
||||
// Empty
|
||||
}
|
||||
|
||||
public void deleteUnknownFiles(List<String> downloadedPackageIndexFiles) {
|
||||
public void deleteUnknownFiles(List<String> downloadedPackageIndexFiles) throws IOException {
|
||||
File preferencesFolder = indexer.getIndexFile(".").getParentFile();
|
||||
File[] additionalPackageIndexFiles = preferencesFolder.listFiles(new PackageIndexFilenameFilter(Constants.DEFAULT_INDEX_FILE_NAME));
|
||||
File[] additionalPackageIndexFiles = preferencesFolder.listFiles(new PackageIndexFilenameFilter(cc.arduino.contributions.Constants.DEFAULT_INDEX_FILE_NAME));
|
||||
if (additionalPackageIndexFiles == null) {
|
||||
return;
|
||||
}
|
||||
for (File additionalPackageIndexFile : additionalPackageIndexFiles) {
|
||||
if (!downloadedPackageIndexFiles.contains(additionalPackageIndexFile.getName())) {
|
||||
additionalPackageIndexFile.delete();
|
||||
Files.delete(additionalPackageIndexFile.toPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomCompar
|
||||
import cc.arduino.contributions.filters.DownloadableContributionWithVersionPredicate;
|
||||
import cc.arduino.contributions.filters.InstalledPredicate;
|
||||
import cc.arduino.contributions.packages.filters.PlatformArchitecturePredicate;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@ -89,7 +88,7 @@ public abstract class ContributionsIndex {
|
||||
}
|
||||
|
||||
public ContributedPlatform getInstalledPlatform(String packageName, String platformArch) {
|
||||
List<ContributedPlatform> installedPlatforms = new LinkedList<ContributedPlatform>(Collections2.filter(findPlatforms(packageName, platformArch), new InstalledPredicate()));
|
||||
List<ContributedPlatform> installedPlatforms = new LinkedList<>(Collections2.filter(findPlatforms(packageName, platformArch), new InstalledPredicate()));
|
||||
Collections.sort(installedPlatforms, new DownloadableContributionBuiltInAtTheBottomComparator());
|
||||
|
||||
if (installedPlatforms.isEmpty()) {
|
||||
@ -99,25 +98,11 @@ public abstract class ContributionsIndex {
|
||||
return installedPlatforms.get(0);
|
||||
}
|
||||
|
||||
public List<ContributedPlatform> getPlatforms() {
|
||||
return Lists.newLinkedList(Iterables.concat(Collections2.transform(getPackages(), new Function<ContributedPackage, List<ContributedPlatform>>() {
|
||||
@Override
|
||||
public List<ContributedPlatform> apply(ContributedPackage contributedPackage) {
|
||||
return contributedPackage.getPlatforms();
|
||||
}
|
||||
})));
|
||||
private List<ContributedPlatform> getPlatforms() {
|
||||
return Lists.newLinkedList(Iterables.concat(Collections2.transform(getPackages(), ContributedPackage::getPlatforms)));
|
||||
}
|
||||
|
||||
|
||||
public ContributedTool findTool(String packageName, String name,
|
||||
String version) {
|
||||
ContributedPackage pack = findPackage(packageName);
|
||||
if (pack == null)
|
||||
return null;
|
||||
return pack.findTool(name, version);
|
||||
}
|
||||
|
||||
private final List<String> categories = new ArrayList<String>();
|
||||
private final List<String> categories = new ArrayList<>();
|
||||
|
||||
public List<String> getCategories() {
|
||||
return categories;
|
||||
@ -126,10 +111,9 @@ public abstract class ContributionsIndex {
|
||||
public void fillCategories() {
|
||||
categories.clear();
|
||||
for (ContributedPackage pack : getPackages()) {
|
||||
for (ContributedPlatform platform : pack.getPlatforms()) {
|
||||
if (!categories.contains(platform.getCategory()))
|
||||
categories.add(platform.getCategory());
|
||||
}
|
||||
pack.getPlatforms().stream()
|
||||
.filter(platform -> !categories.contains(platform.getCategory()))
|
||||
.forEach(platform -> categories.add(platform.getCategory()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,4 +137,8 @@ public abstract class ContributionsIndex {
|
||||
res += pack + "\n";
|
||||
return res;
|
||||
}
|
||||
|
||||
public void setTrusted() {
|
||||
getPackages().stream().forEach(pack -> pack.setTrusted(true));
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,7 @@
|
||||
|
||||
package cc.arduino.contributions.packages;
|
||||
|
||||
import cc.arduino.contributions.DownloadableContribution;
|
||||
import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator;
|
||||
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
|
||||
import cc.arduino.contributions.SignatureVerificationFailedException;
|
||||
import cc.arduino.contributions.*;
|
||||
import cc.arduino.contributions.filters.BuiltInPredicate;
|
||||
import cc.arduino.contributions.filters.InstalledPredicate;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
@ -46,8 +43,9 @@ import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.I18n;
|
||||
import processing.app.Platform;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.debug.TargetPackage;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.app.debug.TargetPlatformException;
|
||||
@ -60,6 +58,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
import static processing.app.helpers.filefilters.OnlyDirs.ONLY_DIRS;
|
||||
|
||||
public class ContributionsIndexer {
|
||||
@ -68,23 +67,26 @@ public class ContributionsIndexer {
|
||||
private final File stagingFolder;
|
||||
private final File preferencesFolder;
|
||||
private final Platform platform;
|
||||
private final SignatureVerifier signatureVerifier;
|
||||
private ContributionsIndex index;
|
||||
|
||||
public ContributionsIndexer(File preferencesFolder, Platform platform) {
|
||||
public ContributionsIndexer(File preferencesFolder, Platform platform, SignatureVerifier signatureVerifier) {
|
||||
this.preferencesFolder = preferencesFolder;
|
||||
this.platform = platform;
|
||||
this.signatureVerifier = signatureVerifier;
|
||||
packagesFolder = new File(preferencesFolder, "packages");
|
||||
stagingFolder = new File(preferencesFolder, "staging" + File.separator + "packages");
|
||||
}
|
||||
|
||||
public void parseIndex() throws Exception {
|
||||
File defaultIndexFile = getIndexFile(Constants.DEFAULT_INDEX_FILE_NAME);
|
||||
if (!isSigned(defaultIndexFile)) {
|
||||
throw new SignatureVerificationFailedException(Constants.DEFAULT_INDEX_FILE_NAME);
|
||||
File defaultIndexFile = getIndexFile(cc.arduino.contributions.Constants.DEFAULT_INDEX_FILE_NAME);
|
||||
if (!signatureVerifier.isSigned(defaultIndexFile)) {
|
||||
throw new SignatureVerificationFailedException(cc.arduino.contributions.Constants.DEFAULT_INDEX_FILE_NAME);
|
||||
}
|
||||
index = parseIndex(defaultIndexFile);
|
||||
index.setTrusted();
|
||||
|
||||
File[] indexFiles = preferencesFolder.listFiles(new TestPackageIndexFilenameFilter(new PackageIndexFilenameFilter(Constants.DEFAULT_INDEX_FILE_NAME)));
|
||||
File[] indexFiles = preferencesFolder.listFiles(new TestPackageIndexFilenameFilter(new PackageIndexFilenameFilter(cc.arduino.contributions.Constants.DEFAULT_INDEX_FILE_NAME)));
|
||||
|
||||
for (File indexFile : indexFiles) {
|
||||
ContributionsIndex contributionsIndex = parseIndex(indexFile);
|
||||
@ -113,10 +115,12 @@ public class ContributionsIndexer {
|
||||
}
|
||||
|
||||
private void mergeContributions(ContributionsIndex contributionsIndex, File indexFile) {
|
||||
boolean signed = isSigned(indexFile);
|
||||
boolean signed = signatureVerifier.isSigned(indexFile);
|
||||
boolean trustall = PreferencesData.getBoolean(Constants.PREF_CONTRIBUTIONS_TRUST_ALL);
|
||||
|
||||
for (ContributedPackage contributedPackage : contributionsIndex.getPackages()) {
|
||||
if (!signed) {
|
||||
contributedPackage.setTrusted(signed || trustall);
|
||||
if (!contributedPackage.isTrusted()) {
|
||||
for (ContributedPlatform contributedPlatform : contributedPackage.getPlatforms()) {
|
||||
contributedPlatform.setCategory("Contributed");
|
||||
}
|
||||
@ -127,7 +131,10 @@ public class ContributionsIndexer {
|
||||
if (targetPackage == null) {
|
||||
index.getPackages().add(contributedPackage);
|
||||
} else {
|
||||
if (signed || !isPackageNameProtected(contributedPackage)) {
|
||||
if (contributedPackage.isTrusted() || !isPackageNameProtected(contributedPackage)) {
|
||||
if (isPackageNameProtected(contributedPackage) && trustall) {
|
||||
System.err.println(I18n.format(_("Warning: forced trusting untrusted contributions")));
|
||||
}
|
||||
List<ContributedPlatform> platforms = contributedPackage.getPlatforms();
|
||||
if (platforms == null) {
|
||||
platforms = new LinkedList<ContributedPlatform>();
|
||||
@ -156,21 +163,7 @@ public class ContributionsIndexer {
|
||||
}
|
||||
|
||||
private boolean isPackageNameProtected(ContributedPackage contributedPackage) {
|
||||
return Constants.PROTECTED_PACKAGE_NAMES.contains(contributedPackage.getName());
|
||||
}
|
||||
|
||||
private boolean isSigned(File indexFile) {
|
||||
File signature = new File(indexFile.getParent(), indexFile.getName() + ".sig");
|
||||
if (!signature.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return new GPGDetachedSignatureVerifier().verify(indexFile, signature, new File(BaseNoGui.getContentFile("lib"), "public.gpg.key"));
|
||||
} catch (Exception e) {
|
||||
BaseNoGui.showWarning(e.getMessage(), e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
return cc.arduino.contributions.Constants.PROTECTED_PACKAGE_NAMES.contains(contributedPackage.getName());
|
||||
}
|
||||
|
||||
private ContributionsIndex parseIndex(File indexFile) throws IOException {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package processing.app;
|
||||
|
||||
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
|
||||
import cc.arduino.contributions.SignatureVerificationFailedException;
|
||||
import cc.arduino.contributions.libraries.LibrariesIndexer;
|
||||
import cc.arduino.contributions.packages.ContributedTool;
|
||||
@ -20,7 +21,10 @@ import processing.app.legacy.PApplet;
|
||||
import processing.app.packages.LibraryList;
|
||||
import processing.app.packages.UserLibrary;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -595,7 +599,7 @@ public class BaseNoGui {
|
||||
}
|
||||
|
||||
static public void initPackages() throws Exception {
|
||||
indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder(), BaseNoGui.getPlatform());
|
||||
indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder(), BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier());
|
||||
File indexFile = indexer.getIndexFile("package_index.json");
|
||||
File defaultPackageJsonFile = new File(getContentFile("dist"), "package_index.json");
|
||||
if (!indexFile.isFile() || (defaultPackageJsonFile.isFile() && defaultPackageJsonFile.lastModified() > indexFile.lastModified())) {
|
||||
|
@ -217,12 +217,18 @@ public class Platform {
|
||||
}
|
||||
|
||||
public List<File> postInstallScripts(File folder) {
|
||||
List<File> scripts = new LinkedList<File>();
|
||||
List<File> scripts = new LinkedList<>();
|
||||
scripts.add(new File(folder, "install_script.sh"));
|
||||
scripts.add(new File(folder, "post_install.sh"));
|
||||
return scripts;
|
||||
}
|
||||
|
||||
public List<File> preUninstallScripts(File folder) {
|
||||
List<File> scripts = new LinkedList<>();
|
||||
scripts.add(new File(folder, "pre_uninstall.sh"));
|
||||
return scripts;
|
||||
}
|
||||
|
||||
public String getOsName() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
|
@ -211,11 +211,17 @@ public class Platform extends processing.app.Platform {
|
||||
}
|
||||
|
||||
public List<File> postInstallScripts(File folder) {
|
||||
List<File> scripts = new LinkedList<File>();
|
||||
List<File> scripts = new LinkedList<>();
|
||||
scripts.add(new File(folder, "post_install.bat"));
|
||||
return scripts;
|
||||
}
|
||||
|
||||
public List<File> preUninstallScripts(File folder) {
|
||||
List<File> scripts = new LinkedList<>();
|
||||
scripts.add(new File(folder, "pre_uninstall.bat"));
|
||||
return scripts;
|
||||
}
|
||||
|
||||
public void symlink(File something, File somewhere) throws IOException, InterruptedException {
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user