1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-01-31 20:52:13 +01:00

Split download and check signature, add check signature to library index

This commit is contained in:
Mattia Bertorello 2019-07-03 15:26:57 +02:00
parent 2596ecee28
commit 5157688590
No known key found for this signature in database
GPG Key ID: CE1FB2BE91770F24
3 changed files with 81 additions and 47 deletions

View File

@ -33,20 +33,22 @@ import cc.arduino.utils.FileHash;
import cc.arduino.utils.MultiStepProgress;
import cc.arduino.utils.Progress;
import cc.arduino.utils.network.FileDownloader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import processing.app.BaseNoGui;
import processing.app.PreferencesData;
import java.io.File;
import java.net.URL;
import java.nio.file.*;
import java.util.LinkedList;
import java.util.List;
import static processing.app.I18n.format;
import static processing.app.I18n.tr;
public class DownloadableContributionsDownloader {
private static Logger log = LoggerFactory.getLogger(DownloadableContributionsDownloader.class);
private static Logger log = LogManager.getLogger(DownloadableContributionsDownloader.class);
private final File stagingFolder;
@ -147,55 +149,71 @@ public class DownloadableContributionsDownloader {
// Extract the file name from the url
URL packageIndexUrl = new URL(packageIndexUrlString);
URL packageIndexSignatureUrl = new URL(packageIndexUrlString + ".sig");
String[] urlPathParts = packageIndexUrl.getFile().split("/");
File packageIndex = BaseNoGui.indexer.getIndexFile(urlPathParts[urlPathParts.length - 1]);
// Signature file name
File packageIndexSignature = BaseNoGui.indexer.getIndexFile(urlPathParts[urlPathParts.length - 1] + ".sig");
final String statusText = tr("Downloading platforms index...");
downloadedFilesAccumulator.add(packageIndex.getName());
// Create temp files
File packageIndexTemp = File.createTempFile(packageIndexUrl.getPath(), ".tmp");
File packageIndexSignatureTemp = File.createTempFile(packageIndexSignatureUrl.getPath(), ".tmp");
try {
// Download package index
download(packageIndexUrl, packageIndexTemp, progress, statusText, progressListener, true);
try {
// Download signature
download(packageIndexSignatureUrl, packageIndexSignatureTemp, progress, statusText, progressListener, true);
final List<String> domain = new LinkedList<>(PreferencesData.getCollection("http.signature_verify_domains"));
// Default domain
domain.add("downloads.arduino.cc");
// Verify the signature before move the files
boolean signatureVerified = signatureVerifier.isSigned(packageIndexTemp, packageIndexSignatureTemp);
if (signatureVerified) {
// Move if the signature is ok
if (domain.contains(packageIndexUrl.getHost())) {
URL signatureUrl = new URL(packageIndexUrl.toString() + ".sig");
if (checkSignature(progress, downloadedFilesAccumulator, signatureUrl, progressListener, signatureVerifier, statusText, packageIndexTemp)) {
Files.move(packageIndexTemp.toPath(), packageIndex.toPath(), StandardCopyOption.REPLACE_EXISTING);
Files.move(packageIndexSignatureTemp.toPath(), packageIndexSignature.toPath(), StandardCopyOption.REPLACE_EXISTING);
downloadedFilesAccumulator.add(packageIndexSignature.getName());
} else {
downloadedFilesAccumulator.remove(packageIndex.getName());
log.error("{} file signature verification failed. File ignored.", packageIndexSignatureUrl);
System.err.println(format(tr("{0} file signature verification failed. File ignored."), packageIndexUrlString));
}
} catch (Exception e) {
log.error("Cannot download the signature from {} the package will be install in any case", packageIndexSignatureUrl, e);
if (packageIndexTemp.length() > 0) {
Files.move(packageIndexTemp.toPath(), packageIndex.toPath(), StandardCopyOption.REPLACE_EXISTING);
} else {
log.error("The temporarily package index file is empty (path:{},url:{}), It cannot be move there {} ",
packageIndexTemp.toPath(), packageIndexUrlString, packageIndex.toPath());
}
} else {
log.info("The domain is not selected to verify the signature. domain list: {}, packageIndex: {}", domain, packageIndexUrl);
}
} catch (Exception e) {
downloadedFilesAccumulator.remove(packageIndex.getName());
throw e;
} finally {
// Delete useless temp file
Files.deleteIfExists(packageIndexTemp.toPath());
Files.deleteIfExists(packageIndexSignatureTemp.toPath());
}
}
public boolean checkSignature(MultiStepProgress progress, List<String> downloadedFilesAccumulator, URL signatureUrl, ProgressListener progressListener, SignatureVerifier signatureVerifier, String statusText, File fileToVerify) throws Exception {
File packageIndexSignatureTemp = File.createTempFile(signatureUrl.getPath(), ".tmp");
// Signature file name
String[] urlPathParts = signatureUrl.getFile().split("/");
File packageIndexSignature = BaseNoGui.indexer.getIndexFile(urlPathParts[urlPathParts.length - 1]);
try {
// Download signature
download(signatureUrl, packageIndexSignatureTemp, progress, statusText, progressListener, true);
// Verify the signature before move the files
boolean signatureVerified = signatureVerifier.isSigned(fileToVerify, packageIndexSignatureTemp);
if (signatureVerified) {
log.info("Signature verified. url={}, signature url={}, file to verify={}, signature file={}", signatureUrl, signatureUrl, fileToVerify, packageIndexSignatureTemp);
// Move if the signature is ok
Files.move(packageIndexSignatureTemp.toPath(), packageIndexSignature.toPath(), StandardCopyOption.REPLACE_EXISTING);
downloadedFilesAccumulator.add(packageIndexSignature.getName());
} else {
log.error("{} file signature verification failed. File ignored.", signatureUrl);
System.err.println(format(tr("{0} file signature verification failed. File ignored."), signatureUrl.toString()));
}
return signatureVerified;
} catch (Exception e) {
log.error("Cannot download the signature from {} the package will be discard", signatureUrl, e);
throw e;
} finally {
Files.deleteIfExists(packageIndexSignatureTemp.toPath());
}
}
}

View File

@ -31,10 +31,13 @@ package cc.arduino.contributions.libraries;
import cc.arduino.Constants;
import cc.arduino.contributions.DownloadableContributionsDownloader;
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
import cc.arduino.contributions.GZippedJsonDownloader;
import cc.arduino.contributions.ProgressListener;
import cc.arduino.utils.ArchiveExtractor;
import cc.arduino.utils.MultiStepProgress;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.Platform;
@ -45,47 +48,59 @@ import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import static processing.app.I18n.tr;
public class LibraryInstaller {
private static Logger log = LogManager.getLogger(LibraryInstaller.class);
private final Platform platform;
private final GPGDetachedSignatureVerifier signatureVerifier;
public LibraryInstaller(Platform platform) {
public LibraryInstaller(Platform platform, GPGDetachedSignatureVerifier signatureVerifier) {
this.platform = platform;
this.signatureVerifier = signatureVerifier;
}
public synchronized void updateIndex(ProgressListener progressListener) throws Exception {
final MultiStepProgress progress = new MultiStepProgress(3);
List<String> downloadedFilesAccumulator = new LinkedList<>();
DownloadableContributionsDownloader downloader = new DownloadableContributionsDownloader(BaseNoGui.librariesIndexer.getStagingFolder());
// Step 1: Download index
File outputFile = BaseNoGui.librariesIndexer.getIndexFile();
// Create temp files
File libraryIndexTemp = File.createTempFile(new URL(Constants.LIBRARY_INDEX_URL).getPath(), ".tmp");
final URL libraryURL = new URL(Constants.LIBRARY_INDEX_URL);
final String statusText = tr("Downloading libraries index...");
try {
GZippedJsonDownloader gZippedJsonDownloader = new GZippedJsonDownloader(downloader, new URL(Constants.LIBRARY_INDEX_URL), new URL(Constants.LIBRARY_INDEX_URL_GZ));
gZippedJsonDownloader.download(libraryIndexTemp, progress, tr("Downloading libraries index..."), progressListener);
GZippedJsonDownloader gZippedJsonDownloader = new GZippedJsonDownloader(downloader, libraryURL, new URL(Constants.LIBRARY_INDEX_URL_GZ));
gZippedJsonDownloader.download(libraryIndexTemp, progress, statusText, progressListener);
} catch (InterruptedException e) {
// Download interrupted... just exit
return;
}
progress.stepDone();
// TODO: Check downloaded index
URL signatureUrl = new URL(libraryURL.toString() + ".sig");
if (downloader.checkSignature(progress, downloadedFilesAccumulator, signatureUrl, progressListener, signatureVerifier, statusText, libraryIndexTemp)) {
// Replace old index with the updated one
if (libraryIndexTemp.length() > 0) {
Files.move(libraryIndexTemp.toPath(), outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
// Replace old index with the updated one
if (libraryIndexTemp.length() > 0) {
Files.move(libraryIndexTemp.toPath(), outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
// Step 2: Parse index
BaseNoGui.librariesIndexer.parseIndex();
// Step 3: Rescan index
rescanLibraryIndex(progress, progressListener);
} else {
log.error("Fail to verify the signature of {}", libraryURL);
}
// Step 2: Parse index
BaseNoGui.librariesIndexer.parseIndex();
// Step 3: Rescan index
rescanLibraryIndex(progress, progressListener);
}
public synchronized void install(ContributedLibrary lib, Optional<ContributedLibrary> mayReplacedLib, ProgressListener progressListener) throws Exception {

View File

@ -41,8 +41,8 @@ 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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.Platform;
@ -63,7 +63,7 @@ import static processing.app.I18n.format;
import static processing.app.I18n.tr;
public class ContributionInstaller {
private static Logger log = LoggerFactory.getLogger(ContributionInstaller.class);
private static Logger log = LogManager.getLogger(ContributionInstaller.class);
private final Platform platform;
private final SignatureVerifier signatureVerifier;
@ -267,10 +267,11 @@ public class ContributionInstaller {
// now try to remove the containing TOOL_NAME folder
// (and silently fail if another version of the tool is installed)
try {
Files.deleteIfExists(destFolder.getParentFile().toPath());
Files.delete(destFolder.getParentFile().toPath());
} catch (Exception e) {
// ignore
log.error(e.getMessage(), e);
log.info("The directory is not empty there is another version installed. directory {}",
destFolder.getParentFile().toPath(), e);
}
}