Commit 1eb10d94 authored by T Dev. D's avatar T Dev. D 😎
Browse files

Merge branch 'develop' of https://code.samourai.io/wallet/ExtLibJ into develop

parents 75b8b191 2500cac1
......@@ -8,6 +8,11 @@ public class HttpException extends Exception {
this.responseBody = responseBody;
}
public HttpException(String message, String responseBody) {
super(message);
this.responseBody = responseBody;
}
public String getResponseBody() {
return responseBody;
}
......
......@@ -12,8 +12,6 @@ import org.bitcoinj.crypto.MnemonicException;
*/
public class BIP47Wallet extends HD_Wallet {
private BIP47Account mAccount = null;
/**
* Constructor for wallet.
*
......@@ -25,11 +23,7 @@ public class BIP47Wallet extends HD_Wallet {
*
*/
public BIP47Wallet(int purpose, MnemonicCode mc, NetworkParameters params, byte[] seed, String passphrase) throws MnemonicException.MnemonicLengthException {
super(purpose, mc, params, seed, passphrase);
mAccount = new BIP47Account(params, mRoot, 0);
}
/**
......@@ -37,22 +31,7 @@ public class BIP47Wallet extends HD_Wallet {
* @param hdWallet
*/
public BIP47Wallet(HD_Wallet hdWallet) {
this(47, hdWallet);
}
/**
* Constructor for wallet.
*
* @param int purpose
* @param HD_Wallet hdWallet to copy from
*
*/
public BIP47Wallet(int purpose, HD_Wallet hdWallet) {
super(purpose, hdWallet);
mAccount = new BIP47Account(mParams, mRoot, 0);
super(47, hdWallet);
}
/**
......@@ -63,8 +42,9 @@ public class BIP47Wallet extends HD_Wallet {
* @return Account
*
*/
@Override
public BIP47Account getAccount(int accountId) {
return mAccount;
return new BIP47Account(mParams, mRoot, 0);
}
}
......@@ -38,7 +38,7 @@ public abstract class AbstractIndexHandler implements IIndexHandler {
@Override
public synchronized void confirmUnconfirmed(final int confirmed) {
if (confirmed >= get()) {
set(confirmed + 1);
set(confirmed + 1, false);
}
Iterator<Integer> it = unconfirmedIndexs.iterator();
......@@ -63,4 +63,14 @@ public abstract class AbstractIndexHandler implements IIndexHandler {
public synchronized void cancelUnconfirmed(int unconfirmed) {
unconfirmedIndexs.remove(unconfirmed);
}
@Override
public void set(int value, boolean allowDecrement) {
if (!allowDecrement && value <= get()) {
return; // deny decrement
}
set(value);
}
protected abstract void set(int value);
}
......@@ -7,7 +7,7 @@ public interface IIndexHandler {
int get();
void set(int value);
void set(int value, boolean allowDecrement);
int getAndIncrementUnconfirmed();
......
......@@ -25,7 +25,7 @@ public class MemoryIndexHandler extends AbstractIndexHandler {
}
@Override
public synchronized void set(int value) {
protected synchronized void set(int value) {
index = value;
}
}
......@@ -10,7 +10,10 @@ import org.bitcoinj.crypto.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class HD_Wallet {
private byte[] mSeed = null;
......@@ -21,6 +24,9 @@ public class HD_Wallet {
protected Map<Integer,HD_Account> mAccounts = null;
// contains xpub of #account0, or all xpubs from constructor
protected String[] xpubs = null;
protected NetworkParameters mParams = null;
private HD_Wallet() { ; }
......@@ -32,7 +38,8 @@ public class HD_Wallet {
this(purpose, mc.toMnemonic(mSeed), mParams, mSeed, strPassphrase);
}
protected HD_Wallet(int purpose, List<String> mWordList, NetworkParameters mParams, byte[] mSeed, String strPassphrase) {
// used by Sparrow
public HD_Wallet(int purpose, List<String> mWordList, NetworkParameters mParams, byte[] mSeed, String strPassphrase) {
this.mSeed = mSeed;
this.strPassphrase = strPassphrase;
this.mWordList = mWordList;
......@@ -41,9 +48,12 @@ public class HD_Wallet {
// compute rootKey for accounts
this.mRoot = computeRootKey(purpose, mWordList, strPassphrase, mParams);
// initialize accounts
// initialize mAccounts with account #0
mAccounts = new LinkedHashMap<>();
getAccount(0);
HD_Account hdAccount = getAccount(0);
// xpubs will only contain account #0 (even if mAccounts contains more accounts)
xpubs = new String[]{hdAccount.xpubstr()};
}
public HD_Wallet(int purpose, HD_Wallet inputWallet) {
......@@ -56,10 +66,13 @@ public class HD_Wallet {
public HD_Wallet(NetworkParameters params, String[] xpub) throws AddressFormatException {
mParams = params;
// initialize accounts
// initialize mAccounts and xpubs
mAccounts = new LinkedHashMap<>();
xpubs = new String[xpub.length];
for(int i = 0; i < xpub.length; i++) {
mAccounts.put(i, new HD_Account(mParams, xpub[i], i));
HD_Account account = new HD_Account(mParams, xpub[i], i);
mAccounts.put(i, account);
xpubs[i] = account.xpubstr();
}
}
......@@ -102,14 +115,7 @@ public class HD_Wallet {
}
public String[] getXPUBs() {
String[] ret = new String[mAccounts.size()];
for(int i = 0; i < mAccounts.size(); i++) {
ret[i] = mAccounts.get(i).xpubstr();
}
return ret;
return xpubs;
}
public byte[] getFingerprint() {
......
......@@ -9,6 +9,8 @@ import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.crypto.MnemonicCode;
import org.bitcoinj.crypto.MnemonicException;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
......@@ -31,8 +33,34 @@ public class HD_WalletFactoryGeneric {
this.mc = mc;
}
public HD_Wallet newWallet(String passphrase, NetworkParameters params) throws Exception {
return newWallet(12, passphrase, params);
}
public HD_Wallet newWallet(int nbWords, String passphrase, NetworkParameters params) throws IOException, MnemonicException.MnemonicLengthException {
if((nbWords % 3 != 0) || (nbWords < 12 || nbWords > 24)) {
nbWords = 12;
}
// len == 16 (12 words), len == 24 (18 words), len == 32 (24 words)
int len = (nbWords / 3) * 4;
if(passphrase == null) {
passphrase = "";
}
SecureRandom random = new SecureRandom();
byte seed[] = new byte[len];
random.nextBytes(seed);
HD_Wallet hdw = new HD_Wallet(44, mc, params, seed, passphrase);
return hdw;
}
public HD_Wallet restoreWallet(String data, String passphrase, NetworkParameters params)
throws AddressFormatException, DecoderException,
throws AddressFormatException, DecoderException,
MnemonicException.MnemonicLengthException, MnemonicException.MnemonicWordException,
MnemonicException.MnemonicChecksumException {
......
package com.samourai.wallet.payload;
import com.fasterxml.jackson.databind.JsonNode;
import com.samourai.wallet.api.pairing.PairingPayload;
import com.samourai.wallet.hd.HD_Wallet;
import com.samourai.wallet.hd.HD_WalletFactoryGeneric;
import com.samourai.wallet.util.FormatsUtilGeneric;
import com.samourai.wallet.util.JSONUtils;
import org.bitcoinj.core.NetworkParameters;
public class BackupPayload {
private JsonNode wallet;
private JsonNode meta;
public BackupPayload() {
this.wallet = null;
this.meta = null;
}
public static BackupPayload parse(String json) throws Exception {
return JSONUtils.getInstance().getObjectMapper().readValue(json, BackupPayload.class);
}
public boolean isWalletTestnet() {
if (wallet == null) {
return false;
}
if (wallet.get("testnet") == null) {
return false;
}
return wallet.get("testnet").booleanValue();
}
public NetworkParameters computeNetworkParameters() {
return FormatsUtilGeneric.getInstance().getNetworkParams(isWalletTestnet());
}
public String getWalletSeed() {
if (wallet == null) return null;
return wallet.get("seed").textValue();
}
public String getWalletPassphrase() {
if (wallet == null) return null;
return wallet.get("passphrase").textValue();
}
public HD_Wallet computeHdWallet() throws Exception {
byte[] seed = org.apache.commons.codec.binary.Hex.decodeHex(getWalletSeed().toCharArray());
String passphrase = getWalletPassphrase();
NetworkParameters params = computeNetworkParameters();
return HD_WalletFactoryGeneric.getInstance().getHD(44, seed, passphrase, params);
}
public PairingPayload.PairingDojo computePairingDojo() {
if (wallet == null) return null;
if (wallet.get("dojo") == null) return null;
JsonNode dojoPairingNode = wallet.get("dojo").get("pairing");
if (dojoPairingNode == null) return null;
String url = dojoPairingNode.get("url").textValue();
String apiKey = dojoPairingNode.get("apikey").textValue();
if (url == null || apiKey == null) return null;
PairingPayload.PairingDojo pairingDojo = new PairingPayload.PairingDojo(url, apiKey);
return pairingDojo;
}
public JsonNode getWallet() {
return wallet;
}
public void setWallet(JsonNode wallet) {
this.wallet = wallet;
}
public JsonNode getMeta() {
return meta;
}
public void setMeta(JsonNode meta) {
this.meta = meta;
}
}
package com.samourai.wallet.payload;
import com.samourai.wallet.crypto.AESUtil;
import com.samourai.wallet.util.CharSequenceX;
import org.json.JSONObject;
public class PayloadUtilGeneric {
private static PayloadUtilGeneric instance = null;
protected PayloadUtilGeneric() { ; }
public static PayloadUtilGeneric getInstance() {
if(instance == null) {
instance = new PayloadUtilGeneric();
}
return instance;
}
public boolean isBackupFile(String data) {
try {
JSONObject jsonObj = new JSONObject(data);
if (jsonObj != null && jsonObj.has("payload")) {
return true;
}
} catch (Exception e) {e.printStackTrace();}
return false;
}
public String decryptBackupFile(String backupFile, String passwordStr) throws Exception {
String encrypted = null;
int version = 1;
try {
JSONObject jsonObj = new JSONObject(backupFile);
if(jsonObj != null && jsonObj.has("payload")) {
encrypted = jsonObj.getString("payload");
}
if(jsonObj != null && jsonObj.has("version")) {
version = jsonObj.getInt("version");
}
}
catch(Exception e) {}
// not a json stream, assume v0
if(encrypted == null) {
encrypted = backupFile;
}
// decrypt
String decrypted = null;
if (passwordStr == null) {
decrypted = encrypted;
} else {
try {
CharSequenceX password = new CharSequenceX(passwordStr);
if (version == 1) {
decrypted = AESUtil.decrypt(encrypted, password, AESUtil.DefaultPBKDF2Iterations);
} else if (version == 2) {
decrypted = AESUtil.decryptSHA256(encrypted, password);
}
} catch (Exception e) {}
}
if (decrypted == null || decrypted.length() < 1) {
throw new Exception("Unable to decrypt");
}
return decrypted;
}
}
\ No newline at end of file
......@@ -38,7 +38,7 @@ public class CryptoTestUtil {
public BIP47Wallet generateBip47Wallet(NetworkParameters networkParameters) throws Exception {
HD_Wallet bip44Wallet = generateWallet(44, networkParameters);
BIP47Wallet bip47Wallet = new BIP47Wallet(47, bip44Wallet);
BIP47Wallet bip47Wallet = new BIP47Wallet(bip44Wallet);
return bip47Wallet;
}
......
......@@ -9,6 +9,7 @@ import org.bitcoinj.core.*;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDKeyDerivation;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.uri.BitcoinURI;
import org.bitcoinj.uri.BitcoinURIParseException;
import org.bouncycastle.util.Arrays;
......@@ -190,6 +191,10 @@ public class FormatsUtilGeneric {
return params != null && !(params instanceof MainNetParams);
}
public NetworkParameters getNetworkParams(boolean testnet) {
return testnet ? TestNet3Params.get() : MainNetParams.get();
}
public boolean isValidBitcoinAddress(final String address, NetworkParameters params) {
boolean ret = false;
......
......@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.samourai.code.wallet</groupId>
<artifactId>extlibj</artifactId>
<version>0.0.22</version>
<version>0.0.27-SNAPSHOT</version>
<name>extlibj</name>
<properties>
<maven.compiler.source>1.6</maven.compiler.source>
......@@ -208,6 +208,6 @@
<scm>
<connection>scm:git:git@code.samourai.io:wallet/ExtLibJ.git</connection>
<tag>0.0.22</tag>
<tag>0.0.26</tag>
</scm>
</project>
......@@ -20,7 +20,6 @@ public abstract class AbstractCahootsTest {
protected void verify(String expectedPayload, Cahoots cahoots) throws Exception {
String payloadStr = cleanPayload(cahoots).toJSONString();
log.info("### payload="+payloadStr);
Assertions.assertEquals(expectedPayload, payloadStr);
}
......
package com.samourai.wallet.hd;
import java.math.BigInteger;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.params.MainNetParams;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
public class HD_WalletFactoryGenericTest {
private static final Logger log = LoggerFactory.getLogger(HD_WalletFactoryGenericTest.class);
private HD_WalletFactoryGeneric hdWalletFactory = HD_WalletFactoryGeneric.getInstance();
@Test
......@@ -40,10 +44,7 @@ public class HD_WalletFactoryGenericTest {
@Test
public void computeSeedFromWords() throws Exception {
NetworkParameters params = MainNetParams.get();
HD_Wallet hdWallet;
byte[] mSeed;
String passphrase = "TREZOR";
// https://github.com/trezor/python-mnemonic/blob/master/vectors.json
......@@ -59,4 +60,27 @@ public class HD_WalletFactoryGenericTest {
mSeed = hdWalletFactory.computeSeedFromWords("void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold");
Assertions.assertEquals("f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", org.bouncycastle.util.encoders.Hex.toHexString(mSeed));
}
@Test
public void newWallet() throws Exception {
NetworkParameters params = MainNetParams.get();
String passphrase = "test";
HD_Wallet hdw1 = hdWalletFactory.newWallet(passphrase, params);
verifyNewWallet(hdw1, passphrase);
HD_Wallet hdw2 = hdWalletFactory.newWallet(passphrase, params);
verifyNewWallet(hdw2, passphrase);
Assertions.assertNotEquals(hdw1.getSeedHex(), hdw2.getSeedHex());
Assertions.assertNotEquals(hdw1.getMnemonic(), hdw2.getMnemonic());
}
private void verifyNewWallet(HD_Wallet hdw, String passphrase) {
if (log.isDebugEnabled()) {
log.debug("verifyNewWallet: "+hdw.getMnemonic());
}
Assertions.assertEquals(12, hdw.getMnemonic().split(" ").length);
Assertions.assertEquals(passphrase, hdw.getPassphrase());
}
}
......@@ -112,8 +112,19 @@ public class HD_WalletTest {
Assertions.assertEquals("bc1qhy6dh6c67q8uwshffrs2rjs85x4wyhx9k45rha", hdWallet2.getAddressAt(0, 0, 0).getAddressString(AddressType.SEGWIT_NATIVE));
}
@Test
public void testHdWalletMainnetXpub() throws Exception {
NetworkParameters params = MainNetParams.get();
HD_Wallet hdWallet1 = new HD_Wallet(params, new String[]{"xpub6By39V6HgpxbtuBVMpGDWPDFaBpMqEewX1KV45eXUZkvoV5TVgr9dvi5MkxtRrdovbngSAJtHR3mau3a2b9hmnTR9G7zjXozwqDBaHFPT5j"});
// verify
verifyWallet1Mainnet(hdWallet1);
}
private void verifyWallet1Mainnet(HD_Wallet hdWallet1) {
Assertions.assertArrayEquals(new String[]{"xpub6By39V6HgpxbtuBVMpGDWPDFaBpMqEewX1KV45eXUZkvoV5TVgr9dvi5MkxtRrdovbngSAJtHR3mau3a2b9hmnTR9G7zjXozwqDBaHFPT5j"}, hdWallet1.getXPUBs());
Assertions.assertEquals("xpub6By39V6HgpxbtuBVMpGDWPDFaBpMqEewX1KV45eXUZkvoV5TVgr9dvi5MkxtRrdovbngSAJtHR3mau3a2b9hmnTR9G7zjXozwqDBaHFPT5j", hdWallet1.getAccount(0).xpubstr());
Assertions.assertEquals("1C36vErfBHdZPnrB5vMh6fRxnZ3RfRr8eW", hdWallet1.getAccount(0).getChain(0).getAddressAt(0).getAddressString());
Assertions.assertEquals("19pAMZjGAy3C4uVREZKK959jhRynUJ6hhD", hdWallet1.getAccount(0).getChain(1).getAddressAt(0).getAddressString());
Assertions.assertEquals("1b1C6KHtjXb5Ln2UFMwxNpuZbuQsmdrGv", hdWallet1.getAccount(0).getChain(1).getAddressAt(1).getAddressString());
......
package com.samourai.wallet.payload;
import com.fasterxml.jackson.databind.JsonNode;
import com.samourai.wallet.api.pairing.PairingPayload;
import com.samourai.wallet.hd.HD_Wallet;
import com.samourai.wallet.util.FormatsUtilGeneric;
import org.bitcoinj.core.NetworkParameters;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BackupPayloadTest {
private static final Logger log = LoggerFactory.getLogger(BackupPayloadTest.class);
private String BACKUP_PAYLOAD = "{\"wallet\":{\"testnet\":false,\"seed\":\"e598320ab2d5c42f94b108ec0dece582\",\"passphrase\":\"test\",\"fingerprint\":\"77275290\",\"accounts\":[{\"xpub\":\"xpub6C2STbGiq9qvjhgfTyXhvHK2HQg4HFgqWcPBVJM82stnyfcLfLTvRKc5M5GCn7t1a5LgsCvvB9bUhQPoLZYFQjN4Wu8yV6y3ZbHtF3KyRXe\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"payment_code\":\"PM8TJbvQrAdpXquDjkh7MQ1ZbtTTXsMVri9ydDbHPWNwNFvuLJanbsqugjLU2CGG78ceHJgui3C94TH2xVBcm9itNvoFSFHV5jkF9z61UfsC5n59n2Xj\",\"payment_code_feature\":\"PM8TJbvQrAdpXquDjkh7MQ1ZbtTTXsMVri9ydDbHPWNwNFvuLJanbsqugjLU2CGG78ceHJgui3C94TH2xVBcm9itNvoFSFHV5jkF9z61UfsC5nDFt8o4\",\"bip49_accounts\":[{\"ypub\":\"ypub6WvxpidnzPZMy1S6udXxo6WT8dcd7MrQokJKeqE2HLQrbmVGfPzNoyyvtyJJFvxjxLtbFPQfVk8r5m872evxReLMJckqEg8SZum96pzzq7U\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"bip84_accounts\":[{\"zpub\":\"zpub6rKtc12pZ41ZY66Bajg7dPE8G6Gov5qSADMZc5uznJjLwQBX3zpLXPvqMjoTSnh3U4217VnxG7X2jNYJCS4T5QDsYWrLN9yA1eNw1ofrTsz\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"whirlpool_account\":[{\"zpub\":\"zpub6rKtc12xtiYXcPMowvBhoNV5XqXDdLAbBPWbTbPGTzzS1ehz94P2KFCKoyeHyUTMFhD5Bj4XevZwrRvBK39hG67SH4x3i5eauzZeQV1EwBw\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483645},{\"zpub\":\"zpub6rKtc12xtiYXei7YcAfs88sEB5A4adcAR4gVNfqHMiWdd2hXJSpnVmy65rPjZJRn5bxAkmpSfRzw8Kp4buKygSQAkhmH2uRGrvDsuFLAyiM\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483646},{\"zpub\":\"zpub6rKtc12xtiYXa9zjfimmeXHGeXektVaQDttRk5R3gzZwfeNaKTj3rCmnsMrJYsakr9rJ8fF2p6jbU7V3zxApyP6gc72Dh6ZLK9DjYfR3wsy\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483644}]},\"meta\":{\"version_name\":\"0.99.97a\",\"android_release\":\"10\",\"device_manufacturer\":\"Unihertz\",\"device_model\":\"Jelly2\",\"device_product\":\"Jelly2_EEA\",\"prev_balance\":0,\"sent_tos\":[],\"sent_tos_from_bip47\":[],\"batch_send\":[],\"use_segwit\":true,\"use_like_typed_change\":true,\"spend_type\":0,\"rbf_opt_in\":false,\"use_ricochet\":false,\"ricochet_staggered_delivery\":false,\"bip47\":{\"pcodes\":[],\"incoming_notif_hashes\":[]},\"pin\":\"00000\",\"pin2\":\"\",\"ricochet\":{\"xpub\":\"zpub6rKtc12xtiYXhEMfFySB7D762WjSyHZSXnXuz1Q6cordkRu5uabzSpuA5EaB2b8Q7UmvgFCMnCFSBDcjoZ6GfZFodmLdM75MK1dbE1LCeem\",\"index\":0,\"queue\":[],\"staggered\":[]},\"cahoots\":[],\"rbfs\":[],\"tor\":{\"active\":false},\"blocked_utxos\":{\"blocked\":[],\"notDusted\":[],\"notDustedPostMix\":[],\"blockedPostMix\":[],\"blockedBadBank\":[]},\"utxo_tags\":[],\"utxo_notes\":[],\"utxo_scores\":[],\"whirlpool\":{},\"tx0_display\":[],\"trusted_no\":\"\",\"scramble_pin\":true,\"haptic_pin\":true,\"auto_backup\":true,\"remote\":false,\"use_trusted\":false,\"check_sim\":false,\"broadcast_tx\":true,\"strict_outputs\":true,\"xpubreg44\":true,\"xpubreg49\":true,\"xpubreg84\":true,\"xpubprereg\":false,\"xpubpostreg\":false,\"xpubricochetreg\":false,\"xpublock44\":false,\"xpublock49\":false,\"xpublock84\":false,\"xpubprelock\":false,\"xpubpostlock\":false,\"xpubbadbanklock\":false,\"xpubricochetlock\":false,\"paynym_claimed\":false,\"paynym_refused\":true,\"paynym_featured_v1\":false,\"user_offline\":false,\"is_sat\":false,\"localIndexes\":{\"local44idx\":0,\"local49idx\":0,\"local84idx\":0},\"xpubpostxreg\":false}}";
@Test
public void decryptBackupFile() throws Exception {
BackupPayload backup = BackupPayload.parse(BACKUP_PAYLOAD);
HD_Wallet hdw = backup.computeHdWallet();
Assertions.assertFalse(backup.isWalletTestnet());
NetworkParameters params = backup.computeNetworkParameters();
Assertions.assertEquals(backup.isWalletTestnet(), FormatsUtilGeneric.getInstance().isTestNet(params));
Assertions.assertEquals("e598320ab2d5c42f94b108ec0dece582", backup.getWalletSeed());
Assertions.assertEquals(backup.getWalletSeed(), hdw.getSeedHex());
Assertions.assertEquals("test", backup.getWalletPassphrase());
Assertions.assertEquals(backup.getWalletPassphrase(), hdw.getPassphrase());
JsonNode wallet = backup.getWallet();
Assertions.assertEquals("{\"testnet\":false,\"seed\":\"e598320ab2d5c42f94b108ec0dece582\",\"passphrase\":\"test\",\"fingerprint\":\"77275290\",\"accounts\":[{\"xpub\":\"xpub6C2STbGiq9qvjhgfTyXhvHK2HQg4HFgqWcPBVJM82stnyfcLfLTvRKc5M5GCn7t1a5LgsCvvB9bUhQPoLZYFQjN4Wu8yV6y3ZbHtF3KyRXe\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"payment_code\":\"PM8TJbvQrAdpXquDjkh7MQ1ZbtTTXsMVri9ydDbHPWNwNFvuLJanbsqugjLU2CGG78ceHJgui3C94TH2xVBcm9itNvoFSFHV5jkF9z61UfsC5n59n2Xj\",\"payment_code_feature\":\"PM8TJbvQrAdpXquDjkh7MQ1ZbtTTXsMVri9ydDbHPWNwNFvuLJanbsqugjLU2CGG78ceHJgui3C94TH2xVBcm9itNvoFSFHV5jkF9z61UfsC5nDFt8o4\",\"bip49_accounts\":[{\"ypub\":\"ypub6WvxpidnzPZMy1S6udXxo6WT8dcd7MrQokJKeqE2HLQrbmVGfPzNoyyvtyJJFvxjxLtbFPQfVk8r5m872evxReLMJckqEg8SZum96pzzq7U\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"bip84_accounts\":[{\"zpub\":\"zpub6rKtc12pZ41ZY66Bajg7dPE8G6Gov5qSADMZc5uznJjLwQBX3zpLXPvqMjoTSnh3U4217VnxG7X2jNYJCS4T5QDsYWrLN9yA1eNw1ofrTsz\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"whirlpool_account\":[{\"zpub\":\"zpub6rKtc12xtiYXcPMowvBhoNV5XqXDdLAbBPWbTbPGTzzS1ehz94P2KFCKoyeHyUTMFhD5Bj4XevZwrRvBK39hG67SH4x3i5eauzZeQV1EwBw\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483645},{\"zpub\":\"zpub6rKtc12xtiYXei7YcAfs88sEB5A4adcAR4gVNfqHMiWdd2hXJSpnVmy65rPjZJRn5bxAkmpSfRzw8Kp4buKygSQAkhmH2uRGrvDsuFLAyiM\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483646},{\"zpub\":\"zpub6rKtc12xtiYXa9zjfimmeXHGeXektVaQDttRk5R3gzZwfeNaKTj3rCmnsMrJYsakr9rJ8fF2p6jbU7V3zxApyP6gc72Dh6ZLK9DjYfR3wsy\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483644}]}", wallet.toString());
JsonNode meta = backup.getMeta();
Assertions.assertEquals("{\"version_name\":\"0.99.97a\",\"android_release\":\"10\",\"device_manufacturer\":\"Unihertz\",\"device_model\":\"Jelly2\",\"device_product\":\"Jelly2_EEA\",\"prev_balance\":0,\"sent_tos\":[],\"sent_tos_from_bip47\":[],\"batch_send\":[],\"use_segwit\":true,\"use_like_typed_change\":true,\"spend_type\":0,\"rbf_opt_in\":false,\"use_ricochet\":false,\"ricochet_staggered_delivery\":false,\"bip47\":{\"pcodes\":[],\"incoming_notif_hashes\":[]},\"pin\":\"00000\",\"pin2\":\"\",\"ricochet\":{\"xpub\":\"zpub6rKtc12xtiYXhEMfFySB7D762WjSyHZSXnXuz1Q6cordkRu5uabzSpuA5EaB2b8Q7UmvgFCMnCFSBDcjoZ6GfZFodmLdM75MK1dbE1LCeem\",\"index\":0,\"queue\":[],\"staggered\":[]},\"cahoots\":[],\"rbfs\":[],\"tor\":{\"active\":false},\"blocked_utxos\":{\"blocked\":[],\"notDusted\":[],\"notDustedPostMix\":[],\"blockedPostMix\":[],\"blockedBadBank\":[]},\"utxo_tags\":[],\"utxo_notes\":[],\"utxo_scores\":[],\"whirlpool\":{},\"tx0_display\":[],\"trusted_no\":\"\",\"scramble_pin\":true,\"haptic_pin\":true,\"auto_backup\":true,\"remote\":false,\"use_trusted\":false,\"check_sim\":false,\"broadcast_tx\":true,\"strict_outputs\":true,\"xpubreg44\":true,\"xpubreg49\":true,\"xpubreg84\":true,\"xpubprereg\":false,\"xpubpostreg\":false,\"xpubricochetreg\":false,\"xpublock44\":false,\"xpublock49\":false,\"xpublock84\":false,\"xpubprelock\":false,\"xpubpostlock\":false,\"xpubbadbanklock\":false,\"xpubricochetlock\":false,\"paynym_claimed\":false,\"paynym_refused\":true,\"paynym_featured_v1\":false,\"user_offline\":false,\"is_sat\":false,\"localIndexes\":{\"local44idx\":0,\"local49idx\":0,\"local84idx\":0},\"xpubpostxreg\":false}", meta.toString());
PairingPayload.PairingDojo pairingDojo = backup.computePairingDojo();
Assertions.assertNull(pairingDojo);
}
}
package com.samourai.wallet.payload;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayloadUtilGenericTest {
private static final Logger log = LoggerFactory.getLogger(PayloadUtilGenericTest.class);
private PayloadUtilGeneric payloadUtil = PayloadUtilGeneric.getInstance();
private String BACKUP_FILE = "{\"version\":2,\"payload\":\"U2FsdGVkX1+vzNxPLqaOpV8Dv7OPnorGrFtAFcqJ+DLQofA2E5IwRU9ZaGw9TExs\\ndHI9PENEOhYq3YKWNH+Sly5ObFSNo8goCHmzpSjYP7za2psfhCI11+1brl4iDqAI\\nKjTSLqwZVSbDcKFAh5lOiSViUwnI+6Q\\/sUrRXYektaFq086Oj0hpr46yUoSy8PsI\\n38bdO0fkjhn5Pa+rE3INldporrdI4vXOJgmUyUJrh0faJNWWAn6AkQdHL0kEX\\/du\\nLat7YI\\/vzKWhlwx8z1i+DwelSyqQq7AyYuJfAmWmyKMyc6G0tNHczASXgzBk3isD\\nubAYguMR8fqBYsqGeWH+6ffRFiCrdCmos\\/uGyKN7KrgwyGGGXY2Bpp8AaEOnwSIY\\na0Ka+GicjPrkONGeHngDawgghLDb5pH9o\\/J052JmbDcHpt\\/Q+3PfzKnVOPTBZdT7\\nBj1jZGLs8fCDXKH+0f3NM3GWZbKZRA\\/fLi91U+pSopXkrcH7CAO2HiXzM1Q5rZFs\\nfgZBZ5GlzTy3ngSI3DHOwxanPeMTdyKFVRfTMlf0bVCC\\/glWXvoJG6emB71WTXh7\\nkTcEhb\\/+GT6YnL0Jq\\/LNjXh7\\/jhZsokYoA7lrVt6VaklA0BmAutRi5a67Ntcp2w6\\nGntx+uiaL5y9lyaTIiwjDLgaaK3Sp7gNYH78UyhvqxdDcSxTS2q4dxNfWjBXaV65\\n2zWtQuVDGL9CHFDO6b9jDvD5RpvPeHa9oQ1xc9csu0h2ozUT95plyR1nnSF5qH+U\\njQJMRe65K4\\/QtW2heBLcLHxy\\/s01unVEb29Jeo\\/Wjl8vbTIcxilALl2ulXwwZtAR\\nPLrFp3fObQ8NGo\\/\\/iuf0LcqxxfuKAr8oOZX4X6zfAivRrcwhLuY6WSng4+QBytOl\\nWtkajwf8cMsRND3xvX9KT6Q2kgAHIQZB8zowVJapHG56IOZHMw7xcLzmJdcGR8Vc\\nIksGkDaBKG7QYW3dUr\\/2DuMHMpsVugtttNweQyqULuviKYAjOtvQMP2mthzQ7eJ1\\nzizvEaHB+UaYIB2KTm9hy7kX9I+c6UmB+8ZxvKncaO3YzEvDqLq8TNqOpv1pK1BM\\nokXVY5TZwYD97D8HZiBdeVxV28T3tWIUfN+EeIwC095F0ith6Hn35nAgUftbE196\\nREpR3FInIMQzaAbXFsiXUpmWFmRU1EmnJGOQ9DxHxCai38dr1RZxii3fifS7TWs8\\nadbB7Gi9Bc3r79yNI2pxyUqj5HjSb0Vk7GOJH2VToivrjM+YSpdyYDnFZw\\/9Bzkj\\nbpLhHR8Y0ZSS9OQijQDuD4Veave+igdx6sf\\/BvdHkf3U0gaSCOCynhS9uLopz5wA\\nhylPGkvJRvsNa3+1OQQVLw9kFCjjh+2+sVeKOBOWNJ1ANKCgQ1AZtfb3aVEQSYAs\\nBAX+q1vI5O\\/rJ6zaWACJbUuwsk3HCg03y83Fv8bXTFM+4GW5XVBB7adpYUWFBERd\\nMBEPFrXwERUsQ\\/51eRr6csOwE9FfB9J+oJ4XyicmN5+KxiVO66CpgnqeNBP4asc1\\nOHdDTrKDHkzutAeMNBGlqmpCLdgtU37eh2NuKfFOleq9zgLPcoAlveD\\/x5uOm\\/5U\\nrfiXSlazSgz7kTVzvUZZQ\\/isrqVar2NN2RDiB+JO3xPeOMSzaKim+FlyUaUWuA2U\\nSxWYRtXQ4xmFsNOF1A3i8MlMI7apG96sLuFtbMe\\/eBxZk1ykW3svJnCjf8rIXpT5\\noUy\\/MnTxRApQBTeYnKTgxNu74Cqw\\/+kRwcStWlNtZwRgK1J8MXVQB+hkj6qzFY+7\\nqO53yLErZN0IzKxEvPSauA5oMkxsIB7aPbyoxzcOQERDMZ35ekwl\\/vx5fk3csk1k\\nxRavH26hz3iFiabKwH1OV+UyeT2ImdJMM9MSSkG8H5qzBxwTE9qUMblrnXphbIt1\\nW2gtwm1e\\/\\/gWKRqzQmSnjDPLaMWwN0G9KOzRTtmccC6pZHp0f2e2XJOJrNO9yCsw\\nK6SvV0JhMjDpnVyx500TtNUkaUiljNU2+Hfo8kOQeDZwnXDhymQQFKSpl5NONzZy\\nE0XT9Y4V3gWxArT4FnSEWC+\\/FBn6XJBimIc6q9\\/9exyMV2ENQ+8PUR+ouSZUfRNI\\njV08mBpSVovTFnR7UD1+bC3lAiLFXIEaxZIDgg6CpAmnDJkZQmTOKk9d1iNi89zN\\n1s5dM5LpahKF6cpmClUc9sx00rTUetG5083o8JWFn75EMdfmu6yIU\\/3Ijduu2Jne\\nXsw18KXv\\/YmPjiZ8gdDwOK21ypvr2zSeFAxOGGcJrFxEmRalWRz2xV3J6MJ5izLL\\nKihKbjJFD7BmX6RLyM9jviRY9CU5\\/uNck3tX80z1tMQ\\/MnYL3q7WzGjpOQBWujzb\\noUZW8AhGjWp4h547FND2jMJX5NZlpGs9cVgKzQBybnd0O2OJOJveZ6et9oi8niNe\\ncJT2V9cj7b9B2Z2fIbMaLILnBynnsJaYbCXO2IIV7CniQ6qyktX6Vb5Pgmc1MN1Z\\nKIp11aeXU87CG\\/I6y0FDVUKvfSxOUsMmW4Uo7RRx+xD5BuZiJBhEqpXIhiGu9+Dx\\nWc0EQgoA6jzMWIPSDZLbHoO6zP2x9LOfUXMaEQgp21bIXi0qYFjtSUsmjXKkFvZS\\nPQuYxrA61FSnSgjUZ591hk67yNAk\\/uzb3e0HFLAQhpev1tWJZiNUMMKOesWshHas\\nrxAYvtp3wNQPsZwAcWQM2K72EFtYLfOqpTLhkhkuhzEG5Oh5vGG\\/Jn+Y4r3oc7YT\\n9Xpt\\/Q9YOFXYZC0B82WJi56NznjjSxwqgbiB1SQw\\/+c87p\\/Qgv7ah+pz2J+jsUZ3\\nL7QlgPdofbQZk3ZXplHcSkAFdgwS1UWhiYOAAqvHIFUWeuOSg37cP4XLxSShC254\\nTRk7Mw\\/JNuSCgZ6aZryni48oGfbCbohPvr28dmG6f1xTbIgGV+MfHiUKLjg\\/eGn+\\nIgOGxIyylftAj2vagcNleXJ9JevdRofMF4dYCPTdnqZCTtGSO0dN1PVf5E6kBXZ6\\noeIxgVQfM8qeaPpXbut6g7edFP7kJtIEIBxtz5HQrsov4Qpzl3hCH1J5\\/WxJYQZw\\npfFv3BCF2PtTyeFhhPXM3jouAh46mHC6grku6dQ26HKgGn0EYhMNEkqQQ1vncIZD\\nP7GhkH\\/hHXB6VltiJVXpFjtxQMx\\/RJKWUqD6WMFoZ6pfe\\/cwjkSxTx5VZ4Jqfz\\/b\\nDbsUtzld65rMA1u8Is2w8Z30A93aYFbToD8CYeCkcQ\\/TIADdfw3BPpnwXi6we34C\\nJcC65brjf6k4vOVFtfLyVr3GHsjq\\/1HpMtEXRiaCNgKpaF59HwI2Z9bR\\/O6bic8C\\neKS2e6h70N0puGJvRdhb1feiWeT33oMZrcUfTpJ4s91L15zHtUd+vsv8500qSeyJ\\nJaJdJFDnRrY7+OhfkIC6GRpnot85Usi\\/CDznGEM21fklx36tQsElv9qeBbQ9MGGZ\\nNRZqjQDsmbq7AYnXrjHnR6L5eyAiRGYGKZnd+a2247QJ\\/t+SCpqQrh+eoDo6tthP\\n8LTIi+srBNjF+swcg3q75CDyN8\\/Ni1TWVlbdUbMfgRgdKzWEwatEYFbjW\\/U0CH2+\\nSnnkUQmz8ibshNra4RUZSjBeWzWPBwQBAFwCtGZRltG4MiWQnFekWHehZ9tpcj1s\\nHjCpr1yaY5PZxubQMlzUlQT60GLtMUOv7fE\\/cmDC9O7MWoFlBI2HkFhpTzEnEust\\nSg+L\\/91gL5RqKx2UwV5gNB1nBlDg4X++XSvblD64+Y3Jh4oEAFaIfzfR1xXgqb7B\\nC+VceZNmY6WH0L3apMC1t4L1ekPMnDUhzq8I0ir6npmwojtIc3+7bPgbzSevqQzs\\nXKIQp58vCMkL+kEuu\\/bvFT1fq+Do8OzHgzUbucs7WrZ1I8f+Oy+04IkA5Fi5iCqL\\n\",\"external\":false}";
private String BACKUP_PAYLOAD = "{\"wallet\":{\"testnet\":false,\"seed\":\"e598320ab2d5c42f94b108ec0dece582\",\"passphrase\":\"test\",\"fingerprint\":\"77275290\",\"accounts\":[{\"xpub\":\"xpub6C2STbGiq9qvjhgfTyXhvHK2HQg4HFgqWcPBVJM82stnyfcLfLTvRKc5M5GCn7t1a5LgsCvvB9bUhQPoLZYFQjN4Wu8yV6y3ZbHtF3KyRXe\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"payment_code\":\"PM8TJbvQrAdpXquDjkh7MQ1ZbtTTXsMVri9ydDbHPWNwNFvuLJanbsqugjLU2CGG78ceHJgui3C94TH2xVBcm9itNvoFSFHV5jkF9z61UfsC5n59n2Xj\",\"payment_code_feature\":\"PM8TJbvQrAdpXquDjkh7MQ1ZbtTTXsMVri9ydDbHPWNwNFvuLJanbsqugjLU2CGG78ceHJgui3C94TH2xVBcm9itNvoFSFHV5jkF9z61UfsC5nDFt8o4\",\"bip49_accounts\":[{\"ypub\":\"ypub6WvxpidnzPZMy1S6udXxo6WT8dcd7MrQokJKeqE2HLQrbmVGfPzNoyyvtyJJFvxjxLtbFPQfVk8r5m872evxReLMJckqEg8SZum96pzzq7U\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"bip84_accounts\":[{\"zpub\":\"zpub6rKtc12pZ41ZY66Bajg7dPE8G6Gov5qSADMZc5uznJjLwQBX3zpLXPvqMjoTSnh3U4217VnxG7X2jNYJCS4T5QDsYWrLN9yA1eNw1ofrTsz\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":0}],\"whirlpool_account\":[{\"zpub\":\"zpub6rKtc12xtiYXcPMowvBhoNV5XqXDdLAbBPWbTbPGTzzS1ehz94P2KFCKoyeHyUTMFhD5Bj4XevZwrRvBK39hG67SH4x3i5eauzZeQV1EwBw\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483645},{\"zpub\":\"zpub6rKtc12xtiYXei7YcAfs88sEB5A4adcAR4gVNfqHMiWdd2hXJSpnVmy65rPjZJRn5bxAkmpSfRzw8Kp4buKygSQAkhmH2uRGrvDsuFLAyiM\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483646},{\"zpub\":\"zpub6rKtc12xtiYXa9zjfimmeXHGeXektVaQDttRk5R3gzZwfeNaKTj3rCmnsMrJYsakr9rJ8fF2p6jbU7V3zxApyP6gc72Dh6ZLK9DjYfR3wsy\",\"receiveIdx\":0,\"changeIdx\":0,\"id\":2147483644}]},\"meta\":{\"version_name\":\"0.99.97a\",\"android_release\":\"10\",\"device_manufacturer\":\"Unihertz\",\"device_model\":\"Jelly2\",\"device_product\":\"Jelly2_EEA\",\"prev_balance\":0,\"sent_tos\":[],\"sent_tos_from_bip47\":[],\"batch_send\":[],\"use_segwit\":true,\"use_like_typed_change\":true,\"spend_type\":0,\"rbf_opt_in\":false,\"use_ricochet\":false,\"ricochet_staggered_delivery\":false,\"bip47\":{\"pcodes\":[],\"incoming_notif_hashes\":[]},\"pin\":\"00000\",\"pin2\":\"\",\"ricochet\":{\"xpub\":\"zpub6rKtc12xtiYXhEMfFySB7D762WjSyHZSXnXuz1Q6cordkRu5uabzSpuA5EaB2b8Q7UmvgFCMnCFSBDcjoZ6GfZFodmLdM75MK1dbE1LCeem\",\"index\":0,\"queue\":[],\"staggered\":[]},\"cahoots\":[],\"rbfs\":[],\"tor\":{\"active\":false},\"blocked_utxos\":{\"blocked\":[],\"notDusted\":[],\"notDustedPostMix\":[],\"blockedPostMix\":[],\"blockedBadBank\":[]},\"utxo_tags\":[],\"utxo_notes\":[],\"utxo_scores\":[],\"whirlpool\":{},\"tx0_display\":[],\"trusted_no\":\"\",\"scramble_pin\":true,\"haptic_pin\":true,\"auto_backup\":true,\"remote\":false,\"use_trusted\":false,\"check_sim\":false,\"broadcast_tx\":true,\"strict_outputs\":true,\"xpubreg44\":true,\"xpubreg49\":true,\"xpubreg84\":true,\"xpubprereg\":false,\"xpubpostreg\":false,\"xpubricochetreg\":false,\"xpublock44\":false,\"xpublock49\":false,\"xpublock84\":false,\"xpubprelock\":false,\"xpubpostlock\":false,\"xpubbadbanklock\":false,\"xpubricochetlock\":false,\"paynym_claimed\":false,\"paynym_refused\":true,\"paynym_featured_v1\":false,\"user_offline\":false,\"is_sat\":false,\"localIndexes\":{\"local44idx\":0,\"local49idx\":0,\"local84idx\":0},\"xpubpostxreg\":false}}";
@Test
public void isBackupFile() throws Exception {
Assertions.assertTrue(payloadUtil.isBackupFile(BACKUP_FILE));