mirror of
https://github.com/arduino/Arduino.git
synced 2025-02-26 20:54:22 +01:00
Delete cached file if the signature verify fail
This commit is contained in:
parent
1bfdf83db8
commit
2d042820a0
@ -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 {
|
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) -> {
|
downloader.addObserver((o, arg) -> {
|
||||||
FileDownloader me = (FileDownloader) o;
|
FileDownloader me = (FileDownloader) o;
|
||||||
String msg = "";
|
String msg = "";
|
||||||
@ -148,22 +148,24 @@ public class DownloadableContributionsDownloader {
|
|||||||
public void downloadIndexAndSignature(MultiStepProgress progress, URL packageIndexUrl, ProgressListener progressListener, SignatureVerifier signatureVerifier) throws Exception {
|
public void downloadIndexAndSignature(MultiStepProgress progress, URL packageIndexUrl, ProgressListener progressListener, SignatureVerifier signatureVerifier) throws Exception {
|
||||||
|
|
||||||
// Extract the file name from the url
|
// Extract the file name from the url
|
||||||
String indexFileName = FilenameUtils.getName(packageIndexUrl.getPath());
|
final String indexFileName = FilenameUtils.getName(packageIndexUrl.getPath());
|
||||||
File packageIndex = BaseNoGui.indexer.getIndexFile(indexFileName);
|
final File packageIndex = BaseNoGui.indexer.getIndexFile(indexFileName);
|
||||||
|
|
||||||
final String statusText = tr("Downloading platforms index...");
|
final String statusText = tr("Downloading platforms index...");
|
||||||
|
|
||||||
// Create temp files
|
// Create temp files
|
||||||
File packageIndexTemp = File.createTempFile(indexFileName, ".tmp");
|
final File packageIndexTemp = File.createTempFile(indexFileName, ".tmp");
|
||||||
try {
|
try {
|
||||||
// Download package index
|
// Download package index
|
||||||
download(packageIndexUrl, packageIndexTemp, progress, statusText, progressListener, true, true);
|
download(packageIndexUrl, packageIndexTemp, progress, statusText, progressListener, true, true);
|
||||||
|
final URL signatureUrl = new URL(packageIndexUrl.toString() + ".sig");
|
||||||
|
|
||||||
if (verifyDomain(packageIndexUrl)) {
|
if (verifyDomain(packageIndexUrl)) {
|
||||||
URL signatureUrl = new URL(packageIndexUrl.toString() + ".sig");
|
|
||||||
|
|
||||||
if (checkSignature(progress, signatureUrl, progressListener, signatureVerifier, statusText, packageIndexTemp)) {
|
if (checkSignature(progress, signatureUrl, progressListener, signatureVerifier, statusText, packageIndexTemp)) {
|
||||||
Files.move(packageIndexTemp.toPath(), packageIndex.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
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 {
|
} else {
|
||||||
// Move the package index to the destination when the signature is not necessary
|
// 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 {
|
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
|
// Signature file name
|
||||||
String signatureFileName = FilenameUtils.getName(signatureUrl.getPath());
|
final String signatureFileName = FilenameUtils.getName(signatureUrl.getPath());
|
||||||
File packageIndexSignature = BaseNoGui.indexer.getIndexFile(signatureFileName);
|
final File packageIndexSignature = BaseNoGui.indexer.getIndexFile(signatureFileName);
|
||||||
File packageIndexSignatureTemp = File.createTempFile(signatureFileName, ".tmp");
|
final File packageIndexSignatureTemp = File.createTempFile(signatureFileName, ".tmp");
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -207,7 +216,7 @@ public class DownloadableContributionsDownloader {
|
|||||||
download(signatureUrl, packageIndexSignatureTemp, progress, statusText, progressListener, true);
|
download(signatureUrl, packageIndexSignatureTemp, progress, statusText, progressListener, true);
|
||||||
|
|
||||||
// Verify the signature before move the files
|
// Verify the signature before move the files
|
||||||
boolean signatureVerified = signatureVerifier.isSigned(fileToVerify, packageIndexSignatureTemp);
|
final boolean signatureVerified = signatureVerifier.isSigned(fileToVerify, packageIndexSignatureTemp);
|
||||||
if (signatureVerified) {
|
if (signatureVerified) {
|
||||||
log.info("Signature verified. url={}, signature url={}, file to verify={}, signature file={}", signatureUrl, signatureUrl, fileToVerify, packageIndexSignatureTemp);
|
log.info("Signature verified. url={}, signature url={}, file to verify={}, signature file={}", signatureUrl, signatureUrl, fileToVerify, packageIndexSignatureTemp);
|
||||||
// Move if the signature is ok
|
// Move if the signature is ok
|
||||||
|
@ -36,6 +36,7 @@ import cc.arduino.contributions.GZippedJsonDownloader;
|
|||||||
import cc.arduino.contributions.ProgressListener;
|
import cc.arduino.contributions.ProgressListener;
|
||||||
import cc.arduino.utils.ArchiveExtractor;
|
import cc.arduino.utils.ArchiveExtractor;
|
||||||
import cc.arduino.utils.MultiStepProgress;
|
import cc.arduino.utils.MultiStepProgress;
|
||||||
|
import cc.arduino.utils.network.FileDownloader;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -74,9 +75,10 @@ public class LibraryInstaller {
|
|||||||
String signatureFileName = FilenameUtils.getName(new URL(Constants.LIBRARY_INDEX_URL).getPath());
|
String signatureFileName = FilenameUtils.getName(new URL(Constants.LIBRARY_INDEX_URL).getPath());
|
||||||
File libraryIndexTemp = File.createTempFile(signatureFileName, ".tmp");
|
File libraryIndexTemp = File.createTempFile(signatureFileName, ".tmp");
|
||||||
final URL libraryURL = new URL(Constants.LIBRARY_INDEX_URL);
|
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...");
|
final String statusText = tr("Downloading libraries index...");
|
||||||
try {
|
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);
|
gZippedJsonDownloader.download(libraryIndexTemp, progress, statusText, progressListener, true);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// Download interrupted... just exit
|
// Download interrupted... just exit
|
||||||
@ -98,7 +100,8 @@ public class LibraryInstaller {
|
|||||||
// Step 3: Rescan index
|
// Step 3: Rescan index
|
||||||
rescanLibraryIndex(progress, progressListener);
|
rescanLibraryIndex(progress, progressListener);
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
log.info("The domain is not selected to verify the signature. library index: {}", signatureUrl);
|
log.info("The domain is not selected to verify the signature. library index: {}", signatureUrl);
|
||||||
|
@ -34,15 +34,18 @@ import org.apache.logging.log4j.LogManager;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import processing.app.helpers.FileUtils;
|
import processing.app.helpers.FileUtils;
|
||||||
|
|
||||||
|
import javax.script.ScriptException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Optional;
|
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 {
|
private void downloadFile(boolean noResume) throws InterruptedException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setStatus(Status.CONNECTING);
|
setStatus(Status.CONNECTING);
|
||||||
|
|
||||||
final Optional<FileDownloaderCache.FileCached> fileCached = FileDownloaderCache.getFileCached(downloadUrl);
|
final Optional<FileDownloaderCache.FileCached> fileCachedOpt = FileDownloaderCache.getFileCached(downloadUrl);
|
||||||
if (fileCached.isPresent() && fileCached.get().isNotChange()) {
|
if (fileCachedOpt.isPresent()) {
|
||||||
final Optional<File> fileFromCache = getFileCached(fileCached.get());
|
final FileDownloaderCache.FileCached fileCached = fileCachedOpt.get();
|
||||||
if (fileFromCache.isPresent()) {
|
|
||||||
|
final Optional<File> fileFromCache = getFileCached(fileCached);
|
||||||
|
if (fileCached.isNotChange() && fileFromCache.isPresent()) {
|
||||||
// Copy the cached file in the destination file
|
// Copy the cached file in the destination file
|
||||||
FileUtils.copyFile(fileFromCache.get(), outputFile);
|
FileUtils.copyFile(fileFromCache.get(), outputFile);
|
||||||
} else {
|
} else {
|
||||||
openConnectionAndFillTheFile(noResume);
|
openConnectionAndFillTheFile(noResume);
|
||||||
|
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
fileCached.get().updateCacheFile(outputFile);
|
fileCached.updateCacheFile(outputFile);
|
||||||
} else {
|
} else {
|
||||||
log.info("The file {} was not cached because allow cache is false", downloadUrl);
|
log.info("The file {} was not cached because allow cache is false", downloadUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
openConnectionAndFillTheFile(noResume);
|
||||||
}
|
}
|
||||||
setStatus(Status.COMPLETE);
|
setStatus(Status.COMPLETE);
|
||||||
|
|
||||||
|
@ -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,
|
throws URISyntaxException, NoSuchMethodException, ScriptException,
|
||||||
IOException {
|
IOException {
|
||||||
// Return always and empty file if the cache is not enable
|
// Return always and empty file if the cache is not enable
|
||||||
@ -268,7 +268,8 @@ public class FileDownloaderCache {
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isExpire() {
|
public boolean isExpire() {
|
||||||
// Check if the file is expire
|
// 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
|
@JsonIgnore
|
||||||
@ -298,7 +299,7 @@ public class FileDownloaderCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public Optional<File> getFileFromCache() {
|
Optional<File> getFileFromCache() {
|
||||||
if (md5Check()) {
|
if (md5Check()) {
|
||||||
return Optional.of(Paths.get(localPath).toFile());
|
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);
|
Path cacheFilePath = Paths.get(localPath);
|
||||||
|
|
||||||
// If the cache directory does not exist create it
|
// 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 {
|
private String calculateMD5() throws IOException, NoSuchAlgorithmException {
|
||||||
if (exists()) {
|
if (exists()) {
|
||||||
return FileHash.hash(Paths.get(localPath).toFile(), "MD5");
|
return FileHash.hash(Paths.get(localPath).toFile(), "MD5");
|
||||||
@ -344,7 +350,7 @@ public class FileDownloaderCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean md5Check() {
|
boolean md5Check() {
|
||||||
try {
|
try {
|
||||||
return !Objects.isNull(getMD5()) && Objects.equals(calculateMD5(), getMD5());
|
return !Objects.isNull(getMD5()) && Objects.equals(calculateMD5(), getMD5());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -354,7 +360,7 @@ public class FileDownloaderCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public LocalDateTime getExpiresTime() {
|
LocalDateTime getExpiresTime() {
|
||||||
final int maxAge;
|
final int maxAge;
|
||||||
if (cacheControl != null) {
|
if (cacheControl != null) {
|
||||||
maxAge = cacheControl.getMaxAge();
|
maxAge = cacheControl.getMaxAge();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user