Add DHT mailbox

This commit is contained in:
Manfred Karrer 2015-03-21 11:04:59 +01:00
parent 506ac37293
commit 239389b529
41 changed files with 680 additions and 391 deletions

View file

@ -69,7 +69,7 @@ public class BlockChainService {
} }
@SuppressWarnings("SameReturnValue") @SuppressWarnings("SameReturnValue")
private boolean isBankAccountBlacklisted(FiatAccount fiatAccount) { private boolean isFiatAccountBlacklisted(FiatAccount fiatAccount) {
// TODO check if accountID is on blacklist // TODO check if accountID is on blacklist
return false; return false;
} }

View file

@ -471,14 +471,14 @@ public class WalletService {
return tradeWalletService; return tradeWalletService;
} }
public void payRegistrationFee(String stringifiedBankAccounts, FutureCallback<Transaction> callback) throws public void payRegistrationFee(String stringifiedFiatAccounts, FutureCallback<Transaction> callback) throws
InsufficientMoneyException { InsufficientMoneyException {
log.debug("payRegistrationFee"); log.debug("payRegistrationFee");
log.trace("stringifiedBankAccounts " + stringifiedBankAccounts); log.trace("stringifiedFiatAccounts " + stringifiedFiatAccounts);
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
byte[] data = signatureService.digestMessageWithSignature(getRegistrationAddressEntry().getKeyPair(), stringifiedBankAccounts); byte[] data = signatureService.digestMessageWithSignature(getRegistrationAddressEntry().getKeyPair(), stringifiedFiatAccounts);
tx.addOutput(Transaction.MIN_NONDUST_OUTPUT, new ScriptBuilder().op(OP_RETURN).data(data).build()); tx.addOutput(Transaction.MIN_NONDUST_OUTPUT, new ScriptBuilder().op(OP_RETURN).data(data).build());
// We don't take a fee at the moment // We don't take a fee at the moment

View file

@ -0,0 +1,32 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.crypto;
import java.io.Serializable;
public class EncryptionPackage implements Serializable {
private static final long serialVersionUID = -8709538217388076762L;
public final byte[] encryptedKey;
public final byte[] encryptedPayload;
public EncryptionPackage(byte[] encryptedKey, byte[] encryptedPayload) {
this.encryptedKey = encryptedKey;
this.encryptedPayload = encryptedPayload;
}
}

View file

@ -19,11 +19,11 @@ package io.bitsquare.crypto;
import io.bitsquare.util.Utilities; import io.bitsquare.util.Utilities;
import java.io.Serializable; import java.security.InvalidKeyException;
import java.security.Key; import java.security.Key;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
@ -32,98 +32,82 @@ import javax.inject.Inject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator; import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
public class EncryptionService<T> { public class EncryptionService<T> {
private static final Logger log = LoggerFactory.getLogger(EncryptionService.class); private static final Logger log = LoggerFactory.getLogger(EncryptionService.class);
private static final String ALGO_SYM = "AES";
private static final String CIPHER_SYM = "AES";
private static final String ALGO_ASYM = "RSA";
private static final String CIPHER_ASYM = "RSA/ECB/PKCS1Padding";
private static final int KEY_SIZE_SYM = 128;
private static final int KEY_SIZE_ASYM = 1024;
@Inject @Inject
public EncryptionService() { public EncryptionService() {
} }
public KeyPair getKeyPair() { public KeyPair getKeyPair() throws NoSuchAlgorithmException {
KeyPair keyPair = null; KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGO_ASYM);
try { keyPairGenerator.initialize(KEY_SIZE_ASYM);
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); return keyPairGenerator.genKeyPair();
keyPairGenerator.initialize(1024);
keyPair = keyPairGenerator.genKeyPair();
} catch (Exception e) {
e.printStackTrace();
log.error("Exception at init " + e.getMessage());
}
return keyPair;
} }
public Tuple encryptObject(PublicKey publicKey, Object object) { public EncryptionPackage encryptObject(PublicKey publicKey, Object object) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException,
NoSuchAlgorithmException, NoSuchPaddingException {
return encrypt(publicKey, Utilities.objectToBytArray(object)); return encrypt(publicKey, Utilities.objectToBytArray(object));
} }
public T decryptToObject(PrivateKey privateKey, Tuple tuple) { public T decryptToObject(PrivateKey privateKey, EncryptionPackage encryptionPackage) throws IllegalBlockSizeException, InvalidKeyException,
return (T) Utilities.byteArrayToObject(decrypt(privateKey, tuple)); BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
return (T) Utilities.byteArrayToObject(decrypt(privateKey, encryptionPackage));
} }
public Tuple encrypt(PublicKey publicKey, byte[] payload) { public EncryptionPackage encrypt(PublicKey publicKey, byte[] payload) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
byte[] encryptedPayload = null; BadPaddingException, IllegalBlockSizeException {
byte[] encryptedKey = null; // Create symmetric key and
try { KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGO_SYM);
// Create symmetric key and keyGenerator.init(KEY_SIZE_SYM);
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); SecretKey secretKey = keyGenerator.generateKey();
keyGenerator.init(256);
SecretKey secretKey = keyGenerator.generateKey();
// Encrypt secretKey with asymmetric key // Encrypt secretKey with asymmetric key
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding"); Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey); cipherAsym.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedKey = cipher.doFinal(secretKey.getEncoded()); log.debug("encrypt secret key length: " + secretKey.getEncoded().length);
byte[] encryptedKey = cipherAsym.doFinal(secretKey.getEncoded());
// Encrypt payload with symmetric key // Encrypt payload with symmetric key
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), ALGO_SYM);
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec); cipherSym.init(Cipher.ENCRYPT_MODE, keySpec);
encryptedPayload = cipher.doFinal(payload); log.debug("encrypt payload length: " + payload.length);
} catch (Exception e) { byte[] encryptedPayload = cipherSym.doFinal(payload);
e.printStackTrace(); return new EncryptionPackage(encryptedKey, encryptedPayload);
log.error("Exception at encrypt " + e.getMessage());
}
return new Tuple(encryptedKey, encryptedPayload);
} }
public byte[] decrypt(PrivateKey privateKey, Tuple tuple) { public byte[] decrypt(PrivateKey privateKey, EncryptionPackage encryptionPackage) throws NoSuchPaddingException, NoSuchAlgorithmException,
byte[] encryptedPayload = tuple.encryptedPayload; InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] encryptedKey = tuple.encryptedKey; byte[] encryptedPayload = encryptionPackage.encryptedPayload;
byte[] encryptedKey = encryptionPackage.encryptedKey;
byte[] payload = null; // Decrypt secretKey key with asymmetric key
try { Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
// Decrypt secretKey key with asymmetric key cipherAsym.init(Cipher.DECRYPT_MODE, privateKey);
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding"); byte[] secretKey = cipherAsym.doFinal(encryptedKey);
cipher.init(Cipher.DECRYPT_MODE, privateKey); log.debug("decrypt secret key length: " + secretKey.length);
byte[] secretKey = cipher.doFinal(encryptedKey); // Decrypt payload with symmetric key
Key key = new SecretKeySpec(secretKey, ALGO_SYM);
// Decrypt payload with symmetric key Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
Key key = new SecretKeySpec(secretKey, "AES"); cipherSym.init(Cipher.DECRYPT_MODE, key);
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] payload = cipherSym.doFinal(encryptedPayload);
cipher.init(Cipher.DECRYPT_MODE, key); log.debug("decrypt payload length: " + payload.length);
payload = cipher.doFinal(encryptedPayload);
} catch (Exception e) {
e.printStackTrace();
log.error("Exception at decrypt " + e.getMessage());
}
return payload; return payload;
} }
public class Tuple implements Serializable {
private static final long serialVersionUID = -8709538217388076762L;
public final byte[] encryptedKey;
public final byte[] encryptedPayload;
public Tuple(byte[] encryptedKey, byte[] encryptedPayload) {
this.encryptedKey = encryptedKey;
this.encryptedPayload = encryptedPayload;
}
}
} }

View file

@ -154,7 +154,7 @@ class RestrictionsDataModel implements Activatable, DataModel {
private void addMockArbitrator() { private void addMockArbitrator() {
if (accountSettings.getAcceptedArbitrators().isEmpty() && user.getP2pSigKeyPair() != null) { if (accountSettings.getAcceptedArbitrators().isEmpty() && user.getP2pSigKeyPair() != null) {
byte[] pubKey = new ECKey().getPubKey(); byte[] pubKey = new ECKey().getPubKey();
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getP2PSigPubKey()); String p2pSigPubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getP2PSigPubKey());
List<Locale> languages = new ArrayList<>(); List<Locale> languages = new ArrayList<>();
languages.add(LanguageUtil.getDefaultLanguageLocale()); languages.add(LanguageUtil.getDefaultLanguageLocale());
List<Arbitrator.METHOD> arbitrationMethods = new ArrayList<>(); List<Arbitrator.METHOD> arbitrationMethods = new ArrayList<>();
@ -166,7 +166,7 @@ class RestrictionsDataModel implements Activatable, DataModel {
// TODO use very small sec. dposit to make testing in testnet less expensive // TODO use very small sec. dposit to make testing in testnet less expensive
// Revert later to 0.1 BTC again // Revert later to 0.1 BTC again
Arbitrator arbitrator = new Arbitrator(pubKey, Arbitrator arbitrator = new Arbitrator(pubKey,
messagePubKeyAsHex, p2pSigPubKeyAsHex,
"Manfred Karrer", "Manfred Karrer",
Arbitrator.ID_TYPE.REAL_LIFE_ID, Arbitrator.ID_TYPE.REAL_LIFE_ID,
languages, languages,

View file

@ -45,7 +45,7 @@ import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol; import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer; import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
@ -135,7 +135,7 @@ public class DebugView extends InitializableView {
ProcessDepositTxPublishedMessage.class, ProcessDepositTxPublishedMessage.class,
TakerCommitDepositTx.class, TakerCommitDepositTx.class,
ProcessBankTransferStartedMessage.class, ProcessFiatTransferStartedMessage.class,
SignAndPublishPayoutTx.class, SignAndPublishPayoutTx.class,
VerifyOfferFeePayment.class, VerifyOfferFeePayment.class,

View file

@ -74,7 +74,7 @@ class ClosedTradesDataModel implements Activatable, DataModel {
} }
public Direction getDirection(Offer offer) { public Direction getDirection(Offer offer) {
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ? return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
offer.getDirection() : offer.getMirroredDirection(); offer.getDirection() : offer.getMirroredDirection();
} }

View file

@ -86,7 +86,7 @@ class OffersDataModel implements Activatable, DataModel {
} }
public Direction getDirection(Offer offer) { public Direction getDirection(Offer offer) {
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ? return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
offer.getDirection() : offer.getMirroredDirection(); offer.getDirection() : offer.getMirroredDirection();
} }
} }

View file

@ -146,7 +146,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
selectedItem = item; selectedItem = item;
if (selectedItem != null) { if (selectedItem != null) {
isOfferer = getTrade().getOffer().getMessagePublicKey().equals(user.getP2PSigPubKey()); isOfferer = getTrade().getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey());
Trade trade = getTrade(); Trade trade = getTrade();
trade.stateProperty().addListener(tradeStateChangeListener); trade.stateProperty().addListener(tradeStateChangeListener);
@ -172,7 +172,6 @@ class PendingTradesDataModel implements Activatable, DataModel {
} }
void fiatPaymentStarted() { void fiatPaymentStarted() {
getTrade().setState(Trade.State.FIAT_PAYMENT_STARTED);
tradeManager.onFiatPaymentStarted(getTrade().getId()); tradeManager.onFiatPaymentStarted(getTrade().getId());
} }
@ -209,7 +208,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
log.error(e.getMessage()); log.error(e.getMessage());
} }
tradeManager.closeTrade(getTrade()); tradeManager.onWithdrawAtTradeCompleted(getTrade());
/* /*
Action response = Popups.openConfirmPopup( Action response = Popups.openConfirmPopup(
@ -269,7 +268,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
} }
public Direction getDirection(Offer offer) { public Direction getDirection(Offer offer) {
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ? return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
offer.getDirection() : offer.getMirroredDirection(); offer.getDirection() : offer.getMirroredDirection();
} }

View file

@ -213,7 +213,7 @@ class OfferBookDataModel implements Activatable, DataModel {
} }
boolean isMyOffer(Offer offer) { boolean isMyOffer(Offer offer) {
return offer.getMessagePublicKey() != null && offer.getMessagePublicKey().equals(user.getP2PSigPubKey()); return offer.getP2PSigPubKey() != null && offer.getP2PSigPubKey().equals(user.getP2PSigPubKey());
} }
Coin getAmountAsCoin() { Coin getAmountAsCoin() {

View file

@ -97,7 +97,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
@Override @Override
public void deactivate() { public void deactivate() {
btcCode.unbind(); btcCode.unbind();
tradeManager.cancelGetOfferAvailableStateRequest(offer); tradeManager.cancelCheckOfferAvailabilityRequest(offer);
} }
void initWithData(Coin amount, Offer offer) { void initWithData(Coin amount, Offer offer) {

View file

@ -70,7 +70,7 @@ public class Offer implements Serializable {
private final Coin amount; private final Coin amount;
private final Coin minAmount; private final Coin minAmount;
//TODO use hex string //TODO use hex string
private final PublicKey messagePublicKey; private final PublicKey p2pSigPubKey;
private final FiatAccountType fiatAccountType; private final FiatAccountType fiatAccountType;
private final Country bankAccountCountry; private final Country bankAccountCountry;
@ -94,7 +94,7 @@ public class Offer implements Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public Offer(String id, public Offer(String id,
PublicKey messagePublicKey, PublicKey p2pSigPubKey,
Direction direction, Direction direction,
long fiatPrice, long fiatPrice,
Coin amount, Coin amount,
@ -108,7 +108,7 @@ public class Offer implements Serializable {
List<Country> acceptedCountries, List<Country> acceptedCountries,
List<Locale> acceptedLanguageLocales) { List<Locale> acceptedLanguageLocales) {
this.id = id; this.id = id;
this.messagePublicKey = messagePublicKey; this.p2pSigPubKey = p2pSigPubKey;
this.direction = direction; this.direction = direction;
this.fiatPrice = fiatPrice; this.fiatPrice = fiatPrice;
this.amount = amount; this.amount = amount;
@ -221,8 +221,8 @@ public class Offer implements Serializable {
return bankAccountUID; return bankAccountUID;
} }
public PublicKey getMessagePublicKey() { public PublicKey getP2PSigPubKey() {
return messagePublicKey; return p2pSigPubKey;
} }
public Date getCreationDate() { public Date getCreationDate() {
@ -250,7 +250,7 @@ public class Offer implements Serializable {
checkNotNull(getCurrency(), "Currency is null"); checkNotNull(getCurrency(), "Currency is null");
checkNotNull(getDirection(), "Direction is null"); checkNotNull(getDirection(), "Direction is null");
checkNotNull(getId(), "Id is null"); checkNotNull(getId(), "Id is null");
checkNotNull(getMessagePublicKey(), "MessagePublicKey is null"); checkNotNull(getP2PSigPubKey(), "p2pSigPubKey is null");
checkNotNull(getMinAmount(), "MinAmount is null"); checkNotNull(getMinAmount(), "MinAmount is null");
checkNotNull(getPrice(), "Price is null"); checkNotNull(getPrice(), "Price is null");
@ -277,7 +277,7 @@ public class Offer implements Serializable {
", fiatPrice=" + fiatPrice + ", fiatPrice=" + fiatPrice +
", amount=" + amount + ", amount=" + amount +
", minAmount=" + minAmount + ", minAmount=" + minAmount +
", messagePublicKey=" + messagePublicKey + ", p2pSigPubKey=" + p2pSigPubKey +
", fiatAccountType=" + fiatAccountType + ", fiatAccountType=" + fiatAccountType +
", bankAccountCountry=" + bankAccountCountry + ", bankAccountCountry=" + bankAccountCountry +
", securityDeposit=" + securityDeposit + ", securityDeposit=" + securityDeposit +

View file

@ -23,5 +23,5 @@ import io.bitsquare.p2p.listener.GetPeerAddressListener;
import java.security.PublicKey; import java.security.PublicKey;
public interface AddressService extends DHTService{ public interface AddressService extends DHTService{
void findPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener); void findPeerAddress(PublicKey p2pSigPubKey, GetPeerAddressListener getPeerAddressListener);
} }

View file

@ -17,7 +17,7 @@
package io.bitsquare.p2p; package io.bitsquare.p2p;
import io.bitsquare.crypto.EncryptionService; import io.bitsquare.crypto.EncryptionPackage;
import java.io.Serializable; import java.io.Serializable;
@ -31,13 +31,13 @@ public class EncryptedMailboxMessage implements MailboxMessage, Serializable {
private static final long serialVersionUID = -3111178895546299769L; private static final long serialVersionUID = -3111178895546299769L;
private static final Logger log = LoggerFactory.getLogger(EncryptedMailboxMessage.class); private static final Logger log = LoggerFactory.getLogger(EncryptedMailboxMessage.class);
private EncryptionService.Tuple tuple; private EncryptionPackage encryptionPackage;
public EncryptedMailboxMessage(EncryptionService.Tuple tuple) { public EncryptedMailboxMessage(EncryptionPackage encryptionPackage) {
this.tuple = tuple; this.encryptionPackage = encryptionPackage;
} }
public EncryptionService.Tuple getTuple() { public EncryptionPackage getEncryptionPackage() {
return tuple; return encryptionPackage;
} }
} }

View file

@ -0,0 +1,24 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.p2p;
import java.util.List;
public interface MailboxMessagesResultHandler {
void handleResult(List<EncryptedMailboxMessage> messages);
}

View file

@ -19,14 +19,14 @@ package io.bitsquare.p2p;
import io.bitsquare.common.handlers.FaultHandler; import io.bitsquare.common.handlers.FaultHandler;
import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.p2p.tomp2p.TomP2PMailboxService;
import java.security.PublicKey; import java.security.PublicKey;
public interface MailboxService { public interface MailboxService {
void addMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler); void addMessage(PublicKey p2pSigPubKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler);
void getAllMessages(PublicKey p2pSigPubKey, MailboxMessagesResultHandler resultHandler);
void removeMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler); void removeAllMessages(PublicKey p2pSigPubKey, ResultHandler resultHandler, FaultHandler faultHandler);
void getMessages(PublicKey publicKey, TomP2PMailboxService.MailboxMessagesResultHandler resultHandler);
} }

View file

@ -20,10 +20,14 @@ package io.bitsquare.p2p;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import java.security.PublicKey;
public interface MessageService extends P2PService { public interface MessageService extends P2PService {
void sendMessage(Peer peer, Message message, SendMessageListener listener); void sendMessage(Peer peer, Message message, SendMessageListener listener);
void sendMessage(Peer peer, Message message, PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey, SendMessageListener listener);
void addMessageHandler(MessageHandler listener); void addMessageHandler(MessageHandler listener);
void removeMessageHandler(MessageHandler listener); void removeMessageHandler(MessageHandler listener);

View file

@ -91,9 +91,9 @@ public class TomP2PAddressService extends TomP2PDHTService implements AddressSer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
public void findPeerAddress(PublicKey publicKey, GetPeerAddressListener listener) { public void findPeerAddress(PublicKey p2pSigPubKey, GetPeerAddressListener listener) {
final Number160 locationKey = Utils.makeSHAHash(publicKey.getEncoded()); final Number160 locationKey = Utils.makeSHAHash(p2pSigPubKey.getEncoded());
FutureGet futureGet = getDataOfProtectedDomain(locationKey, publicKey); FutureGet futureGet = getDataOfProtectedDomain(locationKey, p2pSigPubKey);
log.trace("findPeerAddress called"); log.trace("findPeerAddress called");
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() { futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
@Override @Override

View file

@ -247,6 +247,18 @@ public class TomP2PDHTService extends TomP2PService implements DHTService {
log.trace("getDataFromMapOfMyProtectedDomain"); log.trace("getDataFromMapOfMyProtectedDomain");
return peerDHT.get(locationKey).all().domainKey(pubKeyHashForMyDomain).start(); return peerDHT.get(locationKey).all().domainKey(pubKeyHashForMyDomain).start();
} }
/**
* Remove all data from map for given locationKey.
* Access: Only the domain owner.
*
* @param locationKey
* @return
*/
public FutureRemove removeAllDataFromMapOfMyProtectedDomain(Number160 locationKey) {
log.trace("getDataFromMapOfMyProtectedDomain");
return peerDHT.remove(locationKey).domainKey(pubKeyHashForMyDomain).keyPair(keyPair).all().domainKey(pubKeyHashForMyDomain).keyPair(keyPair).start();
}
} }

View file

@ -21,6 +21,7 @@ import io.bitsquare.common.handlers.FaultHandler;
import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.offer.OfferBookService; import io.bitsquare.offer.OfferBookService;
import io.bitsquare.p2p.EncryptedMailboxMessage; import io.bitsquare.p2p.EncryptedMailboxMessage;
import io.bitsquare.p2p.MailboxMessagesResultHandler;
import io.bitsquare.p2p.MailboxService; import io.bitsquare.p2p.MailboxService;
import io.bitsquare.user.User; import io.bitsquare.user.User;
@ -49,7 +50,7 @@ import org.slf4j.LoggerFactory;
public class TomP2PMailboxService extends TomP2PDHTService implements MailboxService { public class TomP2PMailboxService extends TomP2PDHTService implements MailboxService {
private static final Logger log = LoggerFactory.getLogger(TomP2PMailboxService.class); private static final Logger log = LoggerFactory.getLogger(TomP2PMailboxService.class);
private static final int TTL = 15 * 24 * 60 * 60; // the message is default 15 days valid, as a max trade period might be about 2 weeks. private static final int TTL = 21 * 24 * 60 * 60; // the message is default 21 days valid, as a max trade period might be about 2 weeks.
private final List<OfferBookService.Listener> offerRepositoryListeners = new ArrayList<>(); private final List<OfferBookService.Listener> offerRepositoryListeners = new ArrayList<>();
@ -69,14 +70,14 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
} }
@Override @Override
public void addMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) { public void addMessage(PublicKey p2pSigPubKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) {
try { try {
final Data data = new Data(message); final Data data = new Data(message);
data.ttlSeconds(TTL); data.ttlSeconds(TTL);
log.trace("Add message to DHT requested. Added data: [locationKey: " + getLocationKey(publicKey) + log.trace("Add message to DHT requested. Added data: [locationKey: " + getLocationKey(p2pSigPubKey) +
", hash: " + data.hash().toString() + "]"); ", hash: " + data.hash().toString() + "]");
FuturePut futurePut = addDataToMapOfProtectedDomain(getLocationKey(publicKey), data, publicKey); FuturePut futurePut = addDataToMapOfProtectedDomain(getLocationKey(p2pSigPubKey), data, p2pSigPubKey);
futurePut.addListener(new BaseFutureListener<BaseFuture>() { futurePut.addListener(new BaseFutureListener<BaseFuture>() {
@Override @Override
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
@ -84,7 +85,7 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
executor.execute(() -> { executor.execute(() -> {
resultHandler.handleResult(); resultHandler.handleResult();
log.trace("Add message to mailbox was successful. Added data: [locationKey: " + getLocationKey(publicKey) + log.trace("Add message to mailbox was successful. Added data: [locationKey: " + getLocationKey(p2pSigPubKey) +
", value: " + data + "]"); ", value: " + data + "]");
}); });
} }
@ -101,41 +102,9 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
} }
@Override @Override
public void removeMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) { public void getAllMessages(PublicKey p2pSigPubKey, MailboxMessagesResultHandler resultHandler) {
try { log.trace("Get messages from DHT requested for locationKey: " + getLocationKey(p2pSigPubKey));
final Data data = new Data(message); FutureGet futureGet = getDataFromMapOfMyProtectedDomain(getLocationKey(p2pSigPubKey));
log.trace("Remove message from DHT requested. Removed data: [locationKey: " + getLocationKey(publicKey) +
", hash: " + data.hash().toString() + "]");
FutureRemove futureRemove = removeDataFromMapOfMyProtectedDomain(getLocationKey(publicKey), data);
futureRemove.addListener(new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
// We don't test futureRemove.isSuccess() as this API does not fit well to that operation,
// it might change in future to something like foundAndRemoved and notFound
// See discussion at: https://github.com/tomp2p/TomP2P/issues/57#issuecomment-62069840
log.trace("isRemoved? " + futureRemove.isRemoved());
executor.execute(() -> {
resultHandler.handleResult();
});
}
@Override
public void exceptionCaught(Throwable t) throws Exception {
log.error("Remove message from DHT failed. Error: " + t.getMessage());
faultHandler.handleFault("Remove message from DHT failed. Error: " + t.getMessage(), t);
}
});
} catch (IOException e) {
e.printStackTrace();
log.error("Remove message from DHT failed. Error: " + e.getMessage());
faultHandler.handleFault("Remove message from DHT failed. Error: " + e.getMessage(), e);
}
}
@Override
public void getMessages(PublicKey publicKey, MailboxMessagesResultHandler resultHandler) {
log.trace("Get messages from DHT requested for locationKey: " + getLocationKey(publicKey));
FutureGet futureGet = getDataFromMapOfMyProtectedDomain(getLocationKey(publicKey));
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() { futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
@Override @Override
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
@ -156,7 +125,7 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
executor.execute(() -> resultHandler.handleResult(messages)); executor.execute(() -> resultHandler.handleResult(messages));
} }
log.trace("Get messages from DHT was successful. Stored data: [key: " + getLocationKey(publicKey) log.trace("Get messages from DHT was successful. Stored data: [key: " + getLocationKey(p2pSigPubKey)
+ ", values: " + futureGet.dataMap() + "]"); + ", values: " + futureGet.dataMap() + "]");
} }
else { else {
@ -173,16 +142,32 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
}); });
} }
@Override
public void removeAllMessages(PublicKey p2pSigPubKey, ResultHandler resultHandler, FaultHandler faultHandler) {
log.trace("Remove all messages from DHT requested. locationKey: " + getLocationKey(p2pSigPubKey));
FutureRemove futureRemove = removeAllDataFromMapOfMyProtectedDomain(getLocationKey(p2pSigPubKey));
futureRemove.addListener(new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
// We don't test futureRemove.isSuccess() as this API does not fit well to that operation,
// it might change in future to something like foundAndRemoved and notFound
// See discussion at: https://github.com/tomp2p/TomP2P/issues/57#issuecomment-62069840
log.trace("isRemoved? " + futureRemove.isRemoved());
executor.execute(() -> {
resultHandler.handleResult();
});
}
/////////////////////////////////////////////////////////////////////////////////////////// @Override
// Private public void exceptionCaught(Throwable t) throws Exception {
/////////////////////////////////////////////////////////////////////////////////////////// log.error("Remove all messages from DHT failed. Error: " + t.getMessage());
faultHandler.handleFault("Remove all messages from DHT failed. Error: " + t.getMessage(), t);
private Number160 getLocationKey(PublicKey publicKey) { }
return Number160.createHash("mailbox" + publicKey.hashCode()); });
} }
public interface MailboxMessagesResultHandler {
void handleResult(List<EncryptedMailboxMessage> messages); private Number160 getLocationKey(PublicKey p2pSigPubKey) {
return Number160.createHash("mailbox" + p2pSigPubKey.hashCode());
} }
} }

View file

@ -17,6 +17,7 @@
package io.bitsquare.p2p.tomp2p; package io.bitsquare.p2p.tomp2p;
import io.bitsquare.crypto.EncryptionPackage;
import io.bitsquare.crypto.EncryptionService; import io.bitsquare.crypto.EncryptionService;
import io.bitsquare.p2p.EncryptedMailboxMessage; import io.bitsquare.p2p.EncryptedMailboxMessage;
import io.bitsquare.p2p.MailboxMessage; import io.bitsquare.p2p.MailboxMessage;
@ -28,6 +29,8 @@ import io.bitsquare.p2p.Peer;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import java.security.PublicKey;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Inject; import javax.inject.Inject;
@ -53,7 +56,7 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public TomP2PMessageService(TomP2PNode tomP2PNode, MailboxService mailboxService, User user, EncryptionService encryptionService) { public TomP2PMessageService(TomP2PNode tomP2PNode, MailboxService mailboxService, User user, EncryptionService<MailboxMessage> encryptionService) {
super(tomP2PNode); super(tomP2PNode);
this.mailboxService = mailboxService; this.mailboxService = mailboxService;
this.user = user; this.user = user;
@ -74,6 +77,12 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
@Override @Override
public void sendMessage(Peer peer, Message message, SendMessageListener listener) { public void sendMessage(Peer peer, Message message, SendMessageListener listener) {
sendMessage(peer, message, null, null, listener);
}
@Override
public void sendMessage(Peer peer, Message message, PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey,
SendMessageListener listener) {
if (!(peer instanceof TomP2PPeer)) if (!(peer instanceof TomP2PPeer))
throw new IllegalArgumentException("Peer must be of type TomP2PPeer"); throw new IllegalArgumentException("Peer must be of type TomP2PPeer");
@ -86,8 +95,9 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
executor.execute(listener::handleResult); executor.execute(listener::handleResult);
} }
else { else {
if (message instanceof MailboxMessage) { if (p2pSigPubKey != null && p2pEncryptPubKey != null) {
sendMailboxMessage((MailboxMessage) message, listener); log.info("sendMessage failed. We will try to send the message to the mailbox. Fault reason: " + futureDirect.failedReason());
sendMailboxMessage(p2pSigPubKey, p2pEncryptPubKey, (MailboxMessage) message, listener);
} }
else { else {
log.error("sendMessage failed with reason " + futureDirect.failedReason()); log.error("sendMessage failed with reason " + futureDirect.failedReason());
@ -98,8 +108,9 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
if (message instanceof MailboxMessage) { if (p2pSigPubKey != null && p2pEncryptPubKey != null) {
sendMailboxMessage((MailboxMessage) message, listener); log.info("sendMessage failed with exception. We will try to send the message to the mailbox. Exception: " + t.getMessage());
sendMailboxMessage(p2pSigPubKey, p2pEncryptPubKey, (MailboxMessage) message, listener);
} }
else { else {
log.error("sendMessage failed with exception " + t.getMessage()); log.error("sendMessage failed with exception " + t.getMessage());
@ -109,11 +120,18 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
}); });
} }
private void sendMailboxMessage(MailboxMessage message, SendMessageListener listener) { private void sendMailboxMessage(PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey, MailboxMessage message, SendMessageListener listener) {
EncryptionService.Tuple tuple = encryptionService.encryptObject(user.getP2pEncryptKeyPair().getPublic(), message); EncryptionPackage encryptionPackage = null;
try {
EncryptedMailboxMessage encrypted = new EncryptedMailboxMessage(tuple); encryptionPackage = encryptionService.encryptObject(p2pEncryptPubKey, message);
mailboxService.addMessage(user.getP2PSigPubKey(), encrypted, } catch (Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
executor.execute(listener::handleFault);
}
EncryptedMailboxMessage encrypted = new EncryptedMailboxMessage(encryptionPackage);
mailboxService.addMessage(p2pSigPubKey,
encrypted,
() -> { () -> {
log.debug("Message successfully added to peers mailbox."); log.debug("Message successfully added to peers mailbox.");
executor.execute(listener::handleResult); executor.execute(listener::handleResult);

View file

@ -40,8 +40,8 @@ public class Contract implements Serializable {
private final String takerAccountID; private final String takerAccountID;
private final FiatAccount offererFiatAccount; private final FiatAccount offererFiatAccount;
private final FiatAccount takerFiatAccount; private final FiatAccount takerFiatAccount;
private final String offererMessagePublicKeyAsString; private final String offererP2PSigPubKeyAsString;
private final String takerMessagePublicKeyAsString; private final String takerP2PSigPubKeyAsString;
public Contract(Offer offer, public Contract(Offer offer,
Coin tradeAmount, Coin tradeAmount,
@ -50,8 +50,8 @@ public class Contract implements Serializable {
String takerAccountID, String takerAccountID,
FiatAccount offererFiatAccount, FiatAccount offererFiatAccount,
FiatAccount takerFiatAccount, FiatAccount takerFiatAccount,
PublicKey offererMessagePublicKey, PublicKey offererP2PSigPubKey,
PublicKey takerMessagePublicKey) { PublicKey takerP2PSigPubKey) {
this.offer = offer; this.offer = offer;
this.tradeAmount = tradeAmount; this.tradeAmount = tradeAmount;
this.takeOfferFeeTxID = takeOfferFeeTxID; this.takeOfferFeeTxID = takeOfferFeeTxID;
@ -59,8 +59,8 @@ public class Contract implements Serializable {
this.takerAccountID = takerAccountID; this.takerAccountID = takerAccountID;
this.offererFiatAccount = offererFiatAccount; this.offererFiatAccount = offererFiatAccount;
this.takerFiatAccount = takerFiatAccount; this.takerFiatAccount = takerFiatAccount;
this.offererMessagePublicKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(offererMessagePublicKey); this.offererP2PSigPubKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(offererP2PSigPubKey);
this.takerMessagePublicKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(takerMessagePublicKey); this.takerP2PSigPubKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(takerP2PSigPubKey);
} }
@ -97,11 +97,11 @@ public class Contract implements Serializable {
} }
public String getTakerMessagePublicKey() { public String getTakerMessagePublicKey() {
return takerMessagePublicKeyAsString; return takerP2PSigPubKeyAsString;
} }
public String getOffererMessagePublicKey() { public String getOffererMessagePublicKey() {
return offererMessagePublicKeyAsString; return offererP2PSigPubKeyAsString;
} }
@Override @Override
@ -114,8 +114,8 @@ public class Contract implements Serializable {
", takerAccountID='" + takerAccountID + '\'' + ", takerAccountID='" + takerAccountID + '\'' +
", offererBankAccount=" + offererFiatAccount + ", offererBankAccount=" + offererFiatAccount +
", takerBankAccount=" + takerFiatAccount + ", takerBankAccount=" + takerFiatAccount +
", takerMessagePublicKeyAsString=" + takerMessagePublicKeyAsString + ", takerP2PSigPubKeyAsString=" + takerP2PSigPubKeyAsString +
", offererMessagePublicKeyAsString=" + offererMessagePublicKeyAsString + ", offererP2PSigPubKeyAsString=" + offererP2PSigPubKeyAsString +
'}'; '}';
} }
} }

View file

@ -21,12 +21,15 @@ import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.common.handlers.ErrorMessageHandler; import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.crypto.EncryptionService;
import io.bitsquare.crypto.SignatureService; import io.bitsquare.crypto.SignatureService;
import io.bitsquare.fiat.FiatAccount; import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.offer.Direction; import io.bitsquare.offer.Direction;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.offer.OfferBookService; import io.bitsquare.offer.OfferBookService;
import io.bitsquare.p2p.AddressService; import io.bitsquare.p2p.AddressService;
import io.bitsquare.p2p.EncryptedMailboxMessage;
import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.MailboxService; import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.Message; import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.MessageService; import io.bitsquare.p2p.MessageService;
@ -41,6 +44,7 @@ import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailability
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage; import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel; import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol; import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol; import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol;
import io.bitsquare.trade.protocol.trade.offerer.models.BuyerAsOffererModel; import io.bitsquare.trade.protocol.trade.offerer.models.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol; import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
@ -54,6 +58,7 @@ import org.bitcoinj.utils.Fiat;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
@ -78,6 +83,7 @@ public class TradeManager {
private final BlockChainService blockChainService; private final BlockChainService blockChainService;
private final WalletService walletService; private final WalletService walletService;
private final SignatureService signatureService; private final SignatureService signatureService;
private EncryptionService<MailboxMessage> encryptionService;
private final OfferBookService offerBookService; private final OfferBookService offerBookService;
private final Map<String, SellerAsTakerProtocol> sellerAsTakerProtocolMap = new HashMap<>(); private final Map<String, SellerAsTakerProtocol> sellerAsTakerProtocolMap = new HashMap<>();
@ -87,6 +93,7 @@ public class TradeManager {
private final ObservableMap<String, Offer> openOffers = FXCollections.observableHashMap(); private final ObservableMap<String, Offer> openOffers = FXCollections.observableHashMap();
private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap(); private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap(); private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap();
private final Map<String, MailboxMessage> mailboxMessages = new HashMap<>();
private Trade currentPendingTrade; private Trade currentPendingTrade;
@ -98,7 +105,7 @@ public class TradeManager {
@Inject @Inject
public TradeManager(User user, AccountSettings accountSettings, Persistence persistence, public TradeManager(User user, AccountSettings accountSettings, Persistence persistence,
MessageService messageService, MailboxService mailboxService, AddressService addressService, BlockChainService blockChainService, MessageService messageService, MailboxService mailboxService, AddressService addressService, BlockChainService blockChainService,
WalletService walletService, SignatureService signatureService, WalletService walletService, SignatureService signatureService, EncryptionService<MailboxMessage> encryptionService,
OfferBookService offerBookService) { OfferBookService offerBookService) {
this.user = user; this.user = user;
this.accountSettings = accountSettings; this.accountSettings = accountSettings;
@ -109,6 +116,7 @@ public class TradeManager {
this.blockChainService = blockChainService; this.blockChainService = blockChainService;
this.walletService = walletService; this.walletService = walletService;
this.signatureService = signatureService; this.signatureService = signatureService;
this.encryptionService = encryptionService;
this.offerBookService = offerBookService; this.offerBookService = offerBookService;
Serializable openOffersObject = persistence.read(this, "openOffers"); Serializable openOffersObject = persistence.read(this, "openOffers");
@ -125,10 +133,13 @@ public class TradeManager {
if (closedTradesObject instanceof Map<?, ?>) { if (closedTradesObject instanceof Map<?, ?>) {
closedTrades.putAll((Map<String, Trade>) closedTradesObject); closedTrades.putAll((Map<String, Trade>) closedTradesObject);
} }
messageService.addMessageHandler(this::handleMessage);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////////////////////////////////////////////
// When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades // When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades
// BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early. // BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early.
public void onAllServicesInitialized() { public void onAllServicesInitialized() {
@ -161,41 +172,25 @@ public class TradeManager {
} }
} }
} }
mailboxService.getAllMessages(user.getP2PSigPubKey(),
(messages) -> {
decryptMailboxMessages(messages);
emptyMailbox();
});
messageService.addMessageHandler(this::handleMessage);
} }
public boolean isMyOffer(Offer offer) { public boolean isMyOffer(Offer offer) {
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()); return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey());
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Called from UI // Offer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void checkOfferAvailability(Offer offer) {
offer.setState(Offer.State.UNKNOWN);
if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(
offer,
messageService,
addressService);
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
() -> disposeCheckOfferAvailabilityRequest(offer),
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
protocol.checkOfferAvailability();
}
else {
log.error("That should never happen: onCheckOfferAvailability already called for offer with ID:" + offer.getId());
}
}
// When closing take offer view, we are not interested in the onCheckOfferAvailability result anymore, so remove from the map
public void cancelGetOfferAvailableStateRequest(Offer offer) {
disposeCheckOfferAvailabilityRequest(offer);
}
public void placeOffer(String id, public void placeOffer(String id,
Direction direction, Direction direction,
Fiat price, Fiat price,
@ -240,6 +235,35 @@ public class TradeManager {
removeOpenOffer(offer, resultHandler, errorMessageHandler, true); removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Take offer
///////////////////////////////////////////////////////////////////////////////////////////
public void checkOfferAvailability(Offer offer) {
offer.setState(Offer.State.UNKNOWN);
if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(
offer,
messageService,
addressService);
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
() -> disposeCheckOfferAvailabilityRequest(offer),
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
protocol.checkOfferAvailability();
}
else {
log.error("That should never happen: onCheckOfferAvailability already called for offer with ID:" + offer.getId());
}
}
// When closing take offer view, we are not interested in the onCheckOfferAvailability result anymore, so remove from the map
public void cancelCheckOfferAvailabilityRequest(Offer offer) {
disposeCheckOfferAvailabilityRequest(offer);
}
public void requestTakeOffer(Coin amount, Offer offer, TradeResultHandler tradeResultHandler) { public void requestTakeOffer(Coin amount, Offer offer, TradeResultHandler tradeResultHandler) {
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, messageService, addressService); CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, messageService, addressService);
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model, CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
@ -255,6 +279,138 @@ public class TradeManager {
protocol.checkOfferAvailability(); protocol.checkOfferAvailability();
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Trade
///////////////////////////////////////////////////////////////////////////////////////////
public void onFiatPaymentStarted(String tradeId) {
// TODO remove if check when persistence is impl.
if (buyerAcceptsOfferProtocolMap.containsKey(tradeId)) {
buyerAcceptsOfferProtocolMap.get(tradeId).onFiatPaymentStarted();
persistPendingTrades();
}
}
public void onFiatPaymentReceived(String tradeId) {
sellerAsTakerProtocolMap.get(tradeId).onFiatPaymentReceived();
}
public void onWithdrawAtTradeCompleted(Trade trade) {
closeTrade(trade);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Called from Offerbook when offer gets removed from DHT
///////////////////////////////////////////////////////////////////////////////////////////
public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
disposeCheckOfferAvailabilityRequest(offer);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Message handler
///////////////////////////////////////////////////////////////////////////////////////////
// Offerer handles those requests
private void handleMessage(Message message, Peer sender) {
if (message instanceof RequestIsOfferAvailableMessage) {
String offerId = ((RequestIsOfferAvailableMessage) message).offerId;
checkNotNull(offerId);
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offerId, isOfferOpen(offerId));
messageService.sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
@Override
public void handleResult() {
// Offerer does not do anything at that moment. Peer might only watch the offer and does nto start a trade.
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
}
@Override
public void handleFault() {
log.warn("Sending ReportOfferAvailabilityMessage failed.");
}
});
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public ObservableMap<String, Offer> getOpenOffers() {
return openOffers;
}
public ObservableMap<String, Trade> getPendingTrades() {
return pendingTrades;
}
public ObservableMap<String, Trade> getClosedTrades() {
return closedTrades;
}
public Trade getCurrentPendingTrade() {
return currentPendingTrade;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// Offer
///////////////////////////////////////////////////////////////////////////////////////////
private void removeOpenOffer(Offer offer,
ResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler,
boolean removeFromBuyerAcceptsOfferProtocolMap) {
String offerId = offer.getId();
offerBookService.removeOffer(offer,
() -> {
if (openOffers.containsKey(offerId)) {
openOffers.remove(offerId);
disposeCheckOfferAvailabilityRequest(offer);
persistOpenOffers();
if (removeFromBuyerAcceptsOfferProtocolMap && buyerAcceptsOfferProtocolMap.containsKey(offerId)) {
buyerAcceptsOfferProtocolMap.get(offerId).cleanup();
buyerAcceptsOfferProtocolMap.remove(offerId);
}
resultHandler.handleResult();
}
else {
log.error("Locally stored offers does not contain the offer with the ID " + offerId);
errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offerId);
}
},
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Take offer
///////////////////////////////////////////////////////////////////////////////////////////
private void disposeCheckOfferAvailabilityRequest(Offer offer) {
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
protocol.cancel();
protocol.cleanup();
checkOfferAvailabilityProtocolMap.remove(offer.getId());
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Trade
///////////////////////////////////////////////////////////////////////////////////////////
private Trade takeAvailableOffer(Coin amount, Offer offer, Peer peer) { private Trade takeAvailableOffer(Coin amount, Offer offer, Peer peer) {
Trade trade = createTrade(offer); Trade trade = createTrade(offer);
trade.setTradeAmount(amount); trade.setTradeAmount(amount);
@ -264,6 +420,19 @@ public class TradeManager {
return trade; return trade;
} }
private Trade createTrade(Offer offer) {
if (pendingTrades.containsKey(offer.getId()))
log.error("That must never happen: Trades contains already an trade with the ID " + offer.getId());
Trade trade = new Trade(offer);
pendingTrades.put(offer.getId(), trade);
persistPendingTrades();
currentPendingTrade = trade;
return trade;
}
private SellerAsTakerProtocol createSellerAsTakerProtocol(Trade trade, Peer peer) { private SellerAsTakerProtocol createSellerAsTakerProtocol(Trade trade, Peer peer) {
trade.stateProperty().addListener((ov, oldValue, newValue) -> { trade.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue); log.debug("trade state = " + newValue);
@ -292,6 +461,7 @@ public class TradeManager {
trade, trade,
peer, peer,
messageService, messageService,
mailboxService,
walletService, walletService,
blockChainService, blockChainService,
signatureService, signatureService,
@ -300,122 +470,13 @@ public class TradeManager {
SellerAsTakerProtocol sellerTakesOfferProtocol = new SellerAsTakerProtocol(model); SellerAsTakerProtocol sellerTakesOfferProtocol = new SellerAsTakerProtocol(model);
sellerAsTakerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol); sellerAsTakerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
if (mailboxMessages.containsKey(trade.getId()))
sellerTakesOfferProtocol.setMailboxMessage(mailboxMessages.get(trade.getId()));
return sellerTakesOfferProtocol; return sellerTakesOfferProtocol;
} }
public void onFiatPaymentStarted(String tradeId) {
// TODO remove if check when persistence is impl.
if (buyerAcceptsOfferProtocolMap.containsKey(tradeId)) {
buyerAcceptsOfferProtocolMap.get(tradeId).onFiatPaymentStarted();
persistPendingTrades();
}
}
public void onFiatPaymentReceived(String tradeId) {
sellerAsTakerProtocolMap.get(tradeId).onFiatPaymentReceived();
}
public void closeTrade(Trade trade) {
if (pendingTrades.containsKey(trade.getId())) {
pendingTrades.remove(trade.getId());
persistPendingTrades();
}
if (sellerAsTakerProtocolMap.containsKey(trade.getId())) {
sellerAsTakerProtocolMap.get(trade.getId()).cleanup();
sellerAsTakerProtocolMap.remove(trade.getId());
}
else if (buyerAcceptsOfferProtocolMap.containsKey(trade.getId())) {
buyerAcceptsOfferProtocolMap.get(trade.getId()).cleanup();
buyerAcceptsOfferProtocolMap.remove(trade.getId());
}
if (!closedTrades.containsKey(trade.getId())) {
closedTrades.put(trade.getId(), trade);
persistClosedTrades();
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Called from Offerbook when offer gets removed from DHT
///////////////////////////////////////////////////////////////////////////////////////////
public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
disposeCheckOfferAvailabilityRequest(offer);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Process new tradeMessages
///////////////////////////////////////////////////////////////////////////////////////////
// Offerer handles those requests
private void handleMessage(Message message, Peer sender) {
if (message instanceof RequestIsOfferAvailableMessage) {
String offerId = ((RequestIsOfferAvailableMessage) message).offerId;
checkNotNull(offerId);
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offerId, isOfferOpen(offerId));
messageService.sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
@Override
public void handleResult() {
// Offerer does not do anything at that moment. Peer might only watch the offer and does nto start a trade.
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
}
@Override
public void handleFault() {
log.warn("Sending ReportOfferAvailabilityMessage failed.");
}
});
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void removeOpenOffer(Offer offer,
ResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler,
boolean removeFromBuyerAcceptsOfferProtocolMap) {
String offerId = offer.getId();
offerBookService.removeOffer(offer,
() -> {
if (openOffers.containsKey(offerId)) {
openOffers.remove(offerId);
disposeCheckOfferAvailabilityRequest(offer);
persistOpenOffers();
if (removeFromBuyerAcceptsOfferProtocolMap && buyerAcceptsOfferProtocolMap.containsKey(offerId)) {
buyerAcceptsOfferProtocolMap.get(offerId).cleanup();
buyerAcceptsOfferProtocolMap.remove(offerId);
}
resultHandler.handleResult();
}
else {
log.error("Locally stored offers does not contain the offer with the ID " + offerId);
errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offerId);
}
},
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
}
private Trade createTrade(Offer offer) {
if (pendingTrades.containsKey(offer.getId()))
log.error("That must never happen: Trades contains already an trade with the ID " + offer.getId());
Trade trade = new Trade(offer);
pendingTrades.put(offer.getId(), trade);
persistPendingTrades();
currentPendingTrade = trade;
return trade;
}
private void createBuyerAcceptsOfferProtocol(Offer offer) { private void createBuyerAcceptsOfferProtocol(Offer offer) {
Trade trade; Trade trade;
@ -482,13 +543,63 @@ public class TradeManager {
buyerAcceptsOfferProtocolMap.put(offer.getId(), buyerAcceptsOfferProtocol); buyerAcceptsOfferProtocolMap.put(offer.getId(), buyerAcceptsOfferProtocol);
} }
private void disposeCheckOfferAvailabilityRequest(Offer offer) { private void closeTrade(Trade trade) {
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) { if (pendingTrades.containsKey(trade.getId())) {
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId()); pendingTrades.remove(trade.getId());
protocol.cancel(); persistPendingTrades();
protocol.cleanup();
checkOfferAvailabilityProtocolMap.remove(offer.getId());
} }
if (sellerAsTakerProtocolMap.containsKey(trade.getId())) {
sellerAsTakerProtocolMap.get(trade.getId()).cleanup();
sellerAsTakerProtocolMap.remove(trade.getId());
}
else if (buyerAcceptsOfferProtocolMap.containsKey(trade.getId())) {
buyerAcceptsOfferProtocolMap.get(trade.getId()).cleanup();
buyerAcceptsOfferProtocolMap.remove(trade.getId());
}
if (!closedTrades.containsKey(trade.getId())) {
closedTrades.put(trade.getId(), trade);
persistClosedTrades();
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Mailbox
///////////////////////////////////////////////////////////////////////////////////////////
private void decryptMailboxMessages(List<EncryptedMailboxMessage> encryptedMailboxMessages) {
log.trace("applyMailboxMessage encryptedMailboxMessage.size=" + encryptedMailboxMessages.size());
for (EncryptedMailboxMessage encrypted : encryptedMailboxMessages) {
MailboxMessage mailboxMessage = null;
try {
mailboxMessage = encryptionService.decryptToObject(user.getP2pEncryptPrivateKey(), encrypted.getEncryptionPackage());
} catch (Throwable e) {
e.printStackTrace();
log.error(e.getMessage());
}
if (mailboxMessage instanceof TradeMessage) {
String tradeId = ((TradeMessage) mailboxMessage).tradeId;
mailboxMessages.put(tradeId, mailboxMessage);
log.trace("mailboxMessage with tradeID " + tradeId);
if (sellerAsTakerProtocolMap.containsKey(tradeId)) {
sellerAsTakerProtocolMap.get(tradeId).setMailboxMessage(encrypted);
log.trace("sellerAsTakerProtocolMap exist with tradeID " + tradeId);
}
}
}
}
private void emptyMailbox() {
mailboxService.removeAllMessages(user.getP2PSigPubKey(),
() -> {
log.debug("All mailbox entries removed");
},
(errorMessage, fault) -> {
log.error(errorMessage);
log.error(fault.getMessage());
});
} }
boolean isOfferOpen(String offerId) { boolean isOfferOpen(String offerId) {
@ -498,31 +609,6 @@ public class TradeManager {
|| openOffers.get(offerId).getState() == Offer.State.AVAILABLE); || openOffers.get(offerId).getState() == Offer.State.AVAILABLE);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public ObservableMap<String, Offer> getOpenOffers() {
return openOffers;
}
public ObservableMap<String, Trade> getPendingTrades() {
return pendingTrades;
}
public ObservableMap<String, Trade> getClosedTrades() {
return closedTrades;
}
public Trade getCurrentPendingTrade() {
return currentPendingTrade;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void persistOpenOffers() { private void persistOpenOffers() {
persistence.write(this, "openOffers", (Map<String, Offer>) new HashMap<>(openOffers)); persistence.write(this, "openOffers", (Map<String, Offer>) new HashMap<>(openOffers));
} }

View file

@ -39,7 +39,7 @@ public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
model.addressService.findPeerAddress(model.offer.getMessagePublicKey(), new GetPeerAddressListener() { model.addressService.findPeerAddress(model.offer.getP2PSigPubKey(), new GetPeerAddressListener() {
@Override @Override
public void onResult(Peer peer) { public void onResult(Peer peer) {
model.setPeer(peer); model.setPeer(peer);

View file

@ -22,8 +22,10 @@ import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.common.taskrunner.SharedTaskModel; import io.bitsquare.common.taskrunner.SharedTaskModel;
import io.bitsquare.crypto.SignatureService; import io.bitsquare.crypto.SignatureService;
import io.bitsquare.p2p.MessageService;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.MessageService;
import io.bitsquare.persistence.Persistence; import io.bitsquare.persistence.Persistence;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage; import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
@ -39,11 +41,14 @@ public class SharedTradeModel extends SharedTaskModel implements Serializable {
// provided // provided
transient public final Offer offer; transient public final Offer offer;
transient public final MessageService messageService; transient public final MessageService messageService;
transient public final MailboxService mailboxService;
transient public final WalletService walletService; transient public final WalletService walletService;
transient public final BlockChainService blockChainService; transient public final BlockChainService blockChainService;
transient public final SignatureService signatureService; transient public final SignatureService signatureService;
transient protected final Persistence persistence; transient protected final Persistence persistence;
transient public MailboxMessage mailboxMessage;
// derived // derived
transient public final String id; transient public final String id;
transient public final TradeWalletService tradeWalletService; transient public final TradeWalletService tradeWalletService;
@ -54,12 +59,14 @@ public class SharedTradeModel extends SharedTaskModel implements Serializable {
protected SharedTradeModel(Offer offer, protected SharedTradeModel(Offer offer,
MessageService messageService, MessageService messageService,
MailboxService mailboxService,
WalletService walletService, WalletService walletService,
BlockChainService blockChainService, BlockChainService blockChainService,
SignatureService signatureService, SignatureService signatureService,
Persistence persistence) { Persistence persistence) {
this.offer = offer; this.offer = offer;
this.messageService = messageService; this.messageService = messageService;
this.mailboxService = mailboxService;
this.walletService = walletService; this.walletService = walletService;
this.blockChainService = blockChainService; this.blockChainService = blockChainService;
this.signatureService = signatureService; this.signatureService = signatureService;

View file

@ -23,7 +23,7 @@ import org.bitcoinj.core.Coin;
import java.io.Serializable; import java.io.Serializable;
public class BankTransferStartedMessage extends TradeMessage implements MailboxMessage, Serializable { public class FiatTransferStartedMessage extends TradeMessage implements MailboxMessage, Serializable {
private static final long serialVersionUID = -3479634129543632523L; private static final long serialVersionUID = -3479634129543632523L;
public final byte[] offererSignature; public final byte[] offererSignature;
@ -31,7 +31,7 @@ public class BankTransferStartedMessage extends TradeMessage implements MailboxM
public final Coin takerPayoutAmount; public final Coin takerPayoutAmount;
public final String offererPayoutAddress; public final String offererPayoutAddress;
public BankTransferStartedMessage(String tradeId, public FiatTransferStartedMessage(String tradeId,
byte[] offererSignature, byte[] offererSignature,
Coin offererPayoutAmount, Coin offererPayoutAmount,
Coin takerPayoutAmount, Coin takerPayoutAmount,

View file

@ -33,7 +33,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
public final FiatAccount takerFiatAccount; public final FiatAccount takerFiatAccount;
public final String takerAccountId; public final String takerAccountId;
public final PublicKey takerMessagePublicKey; public final PublicKey takerP2PSigPublicKey;
public final PublicKey takerP2PEncryptPublicKey;
public final String takerContractAsJson; public final String takerContractAsJson;
public final String takerContractSignature; public final String takerContractSignature;
public final String takerPayoutAddressString; public final String takerPayoutAddressString;
@ -44,7 +45,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
public RequestOffererPublishDepositTxMessage(String tradeId, public RequestOffererPublishDepositTxMessage(String tradeId,
FiatAccount takerFiatAccount, FiatAccount takerFiatAccount,
String takerAccountId, String takerAccountId,
PublicKey takerMessagePublicKey, PublicKey takerP2PSigPublicKey,
PublicKey takerP2PEncryptPublicKey,
String takerContractAsJson, String takerContractAsJson,
String takerContractSignature, String takerContractSignature,
String takerPayoutAddressString, String takerPayoutAddressString,
@ -54,7 +56,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
this.tradeId = tradeId; this.tradeId = tradeId;
this.takerFiatAccount = takerFiatAccount; this.takerFiatAccount = takerFiatAccount;
this.takerAccountId = takerAccountId; this.takerAccountId = takerAccountId;
this.takerMessagePublicKey = takerMessagePublicKey; this.takerP2PSigPublicKey = takerP2PSigPublicKey;
this.takerP2PEncryptPublicKey = takerP2PEncryptPublicKey;
this.takerContractAsJson = takerContractAsJson; this.takerContractAsJson = takerContractAsJson;
this.takerContractSignature = takerContractSignature; this.takerContractSignature = takerContractSignature;
this.takerPayoutAddressString = takerPayoutAddressString; this.takerPayoutAddressString = takerPayoutAddressString;

View file

@ -37,7 +37,6 @@ public class BuyerAsOffererModel extends SharedTradeModel implements Serializabl
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererModel.class); private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererModel.class);
transient public final Trade trade; transient public final Trade trade;
transient public final MailboxService mailboxService;
public final TakerModel taker; public final TakerModel taker;
public final OffererModel offerer; public final OffererModel offerer;
@ -54,13 +53,13 @@ public class BuyerAsOffererModel extends SharedTradeModel implements Serializabl
Persistence persistence) { Persistence persistence) {
super(trade.getOffer(), super(trade.getOffer(),
messageService, messageService,
mailboxService,
walletService, walletService,
blockChainService, blockChainService,
signatureService, signatureService,
persistence); persistence);
this.trade = trade; this.trade = trade;
this.mailboxService = mailboxService;
Serializable serializable = persistence.read(this, "BuyerAsOffererModel_" + id); Serializable serializable = persistence.read(this, "BuyerAsOffererModel_" + id);
if (serializable instanceof BuyerAsOffererModel) { if (serializable instanceof BuyerAsOffererModel) {

View file

@ -38,6 +38,7 @@ public class TakerModel implements Serializable {
public String accountId; public String accountId;
public FiatAccount fiatAccount; public FiatAccount fiatAccount;
public PublicKey p2pSigPublicKey; public PublicKey p2pSigPublicKey;
public PublicKey p2pEncryptPubKey;
public String contractAsJson;//TODO only write access now, missing impl. public String contractAsJson;//TODO only write access now, missing impl.
public String contractSignature; public String contractSignature;
public Coin payoutAmount; public Coin payoutAmount;

View file

@ -43,7 +43,8 @@ public class ProcessRequestOffererPublishDepositTxMessage extends Task<BuyerAsOf
model.taker.fiatAccount = checkNotNull(message.takerFiatAccount); model.taker.fiatAccount = checkNotNull(message.takerFiatAccount);
model.taker.accountId = nonEmptyStringOf(message.takerAccountId); model.taker.accountId = nonEmptyStringOf(message.takerAccountId);
model.taker.p2pSigPublicKey = checkNotNull(message.takerMessagePublicKey); model.taker.p2pSigPublicKey = checkNotNull(message.takerP2PSigPublicKey);
model.taker.p2pEncryptPubKey = checkNotNull(message.takerP2PEncryptPublicKey);
model.taker.contractAsJson = nonEmptyStringOf(message.takerContractAsJson); model.taker.contractAsJson = nonEmptyStringOf(message.takerContractAsJson);
model.taker.contractSignature = nonEmptyStringOf(message.takerContractSignature); model.taker.contractSignature = nonEmptyStringOf(message.takerContractSignature);
model.taker.payoutAddressString = nonEmptyStringOf(message.takerPayoutAddressString); model.taker.payoutAddressString = nonEmptyStringOf(message.takerPayoutAddressString);

View file

@ -20,7 +20,8 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.Task; import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.protocol.trade.messages.BankTransferStartedMessage; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.models.BuyerAsOffererModel; import io.bitsquare.trade.protocol.trade.offerer.models.BuyerAsOffererModel;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -36,26 +37,32 @@ public class SendBankTransferStartedMessage extends Task<BuyerAsOffererModel> {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
BankTransferStartedMessage tradeMessage = new BankTransferStartedMessage( FiatTransferStartedMessage tradeMessage = new FiatTransferStartedMessage(model.id,
model.id,
model.offerer.payoutTxSignature, model.offerer.payoutTxSignature,
model.offerer.payoutAmount, model.offerer.payoutAmount,
model.taker.payoutAmount, model.taker.payoutAmount,
model.offerer.addressEntry.getAddressString()); model.offerer.addressEntry.getAddressString());
model.messageService.sendMessage(model.taker.peer, tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("Sending BankTransferInitedMessage succeeded.");
complete();
}
@Override model.messageService.sendMessage(model.taker.peer, tradeMessage,
public void handleFault() { model.taker.p2pSigPublicKey,
failed("Sending BankTransferInitedMessage failed."); model.taker.p2pEncryptPubKey,
} new SendMessageListener() {
}); @Override
public void handleResult() {
log.trace("Sending BankTransferInitedMessage succeeded.");
model.trade.setState(Trade.State.FIAT_PAYMENT_STARTED);
complete();
}
@Override
public void handleFault() {
failed("Sending BankTransferInitedMessage failed.");
model.trade.setState(Trade.State.FAULT);
}
});
} catch (Throwable t) { } catch (Throwable t) {
failed("Sending BankTransferInitedMessage failed."); failed("Sending BankTransferInitedMessage failed.");
model.trade.setState(Trade.State.FAULT);
} }
} }
} }

View file

@ -18,20 +18,21 @@
package io.bitsquare.trade.protocol.trade.taker; package io.bitsquare.trade.protocol.trade.taker;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.Message; import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.MessageHandler; import io.bitsquare.p2p.MessageHandler;
import io.bitsquare.p2p.Peer; import io.bitsquare.p2p.Peer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.messages.BankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.messages.RequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage; import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel; import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer; import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage;
@ -70,6 +71,8 @@ public class SellerAsTakerProtocol {
this.model = model; this.model = model;
messageHandler = this::handleMessage; messageHandler = this::handleMessage;
model.messageService.addMessageHandler(messageHandler); model.messageService.addMessageHandler(messageHandler);
} }
@ -82,6 +85,17 @@ public class SellerAsTakerProtocol {
model.messageService.removeMessageHandler(messageHandler); model.messageService.removeMessageHandler(messageHandler);
} }
public void setMailboxMessage(MailboxMessage mailboxMessage) {
log.debug("setMailboxMessage " + mailboxMessage);
// Might be called twice, so check that its only processed once
if (model.mailboxMessage == null) {
model.mailboxMessage = mailboxMessage;
if (mailboxMessage instanceof FiatTransferStartedMessage) {
handleFiatTransferStartedMessage((FiatTransferStartedMessage) mailboxMessage);
}
}
}
public void takeAvailableOffer() { public void takeAvailableOffer() {
TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model, TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model,
() -> { () -> {
@ -99,7 +113,7 @@ public class SellerAsTakerProtocol {
taskRunner.run(); taskRunner.run();
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling // Incoming message handling
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -143,19 +157,19 @@ public class SellerAsTakerProtocol {
taskRunner.run(); taskRunner.run();
} }
private void handleBankTransferStartedMessage(BankTransferStartedMessage tradeMessage) { private void handleFiatTransferStartedMessage(FiatTransferStartedMessage tradeMessage) {
model.setTradeMessage(tradeMessage); model.setTradeMessage(tradeMessage);
TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model, TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model,
() -> { () -> {
log.debug("taskRunner at handleBankTransferInitedMessage completed"); log.debug("taskRunner at handleFiatTransferStartedMessage completed");
model.trade.setState(Trade.State.FIAT_PAYMENT_STARTED); model.trade.setState(Trade.State.FIAT_PAYMENT_STARTED);
}, },
(errorMessage) -> { (errorMessage) -> {
log.error(errorMessage); log.error(errorMessage);
} }
); );
taskRunner.addTasks(ProcessBankTransferStartedMessage.class); taskRunner.addTasks(ProcessFiatTransferStartedMessage.class);
taskRunner.run(); taskRunner.run();
} }
@ -201,8 +215,8 @@ public class SellerAsTakerProtocol {
else if (tradeMessage instanceof DepositTxPublishedMessage) { else if (tradeMessage instanceof DepositTxPublishedMessage) {
handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage); handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
} }
else if (tradeMessage instanceof BankTransferStartedMessage) { else if (tradeMessage instanceof FiatTransferStartedMessage) {
handleBankTransferStartedMessage((BankTransferStartedMessage) tradeMessage); handleFiatTransferStartedMessage((FiatTransferStartedMessage) tradeMessage);
} }
else { else {
log.error("Incoming message not supported. " + tradeMessage); log.error("Incoming message not supported. " + tradeMessage);

View file

@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.models;
import io.bitsquare.btc.BlockChainService; import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService; import io.bitsquare.crypto.SignatureService;
import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.MessageService; import io.bitsquare.p2p.MessageService;
import io.bitsquare.p2p.Peer; import io.bitsquare.p2p.Peer;
import io.bitsquare.persistence.Persistence; import io.bitsquare.persistence.Persistence;
@ -49,6 +50,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
public SellerAsTakerModel(Trade trade, public SellerAsTakerModel(Trade trade,
Peer offererPeer, Peer offererPeer,
MessageService messageService, MessageService messageService,
MailboxService mailboxService,
WalletService walletService, WalletService walletService,
BlockChainService blockChainService, BlockChainService blockChainService,
SignatureService signatureService, SignatureService signatureService,
@ -56,6 +58,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
Persistence persistence) { Persistence persistence) {
super(trade.getOffer(), super(trade.getOffer(),
messageService, messageService,
mailboxService,
walletService, walletService,
blockChainService, blockChainService,
signatureService, signatureService,
@ -87,6 +90,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
taker.fiatAccount = user.getBankAccount(offer.getBankAccountId()); taker.fiatAccount = user.getBankAccount(offer.getBankAccountId());
taker.accountId = user.getAccountId(); taker.accountId = user.getAccountId();
taker.p2pSigPubKey = user.getP2PSigPubKey(); taker.p2pSigPubKey = user.getP2PSigPubKey();
taker.p2pEncryptPublicKey = user.getP2PEncryptPubKey();
taker.pubKey = taker.addressEntry.getPubKey(); taker.pubKey = taker.addressEntry.getPubKey();
} }

View file

@ -39,6 +39,7 @@ public class TakerModel implements Serializable {
transient public FiatAccount fiatAccount; transient public FiatAccount fiatAccount;
transient public String accountId; transient public String accountId;
transient public PublicKey p2pSigPubKey; transient public PublicKey p2pSigPubKey;
transient public PublicKey p2pEncryptPublicKey;
transient public byte[] registrationPubKey; // TODO not read yet, missing impl. transient public byte[] registrationPubKey; // TODO not read yet, missing impl.
transient public DeterministicKey registrationKeyPair; transient public DeterministicKey registrationKeyPair;
transient public AddressEntry addressEntry; transient public AddressEntry addressEntry;

View file

@ -45,7 +45,7 @@ public class CreateAndSignContract extends Task<SellerAsTakerModel> {
model.taker.accountId, model.taker.accountId,
model.offerer.fiatAccount, model.offerer.fiatAccount,
model.taker.fiatAccount, model.taker.fiatAccount,
model.offer.getMessagePublicKey(), model.offer.getP2PSigPubKey(),
model.taker.p2pSigPubKey); model.taker.p2pSigPubKey);
String contractAsJson = Utilities.objectToJson(contract); String contractAsJson = Utilities.objectToJson(contract);
String signature = model.signatureService.signMessage(model.taker.registrationKeyPair, contractAsJson); String signature = model.signatureService.signMessage(model.taker.registrationKeyPair, contractAsJson);

View file

@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task; import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.protocol.trade.messages.BankTransferStartedMessage; import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel; import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -28,10 +28,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.*;
public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel> { public class ProcessFiatTransferStartedMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessBankTransferStartedMessage.class); private static final Logger log = LoggerFactory.getLogger(ProcessFiatTransferStartedMessage.class);
public ProcessBankTransferStartedMessage(TaskRunner taskHandler, SellerAsTakerModel model) { public ProcessFiatTransferStartedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model); super(taskHandler, model);
} }
@ -39,7 +39,7 @@ public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel>
protected void doRun() { protected void doRun() {
try { try {
checkTradeId(model.id, model.getTradeMessage()); checkTradeId(model.id, model.getTradeMessage());
BankTransferStartedMessage message = (BankTransferStartedMessage) model.getTradeMessage(); FiatTransferStartedMessage message = (FiatTransferStartedMessage) model.getTradeMessage();
model.offerer.signature = checkNotNull(message.offererSignature); model.offerer.signature = checkNotNull(message.offererSignature);
model.offerer.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)); model.offerer.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount));

View file

@ -40,6 +40,7 @@ public class SendSignedTakerDepositTx extends Task<SellerAsTakerModel> {
model.taker.fiatAccount, model.taker.fiatAccount,
model.taker.accountId, model.taker.accountId,
model.taker.p2pSigPubKey, model.taker.p2pSigPubKey,
model.taker.p2pEncryptPublicKey,
model.trade.getContractAsJson(), model.trade.getContractAsJson(),
model.trade.getTakerContractSignature(), model.trade.getTakerContractSignature(),
model.taker.addressEntry.getAddressString(), model.taker.addressEntry.getAddressString(),

View file

@ -24,6 +24,8 @@ import io.bitsquare.util.DSAKeyUtil;
import java.io.Serializable; import java.io.Serializable;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.ArrayList; import java.util.ArrayList;
@ -39,12 +41,16 @@ import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* The User is persisted locally. * The User is persisted locally.
* It must never be transmitted over the wire (messageKeyPair contains private key!). * It must never be transmitted over the wire (messageKeyPair contains private key!).
*/ */
public class User implements Serializable { public class User implements Serializable {
private static final long serialVersionUID = 7409078808248518638L; private static final long serialVersionUID = 7409078808248518638L;
private static final Logger log = LoggerFactory.getLogger(User.class);
private KeyPair p2pSigKeyPair; private KeyPair p2pSigKeyPair;
private KeyPair p2pEncryptKeyPair; private KeyPair p2pEncryptKeyPair;
@ -87,8 +93,13 @@ public class User implements Serializable {
} }
else { else {
// First time // First time
p2pSigKeyPair = DSAKeyUtil.generateKeyPair(); p2pSigKeyPair = DSAKeyUtil.generateDSAKeyPair();
p2pEncryptKeyPair = encryptionService.getKeyPair(); try {
p2pEncryptKeyPair = encryptionService.getKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
log.error(e.getMessage());
}
} }
} }
@ -179,6 +190,10 @@ public class User implements Serializable {
return p2pSigKeyPair.getPublic(); return p2pSigKeyPair.getPublic();
} }
public PublicKey getP2PEncryptPubKey() {
return p2pEncryptKeyPair.getPublic();
}
public ObjectProperty<FiatAccount> currentBankAccountProperty() { public ObjectProperty<FiatAccount> currentBankAccountProperty() {
return currentBankAccount; return currentBankAccount;
} }
@ -192,7 +207,11 @@ public class User implements Serializable {
return _currentFiatAccount; return _currentFiatAccount;
} }
public KeyPair getP2pEncryptKeyPair() { public PrivateKey getP2pEncryptPrivateKey() {
return p2pEncryptKeyPair.getPrivate();
}
KeyPair getP2pEncryptKeyPair() {
return p2pEncryptKeyPair; return p2pEncryptKeyPair;
} }
} }

View file

@ -36,7 +36,7 @@ public class DSAKeyUtil {
return Utils.HEX.encode(x509EncodedKeySpec.getEncoded()); return Utils.HEX.encode(x509EncodedKeySpec.getEncoded());
} }
public static KeyPair generateKeyPair() { public static KeyPair generateDSAKeyPair() {
try { try {
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024); keyGen.initialize(1024);

View file

@ -0,0 +1,88 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.crypto;
import io.bitsquare.p2p.MailboxMessage;
import java.security.KeyPair;
import java.util.Random;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.springframework.test.util.AssertionErrors.assertEquals;
public class EncryptionServiceTests {
private static final Logger log = LoggerFactory.getLogger(EncryptionServiceTests.class);
@Test
public void testEncryptionWithMailboxMessage() throws Exception {
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>();
KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair();
TestMessage message = new TestMessage("test");
EncryptionPackage encryptionPackage = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), message);
MailboxMessage result = encryptionService.decryptToObject(p2pEncryptKeyPair.getPrivate(), encryptionPackage);
assertEquals("", message.data, ((TestMessage) result).data);
}
@Test
public void testEncryptionWithInteger() throws Exception {
EncryptionService<Integer> encryptionService = new EncryptionService<>();
KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair();
int data = 1234;
EncryptionPackage encryptionPackage = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), data);
Integer result = encryptionService.decryptToObject(p2pEncryptKeyPair.getPrivate(), encryptionPackage);
assertEquals("", data, result);
}
@Test
public void testEncryptionWithBytes() throws Exception {
EncryptionService encryptionService = new EncryptionService();
KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair();
byte[] data = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04};
EncryptionPackage encryptionPackage = encryptionService.encrypt(p2pEncryptKeyPair.getPublic(), data);
byte[] result = encryptionService.decrypt(p2pEncryptKeyPair.getPrivate(), encryptionPackage);
assertEquals("", result, data);
}
@Test
public void testEncryptionWithLargeData() throws Exception {
EncryptionService encryptionService = new EncryptionService();
KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair();
byte[] data = new byte[2000];
new Random().nextBytes(data);
EncryptionPackage encryptionPackage = encryptionService.encrypt(p2pEncryptKeyPair.getPublic(), data);
byte[] result = encryptionService.decrypt(p2pEncryptKeyPair.getPrivate(), encryptionPackage);
assertEquals("", result, data);
}
}
class TestMessage implements MailboxMessage {
public String data = "test";
public TestMessage(String data) {
this.data = data;
}
}

View file

@ -296,7 +296,7 @@ public class PlaceOfferProtocolTest {
private Offer getOffer() { private Offer getOffer() {
return new Offer(OFFER_ID, return new Offer(OFFER_ID,
DSAKeyUtil.generateKeyPair().getPublic(), DSAKeyUtil.generateDSAKeyPair().getPublic(),
Direction.BUY, Direction.BUY,
100L, 100L,
Coin.CENT, Coin.CENT,