mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-26 05:26:45 +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}"
|
appVersion = "${sparrowVersion}"
|
||||||
skipInstaller = os.macOsX || properties.skipInstallers
|
skipInstaller = os.macOsX || properties.skipInstallers
|
||||||
imageOptions = []
|
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) {
|
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/']
|
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']
|
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>
|
<key>UTTypeIconFile</key>
|
||||||
<string>sparrow.icns</string>
|
<string>sparrow.icns</string>
|
||||||
</dict>
|
</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>
|
</array>
|
||||||
<key>CFBundleDocumentTypes</key>
|
<key>CFBundleDocumentTypes</key>
|
||||||
<array>
|
<array>
|
||||||
|
|
|
@ -77,6 +77,7 @@ import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.sparrowwallet.sparrow.AppServices.*;
|
import static com.sparrowwallet.sparrow.AppServices.*;
|
||||||
|
import static com.sparrowwallet.sparrow.control.DownloadVerifierDialog.*;
|
||||||
|
|
||||||
public class AppController implements Initializable {
|
public class AppController implements Initializable {
|
||||||
private static final Logger log = LoggerFactory.getLogger(AppController.class);
|
private static final Logger log = LoggerFactory.getLogger(AppController.class);
|
||||||
|
@ -992,6 +993,8 @@ public class AppController implements Initializable {
|
||||||
public void openFile(File file) {
|
public void openFile(File file) {
|
||||||
if(isWalletFile(file)) {
|
if(isWalletFile(file)) {
|
||||||
openWalletFile(file, true);
|
openWalletFile(file, true);
|
||||||
|
} else if(isSignatureFile(file)) {
|
||||||
|
verifyDownload(new ActionEvent(file, rootStack));
|
||||||
} else {
|
} else {
|
||||||
openTransactionFile(file);
|
openTransactionFile(file);
|
||||||
}
|
}
|
||||||
|
@ -1476,7 +1479,7 @@ public class AppController implements Initializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verifyDownload(ActionEvent event) {
|
public void verifyDownload(ActionEvent event) {
|
||||||
DownloadVerifierDialog downloadVerifierDialog = new DownloadVerifierDialog();
|
DownloadVerifierDialog downloadVerifierDialog = new DownloadVerifierDialog(event.getSource() instanceof File file ? file : null);
|
||||||
downloadVerifierDialog.showAndWait();
|
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
|
@Subscribe
|
||||||
public void functionAction(FunctionActionEvent event) {
|
public void functionAction(FunctionActionEvent event) {
|
||||||
selectTab(event.getWallet());
|
selectTab(event.getWallet());
|
||||||
|
|
|
@ -68,6 +68,8 @@ import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.sparrowwallet.sparrow.control.DownloadVerifierDialog.*;
|
||||||
|
|
||||||
public class AppServices {
|
public class AppServices {
|
||||||
private static final Logger log = LoggerFactory.getLogger(AppServices.class);
|
private static final Logger log = LoggerFactory.getLogger(AppServices.class);
|
||||||
|
|
||||||
|
@ -883,6 +885,8 @@ public class AppServices {
|
||||||
for(File file : openFiles) {
|
for(File file : openFiles) {
|
||||||
if(isWalletFile(file)) {
|
if(isWalletFile(file)) {
|
||||||
EventManager.get().post(new RequestWalletOpenEvent(openWindow, file));
|
EventManager.get().post(new RequestWalletOpenEvent(openWindow, file));
|
||||||
|
} else if(isSignatureFile(file)) {
|
||||||
|
EventManager.get().post(new RequestVerifyDownloadEvent(openWindow, file));
|
||||||
} else {
|
} else {
|
||||||
EventManager.get().post(new RequestTransactionOpenEvent(openWindow, file));
|
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 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 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> signature = new SimpleObjectProperty<>();
|
||||||
private final ObjectProperty<File> manifest = new SimpleObjectProperty<>();
|
private final ObjectProperty<File> manifest = new SimpleObjectProperty<>();
|
||||||
private final ObjectProperty<File> publicKey = new SimpleObjectProperty<>();
|
private final ObjectProperty<File> publicKey = new SimpleObjectProperty<>();
|
||||||
|
@ -56,7 +63,7 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
||||||
|
|
||||||
private static File lastFileParent;
|
private static File lastFileParent;
|
||||||
|
|
||||||
public DownloadVerifierDialog() {
|
public DownloadVerifierDialog(File initialSignatureFile) {
|
||||||
final DialogPane dialogPane = getDialogPane();
|
final DialogPane dialogPane = getDialogPane();
|
||||||
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
||||||
dialogPane.getStylesheets().add(AppServices.class.getResource("dialog.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";
|
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 signatureField = setupField(signature, "Signature", SIGNATURE_EXTENSIONS, false, "sparrow-" + version + "-manifest.txt", null);
|
||||||
Field manifestField = setupField(manifest, "Manifest", List.of("txt"), false, "sparrow-" + version + "-manifest", null);
|
Field manifestField = setupField(manifest, "Manifest", MANIFEST_EXTENSIONS, false, "sparrow-" + version + "-manifest", null);
|
||||||
Field publicKeyField = setupField(publicKey, "Public Key", List.of("asc"), true, "pgp_keys", publicKeyDisabled);
|
Field publicKeyField = setupField(publicKey, "Public Key", PUBLIC_KEY_EXTENSIONS, true, "pgp_keys", publicKeyDisabled);
|
||||||
Field releaseFileField = setupField(release, "Release File", getReleaseFileExtensions(), false, getReleaseFileExample(version), null);
|
Field releaseFileField = setupField(release, "Release File", getReleaseFileExtensions(), false, getReleaseFileExample(version), null);
|
||||||
|
|
||||||
filesFieldset.getChildren().addAll(signatureField, manifestField, publicKeyField, releaseFileField);
|
filesFieldset.getChildren().addAll(signatureField, manifestField, publicKeyField, releaseFileField);
|
||||||
|
@ -146,19 +153,20 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
||||||
signature.addListener((observable, oldValue, signatureFile) -> {
|
signature.addListener((observable, oldValue, signatureFile) -> {
|
||||||
if(signatureFile != null) {
|
if(signatureFile != null) {
|
||||||
boolean verify = true;
|
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);
|
manifest.set(signatureFile);
|
||||||
verify = false;
|
verify = false;
|
||||||
} else {
|
} else {
|
||||||
String signatureName = signatureFile.getName();
|
File manifestFile = findManifestFile(signatureFile);
|
||||||
if(signatureName.length() > 4) {
|
if(manifestFile != null && !manifestFile.equals(manifest.get())) {
|
||||||
File manifestFile = new File(signatureFile.getParent(), signatureName.substring(0, signatureName.length() - 4));
|
|
||||||
if(manifestFile.exists() && !manifestFile.equals(manifest.get())) {
|
|
||||||
manifest.set(manifestFile);
|
manifest.set(manifestFile);
|
||||||
verify = false;
|
verify = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(verify) {
|
if(verify) {
|
||||||
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) {
|
} catch(IOException e) {
|
||||||
log.debug("Error reading manifest file", e);
|
log.debug("Error reading manifest file", e);
|
||||||
verify = false;
|
verify = false;
|
||||||
|
@ -203,6 +221,10 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
||||||
release.addListener((observable, oldValue, releaseFile) -> {
|
release.addListener((observable, oldValue, releaseFile) -> {
|
||||||
verify();
|
verify();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(initialSignatureFile != null) {
|
||||||
|
javafx.application.Platform.runLater(() -> signature.set(initialSignatureFile));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verify() {
|
public void verify() {
|
||||||
|
@ -382,17 +404,40 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
||||||
return null;
|
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() {
|
private List<String> getReleaseFileExtensions() {
|
||||||
Platform platform = Platform.getCurrent();
|
Platform platform = Platform.getCurrent();
|
||||||
switch(platform) {
|
switch(platform) {
|
||||||
case OSX -> {
|
case OSX -> {
|
||||||
return List.of("dmg");
|
return MACOS_RELEASE_EXTENSIONS;
|
||||||
}
|
}
|
||||||
case WINDOWS -> {
|
case WINDOWS -> {
|
||||||
return List.of("exe", "zip");
|
return WINDOWS_RELEASE_EXTENSIONS;
|
||||||
}
|
}
|
||||||
default -> {
|
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;
|
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 {
|
private static class Header extends GridPane {
|
||||||
public Header() {
|
public Header() {
|
||||||
setMaxWidth(Double.MAX_VALUE);
|
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