mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 13:16:44 +00:00
handle signature and manifest file mixups, add file handler for .asc files
This commit is contained in:
parent
803e43cb45
commit
d109eaa654
7 changed files with 127 additions and 18 deletions
|
@ -267,7 +267,7 @@ jlink {
|
|||
appVersion = "${sparrowVersion}"
|
||||
skipInstaller = os.macOsX || properties.skipInstallers
|
||||
imageOptions = []
|
||||
installerOptions = ['--file-associations', 'src/main/deploy/psbt.properties', '--file-associations', 'src/main/deploy/txn.properties', '--file-associations', 'src/main/deploy/bitcoin.properties', '--file-associations', 'src/main/deploy/auth47.properties', '--file-associations', 'src/main/deploy/lightning.properties', '--license-file', 'LICENSE']
|
||||
installerOptions = ['--file-associations', 'src/main/deploy/psbt.properties', '--file-associations', 'src/main/deploy/txn.properties', '--file-associations', 'src/main/deploy/asc.properties', '--file-associations', 'src/main/deploy/bitcoin.properties', '--file-associations', 'src/main/deploy/auth47.properties', '--file-associations', 'src/main/deploy/lightning.properties', '--license-file', 'LICENSE']
|
||||
if(os.windows) {
|
||||
installerOptions += ['--win-per-user-install', '--win-dir-chooser', '--win-menu', '--win-menu-group', 'Sparrow', '--win-shortcut', '--resource-dir', 'src/main/deploy/package/windows/']
|
||||
imageOptions += ['--icon', 'src/main/deploy/package/windows/sparrow.ico']
|
||||
|
|
3
src/main/deploy/asc.properties
Normal file
3
src/main/deploy/asc.properties
Normal file
|
@ -0,0 +1,3 @@
|
|||
mime-type=application/pgp-signature
|
||||
extension=asc
|
||||
description=ASCII Armored Signature
|
|
@ -94,6 +94,21 @@
|
|||
<key>UTTypeIconFile</key>
|
||||
<string>sparrow.icns</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.sparrowwallet.asc</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>asc</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>ASCII Armored Signature</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>sparrow.icns</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
|
|
|
@ -77,6 +77,7 @@ import java.util.*;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sparrowwallet.sparrow.AppServices.*;
|
||||
import static com.sparrowwallet.sparrow.control.DownloadVerifierDialog.*;
|
||||
|
||||
public class AppController implements Initializable {
|
||||
private static final Logger log = LoggerFactory.getLogger(AppController.class);
|
||||
|
@ -992,6 +993,8 @@ public class AppController implements Initializable {
|
|||
public void openFile(File file) {
|
||||
if(isWalletFile(file)) {
|
||||
openWalletFile(file, true);
|
||||
} else if(isSignatureFile(file)) {
|
||||
verifyDownload(new ActionEvent(file, rootStack));
|
||||
} else {
|
||||
openTransactionFile(file);
|
||||
}
|
||||
|
@ -1476,7 +1479,7 @@ public class AppController implements Initializable {
|
|||
}
|
||||
|
||||
public void verifyDownload(ActionEvent event) {
|
||||
DownloadVerifierDialog downloadVerifierDialog = new DownloadVerifierDialog();
|
||||
DownloadVerifierDialog downloadVerifierDialog = new DownloadVerifierDialog(event.getSource() instanceof File file ? file : null);
|
||||
downloadVerifierDialog.showAndWait();
|
||||
}
|
||||
|
||||
|
@ -3041,6 +3044,13 @@ public class AppController implements Initializable {
|
|||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void requestVerifyDownloadOpen(RequestVerifyDownloadEvent event) {
|
||||
if(tabs.getScene().getWindow().equals(event.getWindow())) {
|
||||
verifyDownload(new ActionEvent(event.getFile(), rootStack));
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void functionAction(FunctionActionEvent event) {
|
||||
selectTab(event.getWallet());
|
||||
|
|
|
@ -68,6 +68,8 @@ import java.util.*;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sparrowwallet.sparrow.control.DownloadVerifierDialog.*;
|
||||
|
||||
public class AppServices {
|
||||
private static final Logger log = LoggerFactory.getLogger(AppServices.class);
|
||||
|
||||
|
@ -883,6 +885,8 @@ public class AppServices {
|
|||
for(File file : openFiles) {
|
||||
if(isWalletFile(file)) {
|
||||
EventManager.get().post(new RequestWalletOpenEvent(openWindow, file));
|
||||
} else if(isSignatureFile(file)) {
|
||||
EventManager.get().post(new RequestVerifyDownloadEvent(openWindow, file));
|
||||
} else {
|
||||
EventManager.get().post(new RequestTransactionOpenEvent(openWindow, file));
|
||||
}
|
||||
|
|
|
@ -42,6 +42,13 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||
private static final DateFormat signatureDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy z");
|
||||
private static final long MAX_VALID_MANIFEST_SIZE = 100 * 1024;
|
||||
|
||||
private static final List<String> SIGNATURE_EXTENSIONS = List.of("asc", "sig", "gpg");
|
||||
private static final List<String> MANIFEST_EXTENSIONS = List.of("txt");
|
||||
private static final List<String> PUBLIC_KEY_EXTENSIONS = List.of("asc");
|
||||
private static final List<String> MACOS_RELEASE_EXTENSIONS = List.of("dmg");
|
||||
private static final List<String> WINDOWS_RELEASE_EXTENSIONS = List.of("exe", "zip");
|
||||
private static final List<String> LINUX_RELEASE_EXTENSIONS = List.of("deb", "rpm", "tar.gz");
|
||||
|
||||
private final ObjectProperty<File> signature = new SimpleObjectProperty<>();
|
||||
private final ObjectProperty<File> manifest = new SimpleObjectProperty<>();
|
||||
private final ObjectProperty<File> publicKey = new SimpleObjectProperty<>();
|
||||
|
@ -56,7 +63,7 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||
|
||||
private static File lastFileParent;
|
||||
|
||||
public DownloadVerifierDialog() {
|
||||
public DownloadVerifierDialog(File initialSignatureFile) {
|
||||
final DialogPane dialogPane = getDialogPane();
|
||||
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
||||
dialogPane.getStylesheets().add(AppServices.class.getResource("dialog.css").toExternalForm());
|
||||
|
@ -74,9 +81,9 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||
|
||||
String version = VersionCheckService.getVersion() != null ? VersionCheckService.getVersion() : "x.x.x";
|
||||
|
||||
Field signatureField = setupField(signature, "Signature", List.of("asc", "sig", "gpg"), false, "sparrow-" + version + "-manifest.txt", null);
|
||||
Field manifestField = setupField(manifest, "Manifest", List.of("txt"), false, "sparrow-" + version + "-manifest", null);
|
||||
Field publicKeyField = setupField(publicKey, "Public Key", List.of("asc"), true, "pgp_keys", publicKeyDisabled);
|
||||
Field signatureField = setupField(signature, "Signature", SIGNATURE_EXTENSIONS, false, "sparrow-" + version + "-manifest.txt", null);
|
||||
Field manifestField = setupField(manifest, "Manifest", MANIFEST_EXTENSIONS, false, "sparrow-" + version + "-manifest", null);
|
||||
Field publicKeyField = setupField(publicKey, "Public Key", PUBLIC_KEY_EXTENSIONS, true, "pgp_keys", publicKeyDisabled);
|
||||
Field releaseFileField = setupField(release, "Release File", getReleaseFileExtensions(), false, getReleaseFileExample(version), null);
|
||||
|
||||
filesFieldset.getChildren().addAll(signatureField, manifestField, publicKeyField, releaseFileField);
|
||||
|
@ -146,19 +153,20 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||
signature.addListener((observable, oldValue, signatureFile) -> {
|
||||
if(signatureFile != null) {
|
||||
boolean verify = true;
|
||||
if(PGPUtils.signatureContainsManifest(signatureFile)) {
|
||||
File actualSignatureFile = findSignatureFile(signatureFile);
|
||||
if(actualSignatureFile != null && !actualSignatureFile.equals(signature.get())) {
|
||||
signature.set(actualSignatureFile);
|
||||
verify = false;
|
||||
} else if(PGPUtils.signatureContainsManifest(signatureFile)) {
|
||||
manifest.set(signatureFile);
|
||||
verify = false;
|
||||
} else {
|
||||
String signatureName = signatureFile.getName();
|
||||
if(signatureName.length() > 4) {
|
||||
File manifestFile = new File(signatureFile.getParent(), signatureName.substring(0, signatureName.length() - 4));
|
||||
if(manifestFile.exists() && !manifestFile.equals(manifest.get())) {
|
||||
File manifestFile = findManifestFile(signatureFile);
|
||||
if(manifestFile != null && !manifestFile.equals(manifest.get())) {
|
||||
manifest.set(manifestFile);
|
||||
verify = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(verify) {
|
||||
verify();
|
||||
|
@ -182,6 +190,16 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if(release.get() == null) {
|
||||
for(File file : manifestMap.keySet()) {
|
||||
File releaseFile = new File(manifestFile.getParent(), file.getName());
|
||||
if(releaseFile.exists() && !releaseFile.equals(release.get())) {
|
||||
release.set(releaseFile);
|
||||
verify = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(IOException e) {
|
||||
log.debug("Error reading manifest file", e);
|
||||
verify = false;
|
||||
|
@ -203,6 +221,10 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||
release.addListener((observable, oldValue, releaseFile) -> {
|
||||
verify();
|
||||
});
|
||||
|
||||
if(initialSignatureFile != null) {
|
||||
javafx.application.Platform.runLater(() -> signature.set(initialSignatureFile));
|
||||
}
|
||||
}
|
||||
|
||||
public void verify() {
|
||||
|
@ -382,17 +404,40 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||
return null;
|
||||
}
|
||||
|
||||
private File findSignatureFile(File providedFile) {
|
||||
for(String extension : SIGNATURE_EXTENSIONS) {
|
||||
File signatureFile = new File(providedFile.getParentFile(), providedFile.getName() + "." + extension);
|
||||
if(signatureFile.exists()) {
|
||||
return signatureFile;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private File findManifestFile(File providedFile) {
|
||||
String signatureName = providedFile.getName();
|
||||
if(signatureName.length() > 4 && SIGNATURE_EXTENSIONS.stream().anyMatch(ext -> signatureName.toLowerCase(Locale.ROOT).endsWith("." + ext))) {
|
||||
File manifestFile = new File(providedFile.getParent(), signatureName.substring(0, signatureName.length() - 4));
|
||||
if(manifestFile.exists()) {
|
||||
return manifestFile;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getReleaseFileExtensions() {
|
||||
Platform platform = Platform.getCurrent();
|
||||
switch(platform) {
|
||||
case OSX -> {
|
||||
return List.of("dmg");
|
||||
return MACOS_RELEASE_EXTENSIONS;
|
||||
}
|
||||
case WINDOWS -> {
|
||||
return List.of("exe", "zip");
|
||||
return WINDOWS_RELEASE_EXTENSIONS;
|
||||
}
|
||||
default -> {
|
||||
return List.of("deb", "rpm", "tar.gz");
|
||||
return LINUX_RELEASE_EXTENSIONS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -432,6 +477,10 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||
return message;
|
||||
}
|
||||
|
||||
public static boolean isSignatureFile(File file) {
|
||||
return file != null && file.getName().length() > 4 && SIGNATURE_EXTENSIONS.stream().anyMatch(ext -> file.getName().toLowerCase(Locale.ROOT).endsWith("." + ext));
|
||||
}
|
||||
|
||||
private static class Header extends GridPane {
|
||||
public Header() {
|
||||
setMaxWidth(Double.MAX_VALUE);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import javafx.stage.Window;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class RequestVerifyDownloadEvent {
|
||||
private final Window window;
|
||||
private final File file;
|
||||
|
||||
public RequestVerifyDownloadEvent(Window window) {
|
||||
this.window = window;
|
||||
this.file = null;
|
||||
}
|
||||
|
||||
public RequestVerifyDownloadEvent(Window window, File file) {
|
||||
this.window = window;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public Window getWindow() {
|
||||
return window;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue