/* * * * Copyright 2014 http://Bither.net * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * */ package net.bither.utils; import net.bither.bitherj.api.http.Http400Exception; import net.bither.bitherj.core.AddressManager; import net.bither.bitherj.core.HDMAddress; import net.bither.bitherj.core.HDMBId; import net.bither.bitherj.core.HDMKeychain; import net.bither.bitherj.crypto.SecureCharSequence; import net.bither.bitherj.crypto.hd.DeterministicKey; import net.bither.bitherj.crypto.hd.HDKeyDerivation; import net.bither.bitherj.delegate.IPasswordGetterDelegate; import net.bither.bitherj.utils.Utils; import net.bither.qrcode.*; import net.bither.viewsystem.dialogs.DialogConfirmTask; import net.bither.viewsystem.dialogs.DialogProgress; import net.bither.viewsystem.froms.PasswordPanel; import javax.swing.*; import java.util.Arrays; import java.util.List; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class HDMKeychainRecoveryUtil implements IPasswordGetterDelegate { private DialogProgress dp; private ReentrantLock lock = new ReentrantLock(); private Condition coldRootCondition = lock.newCondition(); private Condition hdmIdCondiction = lock.newCondition(); private byte[] coldRoot; private HDMBId hdmBid; private String hdmBidSignature; public HDMKeychainRecoveryUtil(DialogProgress dp) { if (dp == null) { this.dp = new DialogProgress(); } else { this.dp = dp; } } public boolean canRecover() { return AddressManager.getInstance().getHdmKeychain() == null; } public String recovery() { if (AddressManager.getInstance().getHdmKeychain() != null) { throw new RuntimeException("Already has hdm keychain can not recover"); } PasswordPanel.PasswordGetter passwordGetter = new PasswordPanel.PasswordGetter( this); if (getColdRoot() == null) { return null; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { dp.pack(); dp.setVisible(true); } }); String preSign; try { preSign = getHDMIdPresign(); } catch (Exception e) { e.printStackTrace(); String msg = LocaliserUtils.getString("network_or_connection_error"); if (e instanceof Http400Exception) { msg = ExceptionUtil.getHDMHttpExceptionMessage(((Http400Exception) e) .getErrorCode()); } dismissDp(); return msg; } getHDMSignature(preSign); if (hdmBidSignature == null) { dismissDp(); return null; } SecureCharSequence password = passwordGetter.getPassword(); if (password == null) { dismissDp(); return null; } PeerUtil.stopPeer(); HDMKeychain.HDMKeychainRecover keychain; try { keychain = new HDMKeychain.HDMKeychainRecover(coldRoot, password, new HDMKeychain.HDMFetchRemoteAddresses() { @Override public List<HDMAddress.Pubs> getRemoteExistsPublicKeys(CharSequence password) { try { return hdmBid.recoverHDM(hdmBidSignature, password); } catch (Exception e) { e.printStackTrace(); } return null; } }); } catch (Exception e) { e.printStackTrace(); String msg = LocaliserUtils.getString("network_or_connection_error"); if (e instanceof Http400Exception) { msg = ExceptionUtil.getHDMHttpExceptionMessage(((Http400Exception) e) .getErrorCode()); } dismissDp(); return msg; } if (keychain.getAllCompletedAddresses().size() > 0) { KeyUtil.setHDKeyChain(keychain); PeerUtil.startPeer(); } else { PeerUtil.startPeer(); dismissDp(); return LocaliserUtils.getString("hdm_keychain_recovery_no_addresses"); } dismissDp(); return LocaliserUtils.getString("hdm_keychain_recovery_message"); } private void getHDMSignature(final String presign) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { dp.dispose(); HDMServerUnsignedQRCodePanel hdmServerUnsignedQRCodePanel = new HDMServerUnsignedQRCodePanel( new HDMServerUnsignedQRCodeListener() { @Override public void handleResult(String result, IReadQRCode readQRCode) { readQRCode.close(); setServerSignatureResult(result); } @Override public void scanSignedHDMServerQRCodeCancel() { try { lock.lock(); hdmIdCondiction.signal(); } finally { lock.unlock(); } } }, presign); hdmServerUnsignedQRCodePanel.showPanel(); } }); try { lock.lockInterruptibly(); hdmIdCondiction.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } private String getHDMIdPresign() throws Exception { initHDMBidFromColdRoot(); return hdmBid.getPreSignString(); } private void initHDMBidFromColdRoot() { if (hdmBid != null) { return; } DeterministicKey root = HDKeyDerivation.createMasterPubKeyFromExtendedBytes(Arrays.copyOf (coldRoot, coldRoot.length)); DeterministicKey key = root.deriveSoftened(0); String address = Utils.toAddress(key.getPubKeyHash()); root.wipe(); key.wipe(); hdmBid = new HDMBId(address); } private void setServerSignatureResult(String serverSignatureResult) { hdmBidSignature = serverSignatureResult; try { lock.lock(); hdmIdCondiction.signal(); } finally { lock.unlock(); } } public void setColdRoot(String coldRootString) { String result = coldRootString; coldRoot = Utils.hexStringToByteArray(result); try { lock.lock(); coldRootCondition.signal(); } finally { lock.unlock(); } } private byte[] getColdRoot() { if (coldRoot == null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { DialogConfirmTask dialogConfirmTask = new DialogConfirmTask(LocaliserUtils.getString("hdm_keychain_add_scan_cold"), new Runnable() { @Override public void run() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { } }); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { SelectTransportQRCodePanel selectTransportQRCodePanel = new SelectTransportQRCodePanel(new IScanQRCode() { @Override public void handleResult(String result, IReadQRCode readQRCode) { readQRCode.close(); setColdRoot(result); } }); selectTransportQRCodePanel.showPanel(); } }); } }, new Runnable() { @Override public void run() { coldRoot = null; try { lock.lock(); coldRootCondition.signal(); } finally { lock.unlock(); } } }); dialogConfirmTask.pack(); dialogConfirmTask.setVisible(true); } }); try { lock.lockInterruptibly(); coldRootCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } return coldRoot; } private void dismissDp() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { dp.dispose(); } }); } @Override public void beforePasswordDialogShow() { dp.dispose(); } @Override public void afterPasswordDialogDismiss() { dp.dispose(); } }