1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-11-29 10:24:12 +01:00

Delete cached file if the signature verify fail

This commit is contained in:
Mattia Bertorello 2019-07-12 13:00:48 +02:00
parent 1bfdf83db8
commit 2d042820a0
No known key found for this signature in database
GPG Key ID: CE1FB2BE91770F24
4 changed files with 67 additions and 23 deletions

View File

@ -126,7 +126,7 @@ public class DownloadableContributionsDownloader {
}
public void download(URL url, File tmpFile, Progress progress, String statusText, ProgressListener progressListener, boolean noResume, boolean allowCache) throws Exception {
FileDownloader downloader = new FileDownloader(url, tmpFile, allowCache);
final FileDownloader downloader = new FileDownloader(url, tmpFile, allowCache);
downloader.addObserver((o, arg) -> {
FileDownloader me = (FileDownloader) o;
String msg = "";
@ -148,22 +148,24 @@ public class DownloadableContributionsDownloader {
public void downloadIndexAndSignature(MultiStepProgress progress, URL packageIndexUrl, ProgressListener progressListener, SignatureVerifier signatureVerifier) throws Exception {
// Extract the file name from the url
String indexFileName = FilenameUtils.getName(packageIndexUrl.getPath());
File packageIndex = BaseNoGui.indexer.getIndexFile(indexFileName);
final String indexFileName = FilenameUtils.getName(packageIndexUrl.getPath());
final File packageIndex = BaseNoGui.indexer.getIndexFile(indexFileName);
final String statusText = tr("Downloading platforms index...");
// Create temp files
File packageIndexTemp = File.createTempFile(indexFileName, ".tmp");
final File packageIndexTemp = File.createTempFile(indexFileName, ".tmp");
try {
// Download package index
download(packageIndexUrl, packageIndexTemp, progress, statusText, progressListener, true, true);
final URL signatureUrl = new URL(packageIndexUrl.toString() + ".sig");
if (verifyDomain(packageIndexUrl)) {
URL signatureUrl = new URL(packageIndexUrl.toString() + ".sig");
if (checkSignature(progress, signatureUrl, progressListener, signatureVerifier, statusText, packageIndexTemp)) {
Files.move(packageIndexTemp.toPath(), packageIndex.toPath(), StandardCopyOption.REPLACE_EXISTING);
} else {
log.info("The cached files have been removed. {} {}", packageIndexUrl, signatureUrl);
FileDownloader.invalidateFiles(packageIndexUrl, signatureUrl);
}
} else {
// Move the package index to the destination when the signature is not necessary
@ -196,10 +198,17 @@ public class DownloadableContributionsDownloader {
public boolean checkSignature(MultiStepProgress progress, URL signatureUrl, ProgressListener progressListener, SignatureVerifier signatureVerifier, String statusText, File fileToVerify) throws Exception {
final boolean allowInsecurePackages =
PreferencesData.getBoolean("allow_insecure_packages", false);
if (allowInsecurePackages) {
log.info("Allow insecure packages is true the signature will be skip and return always verified");
return true;
}
// Signature file name
String signatureFileName = FilenameUtils.getName(signatureUrl.getPath());
File packageIndexSignature = BaseNoGui.indexer.getIndexFile(signatureFileName);
File packageIndexSignatureTemp = File.createTempFile(signatureFileName, ".tmp");
final String signatureFileName = FilenameUtils.getName(signatureUrl.getPath());
final File packageIndexSignature = BaseNoGui.indexer.getIndexFile(signatureFileName);
final File packageIndexSignatureTemp = File.createTempFile(signatureFileName, ".tmp");
try {
@ -207,7 +216,7 @@ public class DownloadableContributionsDownloader {
download(signatureUrl, packageIndexSignatureTemp, progress, statusText, progressListener, true);
// Verify the signature before move the files
boolean signatureVerified = signatureVerifier.isSigned(fileToVerify, packageIndexSignatureTemp);
final 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

View File

@ -36,6 +36,7 @@ import cc.arduino.contributions.GZippedJsonDownloader;
import cc.arduino.contributions.ProgressListener;
import cc.arduino.utils.ArchiveExtractor;
import cc.arduino.utils.MultiStepProgress;
import cc.arduino.utils.network.FileDownloader;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -74,9 +75,10 @@ public class LibraryInstaller {
String signatureFileName = FilenameUtils.getName(new URL(Constants.LIBRARY_INDEX_URL).getPath());
File libraryIndexTemp = File.createTempFile(signatureFileName, ".tmp");
final URL libraryURL = new URL(Constants.LIBRARY_INDEX_URL);
final URL libraryGzURL = new URL(Constants.LIBRARY_INDEX_URL_GZ);
final String statusText = tr("Downloading libraries index...");
try {
GZippedJsonDownloader gZippedJsonDownloader = new GZippedJsonDownloader(downloader, libraryURL, new URL(Constants.LIBRARY_INDEX_URL_GZ));
GZippedJsonDownloader gZippedJsonDownloader = new GZippedJsonDownloader(downloader, libraryURL, libraryGzURL);
gZippedJsonDownloader.download(libraryIndexTemp, progress, statusText, progressListener, true);
} catch (InterruptedException e) {
// Download interrupted... just exit
@ -98,7 +100,8 @@ public class LibraryInstaller {
// Step 3: Rescan index
rescanLibraryIndex(progress, progressListener);
} else {
log.error("Fail to verify the signature of {}", libraryURL);
FileDownloader.invalidateFiles(libraryGzURL, libraryURL, signatureUrl);
log.error("Fail to verify the signature of {} the cached files have been removed", libraryURL);
}
} else {
log.info("The domain is not selected to verify the signature. library index: {}", signatureUrl);

View File

@ -34,15 +34,18 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import processing.app.helpers.FileUtils;
import javax.script.ScriptException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Observable;
import java.util.Optional;
@ -137,26 +140,49 @@ public class FileDownloader extends Observable {
}
}
public static void invalidateFiles(URL... filesUrl) {
// For each file delete the file cached if exist
Arrays.stream(filesUrl).forEach(url -> {
try {
FileDownloaderCache.getFileCached(url).ifPresent(fileCached -> {
try {
log.info("Invalidate this file {} that comes from {}", fileCached.getLocalPath(), fileCached.getRemoteURL());
fileCached.invalidateCache();
} catch (Exception e) {
log.warn("Fail to invalidate cache", e);
}
});
} catch (URISyntaxException | NoSuchMethodException | ScriptException | IOException e) {
log.warn("Fail to get the file cached during the file invalidation", e);
}
});
}
private void downloadFile(boolean noResume) throws InterruptedException {
try {
setStatus(Status.CONNECTING);
final Optional<FileDownloaderCache.FileCached> fileCached = FileDownloaderCache.getFileCached(downloadUrl);
if (fileCached.isPresent() && fileCached.get().isNotChange()) {
final Optional<File> fileFromCache = getFileCached(fileCached.get());
if (fileFromCache.isPresent()) {
final Optional<FileDownloaderCache.FileCached> fileCachedOpt = FileDownloaderCache.getFileCached(downloadUrl);
if (fileCachedOpt.isPresent()) {
final FileDownloaderCache.FileCached fileCached = fileCachedOpt.get();
final Optional<File> fileFromCache = getFileCached(fileCached);
if (fileCached.isNotChange() && fileFromCache.isPresent()) {
// Copy the cached file in the destination file
FileUtils.copyFile(fileFromCache.get(), outputFile);
} else {
openConnectionAndFillTheFile(noResume);
if (allowCache) {
fileCached.get().updateCacheFile(outputFile);
fileCached.updateCacheFile(outputFile);
} else {
log.info("The file {} was not cached because allow cache is false", downloadUrl);
}
}
} else {
openConnectionAndFillTheFile(noResume);
}
setStatus(Status.COMPLETE);

View File

@ -117,7 +117,7 @@ public class FileDownloaderCache {
}
}
public static Optional<FileCached> getFileCached(final URL remoteURL)
static Optional<FileCached> getFileCached(final URL remoteURL)
throws URISyntaxException, NoSuchMethodException, ScriptException,
IOException {
// Return always and empty file if the cache is not enable
@ -268,7 +268,8 @@ public class FileDownloaderCache {
@JsonIgnore
public boolean isExpire() {
// Check if the file is expire
return this.getExpiresTime().isBefore(LocalDateTime.now());
final LocalDateTime now = LocalDateTime.now();
return this.getExpiresTime().isBefore(now) || this.getExpiresTime().isEqual(now);
}
@JsonIgnore
@ -298,7 +299,7 @@ public class FileDownloaderCache {
}
@JsonIgnore
public Optional<File> getFileFromCache() {
Optional<File> getFileFromCache() {
if (md5Check()) {
return Optional.of(Paths.get(localPath).toFile());
}
@ -306,7 +307,7 @@ public class FileDownloaderCache {
}
public synchronized void updateCacheFile(File fileToCache) throws Exception {
synchronized void updateCacheFile(File fileToCache) throws Exception {
Path cacheFilePath = Paths.get(localPath);
// If the cache directory does not exist create it
@ -336,6 +337,11 @@ public class FileDownloaderCache {
}
synchronized void invalidateCache() throws IOException {
cachedFiles.remove(remoteURL);
Files.deleteIfExists(Paths.get(localPath));
}
private String calculateMD5() throws IOException, NoSuchAlgorithmException {
if (exists()) {
return FileHash.hash(Paths.get(localPath).toFile(), "MD5");
@ -344,7 +350,7 @@ public class FileDownloaderCache {
}
@JsonIgnore
public boolean md5Check() {
boolean md5Check() {
try {
return !Objects.isNull(getMD5()) && Objects.equals(calculateMD5(), getMD5());
} catch (Exception e) {
@ -354,7 +360,7 @@ public class FileDownloaderCache {
}
@JsonIgnore
public LocalDateTime getExpiresTime() {
LocalDateTime getExpiresTime() {
final int maxAge;
if (cacheControl != null) {
maxAge = cacheControl.getMaxAge();