mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-02 12:26:45 +00:00
add wallet import for samourai backup export
This commit is contained in:
parent
31346e2afa
commit
d68ab40c94
7 changed files with 105 additions and 4 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
|||
Subproject commit 3f4ee7af747b80976cda8ebd3c687b6a4ba5ea3f
|
||||
Subproject commit 7584bcf26001d3705bb9467349112bc701905e7f
|
|
@ -38,6 +38,7 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
|
|||
private final KeystoreFileImport importer;
|
||||
private String fileName;
|
||||
private byte[] fileBytes;
|
||||
private String password;
|
||||
|
||||
public FileWalletKeystoreImportPane(KeystoreFileImport importer) {
|
||||
super(importer, importer.getName(), "Wallet import", importer.getKeystoreImportDescription(), "image/" + importer.getWalletModel().getType() + ".png", importer.isKeystoreImportScannable(), importer.isFileFormatAvailable());
|
||||
|
@ -46,6 +47,7 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
|
|||
|
||||
protected void importFile(String fileName, InputStream inputStream, String password) throws ImportException {
|
||||
this.fileName = fileName;
|
||||
this.password = password;
|
||||
|
||||
List<ScriptType> scriptTypes = ScriptType.getAddressableScriptTypes(PolicyType.SINGLE);
|
||||
if(wallets != null && !wallets.isEmpty()) {
|
||||
|
@ -83,7 +85,7 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
|
|||
EventManager.get().post(new WalletImportEvent(wallet));
|
||||
} else {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
|
||||
Keystore keystore = importer.getKeystore(scriptType, bais, "");
|
||||
Keystore keystore = importer.getKeystore(scriptType, bais, password);
|
||||
|
||||
Wallet wallet = new Wallet();
|
||||
wallet.setName(Files.getNameWithoutExtension(fileName));
|
||||
|
|
|
@ -51,7 +51,8 @@ public class WalletImportDialog extends Dialog<Wallet> {
|
|||
AnchorPane.setRightAnchor(scrollPane, 0.0);
|
||||
|
||||
importAccordion = new Accordion();
|
||||
List<KeystoreFileImport> keystoreImporters = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new Jade(), new KeystoneSinglesig(), new PassportSinglesig(), new GordianSeedTool(), new SeedSigner(), new SpecterDIY(), new Krux(), new AirGapVault());
|
||||
List<KeystoreFileImport> keystoreImporters = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new Jade(), new KeystoneSinglesig(), new PassportSinglesig(),
|
||||
new GordianSeedTool(), new SeedSigner(), new SpecterDIY(), new Krux(), new AirGapVault(), new Samourai());
|
||||
for(KeystoreFileImport importer : keystoreImporters) {
|
||||
if(!importer.isDeprecated() || Config.get().isShowDeprecatedImportExport()) {
|
||||
FileWalletKeystoreImportPane importPane = new FileWalletKeystoreImportPane(importer);
|
||||
|
@ -59,7 +60,8 @@ public class WalletImportDialog extends Dialog<Wallet> {
|
|||
}
|
||||
}
|
||||
|
||||
List<WalletImport> walletImporters = new ArrayList<>(List.of(new Bip129(), new CaravanMultisig(), new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new KeystoneMultisig(), new Descriptor(), new SpecterDesktop(), new BlueWalletMultisig(), new Sparrow(), new JadeMultisig()));
|
||||
List<WalletImport> walletImporters = new ArrayList<>(List.of(new Bip129(), new CaravanMultisig(), new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(),
|
||||
new KeystoneMultisig(), new Descriptor(), new SpecterDesktop(), new BlueWalletMultisig(), new Sparrow(), new JadeMultisig()));
|
||||
if(!selectedWalletForms.isEmpty()) {
|
||||
walletImporters.add(new WalletLabels(selectedWalletForms));
|
||||
}
|
||||
|
|
97
src/main/java/com/sparrowwallet/sparrow/io/Samourai.java
Normal file
97
src/main/java/com/sparrowwallet/sparrow/io/Samourai.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package com.sparrowwallet.sparrow.io;
|
||||
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.samourai.wallet.crypto.AESUtil;
|
||||
import com.samourai.wallet.util.CharSequenceX;
|
||||
import com.sparrowwallet.drongo.Utils;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class Samourai implements KeystoreFileImport {
|
||||
@Override
|
||||
public String getKeystoreImportDescription(int account) {
|
||||
return "Import the wallet backup file samourai.txt exported from the Samourai app.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
|
||||
try {
|
||||
String input = CharStreams.toString(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||
|
||||
Gson gson = new Gson();
|
||||
Type stringStringMap = new TypeToken<Map<String, JsonElement>>() {
|
||||
}.getType();
|
||||
Map<String, JsonElement> map = gson.fromJson(input, stringStringMap);
|
||||
|
||||
String payload = input;
|
||||
if(map.containsKey("payload")) {
|
||||
payload = map.get("payload").getAsString();
|
||||
}
|
||||
|
||||
int version = 1;
|
||||
if(map.containsKey("version")) {
|
||||
version = map.get("version").getAsInt();
|
||||
}
|
||||
|
||||
String decrypted;
|
||||
if(version == 1) {
|
||||
decrypted = AESUtil.decrypt(payload, new CharSequenceX(password), AESUtil.DefaultPBKDF2Iterations);
|
||||
} else if(version == 2) {
|
||||
decrypted = AESUtil.decryptSHA256(payload, new CharSequenceX(password));
|
||||
} else {
|
||||
throw new ImportException("Unsupported backup version: " + version);
|
||||
}
|
||||
|
||||
SamouraiBackup backup = gson.fromJson(decrypted, SamouraiBackup.class);
|
||||
DeterministicSeed seed = new DeterministicSeed(Utils.hexToBytes(backup.wallet.seed), password, 0);
|
||||
Keystore keystore = Keystore.fromSeed(seed, scriptType.getDefaultDerivation());
|
||||
keystore.setLabel(getWalletModel().toDisplayString());
|
||||
return keystore;
|
||||
} catch(ImportException e) {
|
||||
throw e;
|
||||
} catch(Exception e) {
|
||||
throw new ImportException("Error importing backup", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeystoreImportScannable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncrypted(File file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Samourai Backup";
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletModel getWalletModel() {
|
||||
return WalletModel.SAMOURAI;
|
||||
}
|
||||
|
||||
private static class SamouraiBackup {
|
||||
public SamouraiWallet wallet;
|
||||
}
|
||||
|
||||
private static class SamouraiWallet {
|
||||
public boolean testnet;
|
||||
public String seed;
|
||||
public String fingerprint;
|
||||
}
|
||||
}
|
BIN
src/main/resources/image/samourai.png
Normal file
BIN
src/main/resources/image/samourai.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
src/main/resources/image/samourai@2x.png
Normal file
BIN
src/main/resources/image/samourai@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
src/main/resources/image/samourai@3x.png
Normal file
BIN
src/main/resources/image/samourai@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
Loading…
Reference in a new issue