mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-04-21 08:06:33 -04:00
Add DHT mailbox
This commit is contained in:
parent
506ac37293
commit
239389b529
@ -69,7 +69,7 @@ public class BlockChainService {
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameReturnValue")
|
||||
private boolean isBankAccountBlacklisted(FiatAccount fiatAccount) {
|
||||
private boolean isFiatAccountBlacklisted(FiatAccount fiatAccount) {
|
||||
// TODO check if accountID is on blacklist
|
||||
return false;
|
||||
}
|
||||
|
@ -471,14 +471,14 @@ public class WalletService {
|
||||
return tradeWalletService;
|
||||
}
|
||||
|
||||
public void payRegistrationFee(String stringifiedBankAccounts, FutureCallback<Transaction> callback) throws
|
||||
public void payRegistrationFee(String stringifiedFiatAccounts, FutureCallback<Transaction> callback) throws
|
||||
InsufficientMoneyException {
|
||||
log.debug("payRegistrationFee");
|
||||
log.trace("stringifiedBankAccounts " + stringifiedBankAccounts);
|
||||
log.trace("stringifiedFiatAccounts " + stringifiedFiatAccounts);
|
||||
|
||||
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());
|
||||
|
||||
// We don't take a fee at the moment
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -19,11 +19,11 @@ package io.bitsquare.crypto;
|
||||
|
||||
import io.bitsquare.util.Utilities;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
@ -32,98 +32,82 @@ import javax.inject.Inject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class EncryptionService<T> {
|
||||
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
|
||||
public EncryptionService() {
|
||||
}
|
||||
|
||||
public KeyPair getKeyPair() {
|
||||
KeyPair keyPair = null;
|
||||
try {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(1024);
|
||||
keyPair = keyPairGenerator.genKeyPair();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("Exception at init " + e.getMessage());
|
||||
}
|
||||
return keyPair;
|
||||
public KeyPair getKeyPair() throws NoSuchAlgorithmException {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGO_ASYM);
|
||||
keyPairGenerator.initialize(KEY_SIZE_ASYM);
|
||||
return keyPairGenerator.genKeyPair();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public T decryptToObject(PrivateKey privateKey, Tuple tuple) {
|
||||
return (T) Utilities.byteArrayToObject(decrypt(privateKey, tuple));
|
||||
public T decryptToObject(PrivateKey privateKey, EncryptionPackage encryptionPackage) throws IllegalBlockSizeException, InvalidKeyException,
|
||||
BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
return (T) Utilities.byteArrayToObject(decrypt(privateKey, encryptionPackage));
|
||||
}
|
||||
|
||||
public Tuple encrypt(PublicKey publicKey, byte[] payload) {
|
||||
byte[] encryptedPayload = null;
|
||||
byte[] encryptedKey = null;
|
||||
try {
|
||||
// Create symmetric key and
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||
keyGenerator.init(256);
|
||||
SecretKey secretKey = keyGenerator.generateKey();
|
||||
public EncryptionPackage encrypt(PublicKey publicKey, byte[] payload) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
|
||||
BadPaddingException, IllegalBlockSizeException {
|
||||
// Create symmetric key and
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGO_SYM);
|
||||
keyGenerator.init(KEY_SIZE_SYM);
|
||||
SecretKey secretKey = keyGenerator.generateKey();
|
||||
|
||||
// Encrypt secretKey with asymmetric key
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
encryptedKey = cipher.doFinal(secretKey.getEncoded());
|
||||
// Encrypt secretKey with asymmetric key
|
||||
Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
|
||||
cipherAsym.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
log.debug("encrypt secret key length: " + secretKey.getEncoded().length);
|
||||
byte[] encryptedKey = cipherAsym.doFinal(secretKey.getEncoded());
|
||||
|
||||
// Encrypt payload with symmetric key
|
||||
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
|
||||
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
|
||||
encryptedPayload = cipher.doFinal(payload);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("Exception at encrypt " + e.getMessage());
|
||||
}
|
||||
return new Tuple(encryptedKey, encryptedPayload);
|
||||
// Encrypt payload with symmetric key
|
||||
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), ALGO_SYM);
|
||||
Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
|
||||
cipherSym.init(Cipher.ENCRYPT_MODE, keySpec);
|
||||
log.debug("encrypt payload length: " + payload.length);
|
||||
byte[] encryptedPayload = cipherSym.doFinal(payload);
|
||||
return new EncryptionPackage(encryptedKey, encryptedPayload);
|
||||
}
|
||||
|
||||
public byte[] decrypt(PrivateKey privateKey, Tuple tuple) {
|
||||
byte[] encryptedPayload = tuple.encryptedPayload;
|
||||
byte[] encryptedKey = tuple.encryptedKey;
|
||||
public byte[] decrypt(PrivateKey privateKey, EncryptionPackage encryptionPackage) throws NoSuchPaddingException, NoSuchAlgorithmException,
|
||||
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
||||
byte[] encryptedPayload = encryptionPackage.encryptedPayload;
|
||||
byte[] encryptedKey = encryptionPackage.encryptedKey;
|
||||
|
||||
byte[] payload = null;
|
||||
try {
|
||||
// Decrypt secretKey key with asymmetric key
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] secretKey = cipher.doFinal(encryptedKey);
|
||||
|
||||
// Decrypt payload with symmetric key
|
||||
Key key = new SecretKeySpec(secretKey, "AES");
|
||||
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, key);
|
||||
payload = cipher.doFinal(encryptedPayload);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("Exception at decrypt " + e.getMessage());
|
||||
}
|
||||
// Decrypt secretKey key with asymmetric key
|
||||
Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
|
||||
cipherAsym.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] secretKey = cipherAsym.doFinal(encryptedKey);
|
||||
log.debug("decrypt secret key length: " + secretKey.length);
|
||||
// Decrypt payload with symmetric key
|
||||
Key key = new SecretKeySpec(secretKey, ALGO_SYM);
|
||||
Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
|
||||
cipherSym.init(Cipher.DECRYPT_MODE, key);
|
||||
byte[] payload = cipherSym.doFinal(encryptedPayload);
|
||||
log.debug("decrypt payload length: " + payload.length);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ class RestrictionsDataModel implements Activatable, DataModel {
|
||||
private void addMockArbitrator() {
|
||||
if (accountSettings.getAcceptedArbitrators().isEmpty() && user.getP2pSigKeyPair() != null) {
|
||||
byte[] pubKey = new ECKey().getPubKey();
|
||||
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getP2PSigPubKey());
|
||||
String p2pSigPubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getP2PSigPubKey());
|
||||
List<Locale> languages = new ArrayList<>();
|
||||
languages.add(LanguageUtil.getDefaultLanguageLocale());
|
||||
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
|
||||
// Revert later to 0.1 BTC again
|
||||
Arbitrator arbitrator = new Arbitrator(pubKey,
|
||||
messagePubKeyAsHex,
|
||||
p2pSigPubKeyAsHex,
|
||||
"Manfred Karrer",
|
||||
Arbitrator.ID_TYPE.REAL_LIFE_ID,
|
||||
languages,
|
||||
|
@ -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.tasks.CreateAndSignContract;
|
||||
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.ProcessRequestDepositPaymentMessage;
|
||||
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
|
||||
@ -135,7 +135,7 @@ public class DebugView extends InitializableView {
|
||||
ProcessDepositTxPublishedMessage.class,
|
||||
TakerCommitDepositTx.class,
|
||||
|
||||
ProcessBankTransferStartedMessage.class,
|
||||
ProcessFiatTransferStartedMessage.class,
|
||||
|
||||
SignAndPublishPayoutTx.class,
|
||||
VerifyOfferFeePayment.class,
|
||||
|
@ -74,7 +74,7 @@ class ClosedTradesDataModel implements Activatable, DataModel {
|
||||
}
|
||||
|
||||
public Direction getDirection(Offer offer) {
|
||||
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ?
|
||||
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
|
||||
offer.getDirection() : offer.getMirroredDirection();
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ class OffersDataModel implements Activatable, DataModel {
|
||||
}
|
||||
|
||||
public Direction getDirection(Offer offer) {
|
||||
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ?
|
||||
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
|
||||
offer.getDirection() : offer.getMirroredDirection();
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||
selectedItem = item;
|
||||
|
||||
if (selectedItem != null) {
|
||||
isOfferer = getTrade().getOffer().getMessagePublicKey().equals(user.getP2PSigPubKey());
|
||||
isOfferer = getTrade().getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey());
|
||||
|
||||
Trade trade = getTrade();
|
||||
trade.stateProperty().addListener(tradeStateChangeListener);
|
||||
@ -172,7 +172,6 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||
}
|
||||
|
||||
void fiatPaymentStarted() {
|
||||
getTrade().setState(Trade.State.FIAT_PAYMENT_STARTED);
|
||||
tradeManager.onFiatPaymentStarted(getTrade().getId());
|
||||
}
|
||||
|
||||
@ -209,7 +208,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
|
||||
tradeManager.closeTrade(getTrade());
|
||||
tradeManager.onWithdrawAtTradeCompleted(getTrade());
|
||||
|
||||
/*
|
||||
Action response = Popups.openConfirmPopup(
|
||||
@ -269,7 +268,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||
}
|
||||
|
||||
public Direction getDirection(Offer offer) {
|
||||
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ?
|
||||
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
|
||||
offer.getDirection() : offer.getMirroredDirection();
|
||||
}
|
||||
|
||||
|
@ -213,7 +213,7 @@ class OfferBookDataModel implements Activatable, DataModel {
|
||||
}
|
||||
|
||||
boolean isMyOffer(Offer offer) {
|
||||
return offer.getMessagePublicKey() != null && offer.getMessagePublicKey().equals(user.getP2PSigPubKey());
|
||||
return offer.getP2PSigPubKey() != null && offer.getP2PSigPubKey().equals(user.getP2PSigPubKey());
|
||||
}
|
||||
|
||||
Coin getAmountAsCoin() {
|
||||
|
@ -97,7 +97,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
|
||||
@Override
|
||||
public void deactivate() {
|
||||
btcCode.unbind();
|
||||
tradeManager.cancelGetOfferAvailableStateRequest(offer);
|
||||
tradeManager.cancelCheckOfferAvailabilityRequest(offer);
|
||||
}
|
||||
|
||||
void initWithData(Coin amount, Offer offer) {
|
||||
|
@ -70,7 +70,7 @@ public class Offer implements Serializable {
|
||||
private final Coin amount;
|
||||
private final Coin minAmount;
|
||||
//TODO use hex string
|
||||
private final PublicKey messagePublicKey;
|
||||
private final PublicKey p2pSigPubKey;
|
||||
private final FiatAccountType fiatAccountType;
|
||||
private final Country bankAccountCountry;
|
||||
|
||||
@ -94,7 +94,7 @@ public class Offer implements Serializable {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Offer(String id,
|
||||
PublicKey messagePublicKey,
|
||||
PublicKey p2pSigPubKey,
|
||||
Direction direction,
|
||||
long fiatPrice,
|
||||
Coin amount,
|
||||
@ -108,7 +108,7 @@ public class Offer implements Serializable {
|
||||
List<Country> acceptedCountries,
|
||||
List<Locale> acceptedLanguageLocales) {
|
||||
this.id = id;
|
||||
this.messagePublicKey = messagePublicKey;
|
||||
this.p2pSigPubKey = p2pSigPubKey;
|
||||
this.direction = direction;
|
||||
this.fiatPrice = fiatPrice;
|
||||
this.amount = amount;
|
||||
@ -221,8 +221,8 @@ public class Offer implements Serializable {
|
||||
return bankAccountUID;
|
||||
}
|
||||
|
||||
public PublicKey getMessagePublicKey() {
|
||||
return messagePublicKey;
|
||||
public PublicKey getP2PSigPubKey() {
|
||||
return p2pSigPubKey;
|
||||
}
|
||||
|
||||
public Date getCreationDate() {
|
||||
@ -250,7 +250,7 @@ public class Offer implements Serializable {
|
||||
checkNotNull(getCurrency(), "Currency is null");
|
||||
checkNotNull(getDirection(), "Direction is null");
|
||||
checkNotNull(getId(), "Id is null");
|
||||
checkNotNull(getMessagePublicKey(), "MessagePublicKey is null");
|
||||
checkNotNull(getP2PSigPubKey(), "p2pSigPubKey is null");
|
||||
checkNotNull(getMinAmount(), "MinAmount is null");
|
||||
checkNotNull(getPrice(), "Price is null");
|
||||
|
||||
@ -277,7 +277,7 @@ public class Offer implements Serializable {
|
||||
", fiatPrice=" + fiatPrice +
|
||||
", amount=" + amount +
|
||||
", minAmount=" + minAmount +
|
||||
", messagePublicKey=" + messagePublicKey +
|
||||
", p2pSigPubKey=" + p2pSigPubKey +
|
||||
", fiatAccountType=" + fiatAccountType +
|
||||
", bankAccountCountry=" + bankAccountCountry +
|
||||
", securityDeposit=" + securityDeposit +
|
||||
|
@ -23,5 +23,5 @@ import io.bitsquare.p2p.listener.GetPeerAddressListener;
|
||||
import java.security.PublicKey;
|
||||
|
||||
public interface AddressService extends DHTService{
|
||||
void findPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener);
|
||||
void findPeerAddress(PublicKey p2pSigPubKey, GetPeerAddressListener getPeerAddressListener);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
package io.bitsquare.p2p;
|
||||
|
||||
import io.bitsquare.crypto.EncryptionService;
|
||||
import io.bitsquare.crypto.EncryptionPackage;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@ -31,13 +31,13 @@ public class EncryptedMailboxMessage implements MailboxMessage, Serializable {
|
||||
private static final long serialVersionUID = -3111178895546299769L;
|
||||
private static final Logger log = LoggerFactory.getLogger(EncryptedMailboxMessage.class);
|
||||
|
||||
private EncryptionService.Tuple tuple;
|
||||
private EncryptionPackage encryptionPackage;
|
||||
|
||||
public EncryptedMailboxMessage(EncryptionService.Tuple tuple) {
|
||||
this.tuple = tuple;
|
||||
public EncryptedMailboxMessage(EncryptionPackage encryptionPackage) {
|
||||
this.encryptionPackage = encryptionPackage;
|
||||
}
|
||||
|
||||
public EncryptionService.Tuple getTuple() {
|
||||
return tuple;
|
||||
public EncryptionPackage getEncryptionPackage() {
|
||||
return encryptionPackage;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -19,14 +19,14 @@ package io.bitsquare.p2p;
|
||||
|
||||
import io.bitsquare.common.handlers.FaultHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.p2p.tomp2p.TomP2PMailboxService;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -20,10 +20,14 @@ package io.bitsquare.p2p;
|
||||
|
||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
public interface MessageService extends P2PService {
|
||||
|
||||
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 removeMessageHandler(MessageHandler listener);
|
||||
|
@ -91,9 +91,9 @@ public class TomP2PAddressService extends TomP2PDHTService implements AddressSer
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void findPeerAddress(PublicKey publicKey, GetPeerAddressListener listener) {
|
||||
final Number160 locationKey = Utils.makeSHAHash(publicKey.getEncoded());
|
||||
FutureGet futureGet = getDataOfProtectedDomain(locationKey, publicKey);
|
||||
public void findPeerAddress(PublicKey p2pSigPubKey, GetPeerAddressListener listener) {
|
||||
final Number160 locationKey = Utils.makeSHAHash(p2pSigPubKey.getEncoded());
|
||||
FutureGet futureGet = getDataOfProtectedDomain(locationKey, p2pSigPubKey);
|
||||
log.trace("findPeerAddress called");
|
||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
|
@ -247,6 +247,18 @@ public class TomP2PDHTService extends TomP2PService implements DHTService {
|
||||
log.trace("getDataFromMapOfMyProtectedDomain");
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import io.bitsquare.common.handlers.FaultHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.offer.OfferBookService;
|
||||
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
||||
import io.bitsquare.p2p.MailboxMessagesResultHandler;
|
||||
import io.bitsquare.p2p.MailboxService;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
@ -49,7 +50,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TomP2PMailboxService extends TomP2PDHTService implements MailboxService {
|
||||
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<>();
|
||||
|
||||
@ -69,14 +70,14 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||
public void addMessage(PublicKey p2pSigPubKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||
try {
|
||||
final Data data = new Data(message);
|
||||
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() + "]");
|
||||
|
||||
FuturePut futurePut = addDataToMapOfProtectedDomain(getLocationKey(publicKey), data, publicKey);
|
||||
FuturePut futurePut = addDataToMapOfProtectedDomain(getLocationKey(p2pSigPubKey), data, p2pSigPubKey);
|
||||
futurePut.addListener(new BaseFutureListener<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
@ -84,7 +85,7 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||
executor.execute(() -> {
|
||||
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 + "]");
|
||||
});
|
||||
}
|
||||
@ -101,41 +102,9 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||
try {
|
||||
final Data data = new Data(message);
|
||||
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));
|
||||
public void getAllMessages(PublicKey p2pSigPubKey, MailboxMessagesResultHandler resultHandler) {
|
||||
log.trace("Get messages from DHT requested for locationKey: " + getLocationKey(p2pSigPubKey));
|
||||
FutureGet futureGet = getDataFromMapOfMyProtectedDomain(getLocationKey(p2pSigPubKey));
|
||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception {
|
||||
@ -156,7 +125,7 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||
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() + "]");
|
||||
}
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private Number160 getLocationKey(PublicKey publicKey) {
|
||||
return Number160.createHash("mailbox" + publicKey.hashCode());
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface MailboxMessagesResultHandler {
|
||||
void handleResult(List<EncryptedMailboxMessage> messages);
|
||||
|
||||
private Number160 getLocationKey(PublicKey p2pSigPubKey) {
|
||||
return Number160.createHash("mailbox" + p2pSigPubKey.hashCode());
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
|
||||
package io.bitsquare.p2p.tomp2p;
|
||||
|
||||
import io.bitsquare.crypto.EncryptionPackage;
|
||||
import io.bitsquare.crypto.EncryptionService;
|
||||
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
||||
import io.bitsquare.p2p.MailboxMessage;
|
||||
@ -28,6 +29,8 @@ import io.bitsquare.p2p.Peer;
|
||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -53,7 +56,7 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public TomP2PMessageService(TomP2PNode tomP2PNode, MailboxService mailboxService, User user, EncryptionService encryptionService) {
|
||||
public TomP2PMessageService(TomP2PNode tomP2PNode, MailboxService mailboxService, User user, EncryptionService<MailboxMessage> encryptionService) {
|
||||
super(tomP2PNode);
|
||||
this.mailboxService = mailboxService;
|
||||
this.user = user;
|
||||
@ -74,6 +77,12 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||
|
||||
@Override
|
||||
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))
|
||||
throw new IllegalArgumentException("Peer must be of type TomP2PPeer");
|
||||
|
||||
@ -86,8 +95,9 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||
executor.execute(listener::handleResult);
|
||||
}
|
||||
else {
|
||||
if (message instanceof MailboxMessage) {
|
||||
sendMailboxMessage((MailboxMessage) message, listener);
|
||||
if (p2pSigPubKey != null && p2pEncryptPubKey != null) {
|
||||
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 {
|
||||
log.error("sendMessage failed with reason " + futureDirect.failedReason());
|
||||
@ -98,8 +108,9 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(Throwable t) throws Exception {
|
||||
if (message instanceof MailboxMessage) {
|
||||
sendMailboxMessage((MailboxMessage) message, listener);
|
||||
if (p2pSigPubKey != null && p2pEncryptPubKey != null) {
|
||||
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 {
|
||||
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) {
|
||||
EncryptionService.Tuple tuple = encryptionService.encryptObject(user.getP2pEncryptKeyPair().getPublic(), message);
|
||||
|
||||
EncryptedMailboxMessage encrypted = new EncryptedMailboxMessage(tuple);
|
||||
mailboxService.addMessage(user.getP2PSigPubKey(), encrypted,
|
||||
private void sendMailboxMessage(PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey, MailboxMessage message, SendMessageListener listener) {
|
||||
EncryptionPackage encryptionPackage = null;
|
||||
try {
|
||||
encryptionPackage = encryptionService.encryptObject(p2pEncryptPubKey, message);
|
||||
} 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.");
|
||||
executor.execute(listener::handleResult);
|
||||
|
@ -40,8 +40,8 @@ public class Contract implements Serializable {
|
||||
private final String takerAccountID;
|
||||
private final FiatAccount offererFiatAccount;
|
||||
private final FiatAccount takerFiatAccount;
|
||||
private final String offererMessagePublicKeyAsString;
|
||||
private final String takerMessagePublicKeyAsString;
|
||||
private final String offererP2PSigPubKeyAsString;
|
||||
private final String takerP2PSigPubKeyAsString;
|
||||
|
||||
public Contract(Offer offer,
|
||||
Coin tradeAmount,
|
||||
@ -50,8 +50,8 @@ public class Contract implements Serializable {
|
||||
String takerAccountID,
|
||||
FiatAccount offererFiatAccount,
|
||||
FiatAccount takerFiatAccount,
|
||||
PublicKey offererMessagePublicKey,
|
||||
PublicKey takerMessagePublicKey) {
|
||||
PublicKey offererP2PSigPubKey,
|
||||
PublicKey takerP2PSigPubKey) {
|
||||
this.offer = offer;
|
||||
this.tradeAmount = tradeAmount;
|
||||
this.takeOfferFeeTxID = takeOfferFeeTxID;
|
||||
@ -59,8 +59,8 @@ public class Contract implements Serializable {
|
||||
this.takerAccountID = takerAccountID;
|
||||
this.offererFiatAccount = offererFiatAccount;
|
||||
this.takerFiatAccount = takerFiatAccount;
|
||||
this.offererMessagePublicKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(offererMessagePublicKey);
|
||||
this.takerMessagePublicKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(takerMessagePublicKey);
|
||||
this.offererP2PSigPubKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(offererP2PSigPubKey);
|
||||
this.takerP2PSigPubKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(takerP2PSigPubKey);
|
||||
}
|
||||
|
||||
|
||||
@ -97,11 +97,11 @@ public class Contract implements Serializable {
|
||||
}
|
||||
|
||||
public String getTakerMessagePublicKey() {
|
||||
return takerMessagePublicKeyAsString;
|
||||
return takerP2PSigPubKeyAsString;
|
||||
}
|
||||
|
||||
public String getOffererMessagePublicKey() {
|
||||
return offererMessagePublicKeyAsString;
|
||||
return offererP2PSigPubKeyAsString;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -114,8 +114,8 @@ public class Contract implements Serializable {
|
||||
", takerAccountID='" + takerAccountID + '\'' +
|
||||
", offererBankAccount=" + offererFiatAccount +
|
||||
", takerBankAccount=" + takerFiatAccount +
|
||||
", takerMessagePublicKeyAsString=" + takerMessagePublicKeyAsString +
|
||||
", offererMessagePublicKeyAsString=" + offererMessagePublicKeyAsString +
|
||||
", takerP2PSigPubKeyAsString=" + takerP2PSigPubKeyAsString +
|
||||
", offererP2PSigPubKeyAsString=" + offererP2PSigPubKeyAsString +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -21,12 +21,15 @@ import io.bitsquare.btc.BlockChainService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.crypto.EncryptionService;
|
||||
import io.bitsquare.crypto.SignatureService;
|
||||
import io.bitsquare.fiat.FiatAccount;
|
||||
import io.bitsquare.offer.Direction;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.offer.OfferBookService;
|
||||
import io.bitsquare.p2p.AddressService;
|
||||
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
||||
import io.bitsquare.p2p.MailboxMessage;
|
||||
import io.bitsquare.p2p.MailboxService;
|
||||
import io.bitsquare.p2p.Message;
|
||||
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.placeoffer.PlaceOfferModel;
|
||||
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.models.BuyerAsOffererModel;
|
||||
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
|
||||
@ -54,6 +58,7 @@ import org.bitcoinj.utils.Fiat;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -78,6 +83,7 @@ public class TradeManager {
|
||||
private final BlockChainService blockChainService;
|
||||
private final WalletService walletService;
|
||||
private final SignatureService signatureService;
|
||||
private EncryptionService<MailboxMessage> encryptionService;
|
||||
private final OfferBookService offerBookService;
|
||||
|
||||
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, Trade> pendingTrades = FXCollections.observableHashMap();
|
||||
private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap();
|
||||
private final Map<String, MailboxMessage> mailboxMessages = new HashMap<>();
|
||||
|
||||
private Trade currentPendingTrade;
|
||||
|
||||
@ -98,7 +105,7 @@ public class TradeManager {
|
||||
@Inject
|
||||
public TradeManager(User user, AccountSettings accountSettings, Persistence persistence,
|
||||
MessageService messageService, MailboxService mailboxService, AddressService addressService, BlockChainService blockChainService,
|
||||
WalletService walletService, SignatureService signatureService,
|
||||
WalletService walletService, SignatureService signatureService, EncryptionService<MailboxMessage> encryptionService,
|
||||
OfferBookService offerBookService) {
|
||||
this.user = user;
|
||||
this.accountSettings = accountSettings;
|
||||
@ -109,6 +116,7 @@ public class TradeManager {
|
||||
this.blockChainService = blockChainService;
|
||||
this.walletService = walletService;
|
||||
this.signatureService = signatureService;
|
||||
this.encryptionService = encryptionService;
|
||||
this.offerBookService = offerBookService;
|
||||
|
||||
Serializable openOffersObject = persistence.read(this, "openOffers");
|
||||
@ -125,10 +133,13 @@ public class TradeManager {
|
||||
if (closedTradesObject instanceof Map<?, ?>) {
|
||||
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
|
||||
// BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early.
|
||||
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) {
|
||||
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,
|
||||
Direction direction,
|
||||
Fiat price,
|
||||
@ -240,6 +235,35 @@ public class TradeManager {
|
||||
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) {
|
||||
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, messageService, addressService);
|
||||
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
|
||||
@ -255,6 +279,138 @@ public class TradeManager {
|
||||
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) {
|
||||
Trade trade = createTrade(offer);
|
||||
trade.setTradeAmount(amount);
|
||||
@ -264,6 +420,19 @@ public class TradeManager {
|
||||
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) {
|
||||
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
|
||||
log.debug("trade state = " + newValue);
|
||||
@ -292,6 +461,7 @@ public class TradeManager {
|
||||
trade,
|
||||
peer,
|
||||
messageService,
|
||||
mailboxService,
|
||||
walletService,
|
||||
blockChainService,
|
||||
signatureService,
|
||||
@ -300,122 +470,13 @@ public class TradeManager {
|
||||
|
||||
SellerAsTakerProtocol sellerTakesOfferProtocol = new SellerAsTakerProtocol(model);
|
||||
sellerAsTakerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
|
||||
|
||||
if (mailboxMessages.containsKey(trade.getId()))
|
||||
sellerTakesOfferProtocol.setMailboxMessage(mailboxMessages.get(trade.getId()));
|
||||
|
||||
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) {
|
||||
Trade trade;
|
||||
@ -482,13 +543,63 @@ public class TradeManager {
|
||||
buyerAcceptsOfferProtocolMap.put(offer.getId(), buyerAcceptsOfferProtocol);
|
||||
}
|
||||
|
||||
private void disposeCheckOfferAvailabilityRequest(Offer offer) {
|
||||
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
||||
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
|
||||
protocol.cancel();
|
||||
protocol.cleanup();
|
||||
checkOfferAvailabilityProtocolMap.remove(offer.getId());
|
||||
private 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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) {
|
||||
@ -498,31 +609,6 @@ public class TradeManager {
|
||||
|| 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() {
|
||||
persistence.write(this, "openOffers", (Map<String, Offer>) new HashMap<>(openOffers));
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
|
||||
@Override
|
||||
protected void doRun() {
|
||||
try {
|
||||
model.addressService.findPeerAddress(model.offer.getMessagePublicKey(), new GetPeerAddressListener() {
|
||||
model.addressService.findPeerAddress(model.offer.getP2PSigPubKey(), new GetPeerAddressListener() {
|
||||
@Override
|
||||
public void onResult(Peer peer) {
|
||||
model.setPeer(peer);
|
||||
|
@ -22,8 +22,10 @@ import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.taskrunner.SharedTaskModel;
|
||||
import io.bitsquare.crypto.SignatureService;
|
||||
import io.bitsquare.p2p.MessageService;
|
||||
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.trade.protocol.trade.messages.TradeMessage;
|
||||
|
||||
@ -39,11 +41,14 @@ public class SharedTradeModel extends SharedTaskModel implements Serializable {
|
||||
// provided
|
||||
transient public final Offer offer;
|
||||
transient public final MessageService messageService;
|
||||
transient public final MailboxService mailboxService;
|
||||
transient public final WalletService walletService;
|
||||
transient public final BlockChainService blockChainService;
|
||||
transient public final SignatureService signatureService;
|
||||
transient protected final Persistence persistence;
|
||||
|
||||
transient public MailboxMessage mailboxMessage;
|
||||
|
||||
// derived
|
||||
transient public final String id;
|
||||
transient public final TradeWalletService tradeWalletService;
|
||||
@ -54,12 +59,14 @@ public class SharedTradeModel extends SharedTaskModel implements Serializable {
|
||||
|
||||
protected SharedTradeModel(Offer offer,
|
||||
MessageService messageService,
|
||||
MailboxService mailboxService,
|
||||
WalletService walletService,
|
||||
BlockChainService blockChainService,
|
||||
SignatureService signatureService,
|
||||
Persistence persistence) {
|
||||
this.offer = offer;
|
||||
this.messageService = messageService;
|
||||
this.mailboxService = mailboxService;
|
||||
this.walletService = walletService;
|
||||
this.blockChainService = blockChainService;
|
||||
this.signatureService = signatureService;
|
||||
|
@ -23,7 +23,7 @@ import org.bitcoinj.core.Coin;
|
||||
|
||||
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;
|
||||
|
||||
public final byte[] offererSignature;
|
||||
@ -31,7 +31,7 @@ public class BankTransferStartedMessage extends TradeMessage implements MailboxM
|
||||
public final Coin takerPayoutAmount;
|
||||
public final String offererPayoutAddress;
|
||||
|
||||
public BankTransferStartedMessage(String tradeId,
|
||||
public FiatTransferStartedMessage(String tradeId,
|
||||
byte[] offererSignature,
|
||||
Coin offererPayoutAmount,
|
||||
Coin takerPayoutAmount,
|
@ -33,7 +33,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
|
||||
|
||||
public final FiatAccount takerFiatAccount;
|
||||
public final String takerAccountId;
|
||||
public final PublicKey takerMessagePublicKey;
|
||||
public final PublicKey takerP2PSigPublicKey;
|
||||
public final PublicKey takerP2PEncryptPublicKey;
|
||||
public final String takerContractAsJson;
|
||||
public final String takerContractSignature;
|
||||
public final String takerPayoutAddressString;
|
||||
@ -44,7 +45,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
|
||||
public RequestOffererPublishDepositTxMessage(String tradeId,
|
||||
FiatAccount takerFiatAccount,
|
||||
String takerAccountId,
|
||||
PublicKey takerMessagePublicKey,
|
||||
PublicKey takerP2PSigPublicKey,
|
||||
PublicKey takerP2PEncryptPublicKey,
|
||||
String takerContractAsJson,
|
||||
String takerContractSignature,
|
||||
String takerPayoutAddressString,
|
||||
@ -54,7 +56,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
|
||||
this.tradeId = tradeId;
|
||||
this.takerFiatAccount = takerFiatAccount;
|
||||
this.takerAccountId = takerAccountId;
|
||||
this.takerMessagePublicKey = takerMessagePublicKey;
|
||||
this.takerP2PSigPublicKey = takerP2PSigPublicKey;
|
||||
this.takerP2PEncryptPublicKey = takerP2PEncryptPublicKey;
|
||||
this.takerContractAsJson = takerContractAsJson;
|
||||
this.takerContractSignature = takerContractSignature;
|
||||
this.takerPayoutAddressString = takerPayoutAddressString;
|
||||
|
@ -37,7 +37,6 @@ public class BuyerAsOffererModel extends SharedTradeModel implements Serializabl
|
||||
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererModel.class);
|
||||
|
||||
transient public final Trade trade;
|
||||
transient public final MailboxService mailboxService;
|
||||
public final TakerModel taker;
|
||||
public final OffererModel offerer;
|
||||
|
||||
@ -54,13 +53,13 @@ public class BuyerAsOffererModel extends SharedTradeModel implements Serializabl
|
||||
Persistence persistence) {
|
||||
super(trade.getOffer(),
|
||||
messageService,
|
||||
mailboxService,
|
||||
walletService,
|
||||
blockChainService,
|
||||
signatureService,
|
||||
persistence);
|
||||
|
||||
this.trade = trade;
|
||||
this.mailboxService = mailboxService;
|
||||
|
||||
Serializable serializable = persistence.read(this, "BuyerAsOffererModel_" + id);
|
||||
if (serializable instanceof BuyerAsOffererModel) {
|
||||
|
@ -38,6 +38,7 @@ public class TakerModel implements Serializable {
|
||||
public String accountId;
|
||||
public FiatAccount fiatAccount;
|
||||
public PublicKey p2pSigPublicKey;
|
||||
public PublicKey p2pEncryptPubKey;
|
||||
public String contractAsJson;//TODO only write access now, missing impl.
|
||||
public String contractSignature;
|
||||
public Coin payoutAmount;
|
||||
|
@ -43,7 +43,8 @@ public class ProcessRequestOffererPublishDepositTxMessage extends Task<BuyerAsOf
|
||||
|
||||
model.taker.fiatAccount = checkNotNull(message.takerFiatAccount);
|
||||
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.contractSignature = nonEmptyStringOf(message.takerContractSignature);
|
||||
model.taker.payoutAddressString = nonEmptyStringOf(message.takerPayoutAddressString);
|
||||
|
@ -20,7 +20,8 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
|
||||
import io.bitsquare.common.taskrunner.Task;
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
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 org.slf4j.Logger;
|
||||
@ -36,26 +37,32 @@ public class SendBankTransferStartedMessage extends Task<BuyerAsOffererModel> {
|
||||
@Override
|
||||
protected void doRun() {
|
||||
try {
|
||||
BankTransferStartedMessage tradeMessage = new BankTransferStartedMessage(
|
||||
model.id,
|
||||
FiatTransferStartedMessage tradeMessage = new FiatTransferStartedMessage(model.id,
|
||||
model.offerer.payoutTxSignature,
|
||||
model.offerer.payoutAmount,
|
||||
model.taker.payoutAmount,
|
||||
model.offerer.addressEntry.getAddressString());
|
||||
model.messageService.sendMessage(model.taker.peer, tradeMessage, new SendMessageListener() {
|
||||
@Override
|
||||
public void handleResult() {
|
||||
log.trace("Sending BankTransferInitedMessage succeeded.");
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFault() {
|
||||
failed("Sending BankTransferInitedMessage failed.");
|
||||
}
|
||||
});
|
||||
model.messageService.sendMessage(model.taker.peer, tradeMessage,
|
||||
model.taker.p2pSigPublicKey,
|
||||
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) {
|
||||
failed("Sending BankTransferInitedMessage failed.");
|
||||
model.trade.setState(Trade.State.FAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,20 +18,21 @@
|
||||
package io.bitsquare.trade.protocol.trade.taker;
|
||||
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.p2p.MailboxMessage;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.MessageHandler;
|
||||
import io.bitsquare.p2p.Peer;
|
||||
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.FiatTransferStartedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.RequestDepositPaymentMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||
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.CreateAndSignContract;
|
||||
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.ProcessFiatTransferStartedMessage;
|
||||
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.SendRequestDepositTxInputsMessage;
|
||||
@ -70,6 +71,8 @@ public class SellerAsTakerProtocol {
|
||||
this.model = model;
|
||||
messageHandler = this::handleMessage;
|
||||
model.messageService.addMessageHandler(messageHandler);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -82,6 +85,17 @@ public class SellerAsTakerProtocol {
|
||||
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() {
|
||||
TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model,
|
||||
() -> {
|
||||
@ -99,7 +113,7 @@ public class SellerAsTakerProtocol {
|
||||
taskRunner.run();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Incoming message handling
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -143,19 +157,19 @@ public class SellerAsTakerProtocol {
|
||||
taskRunner.run();
|
||||
}
|
||||
|
||||
private void handleBankTransferStartedMessage(BankTransferStartedMessage tradeMessage) {
|
||||
private void handleFiatTransferStartedMessage(FiatTransferStartedMessage tradeMessage) {
|
||||
model.setTradeMessage(tradeMessage);
|
||||
|
||||
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);
|
||||
},
|
||||
(errorMessage) -> {
|
||||
log.error(errorMessage);
|
||||
}
|
||||
);
|
||||
taskRunner.addTasks(ProcessBankTransferStartedMessage.class);
|
||||
taskRunner.addTasks(ProcessFiatTransferStartedMessage.class);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
||||
@ -201,8 +215,8 @@ public class SellerAsTakerProtocol {
|
||||
else if (tradeMessage instanceof DepositTxPublishedMessage) {
|
||||
handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
|
||||
}
|
||||
else if (tradeMessage instanceof BankTransferStartedMessage) {
|
||||
handleBankTransferStartedMessage((BankTransferStartedMessage) tradeMessage);
|
||||
else if (tradeMessage instanceof FiatTransferStartedMessage) {
|
||||
handleFiatTransferStartedMessage((FiatTransferStartedMessage) tradeMessage);
|
||||
}
|
||||
else {
|
||||
log.error("Incoming message not supported. " + tradeMessage);
|
||||
|
@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.models;
|
||||
import io.bitsquare.btc.BlockChainService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.crypto.SignatureService;
|
||||
import io.bitsquare.p2p.MailboxService;
|
||||
import io.bitsquare.p2p.MessageService;
|
||||
import io.bitsquare.p2p.Peer;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
@ -49,6 +50,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||
public SellerAsTakerModel(Trade trade,
|
||||
Peer offererPeer,
|
||||
MessageService messageService,
|
||||
MailboxService mailboxService,
|
||||
WalletService walletService,
|
||||
BlockChainService blockChainService,
|
||||
SignatureService signatureService,
|
||||
@ -56,6 +58,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||
Persistence persistence) {
|
||||
super(trade.getOffer(),
|
||||
messageService,
|
||||
mailboxService,
|
||||
walletService,
|
||||
blockChainService,
|
||||
signatureService,
|
||||
@ -87,6 +90,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||
taker.fiatAccount = user.getBankAccount(offer.getBankAccountId());
|
||||
taker.accountId = user.getAccountId();
|
||||
taker.p2pSigPubKey = user.getP2PSigPubKey();
|
||||
taker.p2pEncryptPublicKey = user.getP2PEncryptPubKey();
|
||||
taker.pubKey = taker.addressEntry.getPubKey();
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ public class TakerModel implements Serializable {
|
||||
transient public FiatAccount fiatAccount;
|
||||
transient public String accountId;
|
||||
transient public PublicKey p2pSigPubKey;
|
||||
transient public PublicKey p2pEncryptPublicKey;
|
||||
transient public byte[] registrationPubKey; // TODO not read yet, missing impl.
|
||||
transient public DeterministicKey registrationKeyPair;
|
||||
transient public AddressEntry addressEntry;
|
||||
|
@ -45,7 +45,7 @@ public class CreateAndSignContract extends Task<SellerAsTakerModel> {
|
||||
model.taker.accountId,
|
||||
model.offerer.fiatAccount,
|
||||
model.taker.fiatAccount,
|
||||
model.offer.getMessagePublicKey(),
|
||||
model.offer.getP2PSigPubKey(),
|
||||
model.taker.p2pSigPubKey);
|
||||
String contractAsJson = Utilities.objectToJson(contract);
|
||||
String signature = model.signatureService.signMessage(model.taker.registrationKeyPair, contractAsJson);
|
||||
|
@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
|
||||
|
||||
import io.bitsquare.common.taskrunner.Task;
|
||||
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 org.slf4j.Logger;
|
||||
@ -28,10 +28,10 @@ import org.slf4j.LoggerFactory;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.bitsquare.util.Validator.*;
|
||||
|
||||
public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel> {
|
||||
private static final Logger log = LoggerFactory.getLogger(ProcessBankTransferStartedMessage.class);
|
||||
public class ProcessFiatTransferStartedMessage extends Task<SellerAsTakerModel> {
|
||||
private static final Logger log = LoggerFactory.getLogger(ProcessFiatTransferStartedMessage.class);
|
||||
|
||||
public ProcessBankTransferStartedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
|
||||
public ProcessFiatTransferStartedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
|
||||
super(taskHandler, model);
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel>
|
||||
protected void doRun() {
|
||||
try {
|
||||
checkTradeId(model.id, model.getTradeMessage());
|
||||
BankTransferStartedMessage message = (BankTransferStartedMessage) model.getTradeMessage();
|
||||
FiatTransferStartedMessage message = (FiatTransferStartedMessage) model.getTradeMessage();
|
||||
|
||||
model.offerer.signature = checkNotNull(message.offererSignature);
|
||||
model.offerer.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount));
|
@ -40,6 +40,7 @@ public class SendSignedTakerDepositTx extends Task<SellerAsTakerModel> {
|
||||
model.taker.fiatAccount,
|
||||
model.taker.accountId,
|
||||
model.taker.p2pSigPubKey,
|
||||
model.taker.p2pEncryptPublicKey,
|
||||
model.trade.getContractAsJson(),
|
||||
model.trade.getTakerContractSignature(),
|
||||
model.taker.addressEntry.getAddressString(),
|
||||
|
@ -24,6 +24,8 @@ import io.bitsquare.util.DSAKeyUtil;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -39,12 +41,16 @@ import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The User is persisted locally.
|
||||
* It must never be transmitted over the wire (messageKeyPair contains private key!).
|
||||
*/
|
||||
public class User implements Serializable {
|
||||
private static final long serialVersionUID = 7409078808248518638L;
|
||||
private static final Logger log = LoggerFactory.getLogger(User.class);
|
||||
|
||||
private KeyPair p2pSigKeyPair;
|
||||
private KeyPair p2pEncryptKeyPair;
|
||||
@ -87,8 +93,13 @@ public class User implements Serializable {
|
||||
}
|
||||
else {
|
||||
// First time
|
||||
p2pSigKeyPair = DSAKeyUtil.generateKeyPair();
|
||||
p2pEncryptKeyPair = encryptionService.getKeyPair();
|
||||
p2pSigKeyPair = DSAKeyUtil.generateDSAKeyPair();
|
||||
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();
|
||||
}
|
||||
|
||||
public PublicKey getP2PEncryptPubKey() {
|
||||
return p2pEncryptKeyPair.getPublic();
|
||||
}
|
||||
|
||||
public ObjectProperty<FiatAccount> currentBankAccountProperty() {
|
||||
return currentBankAccount;
|
||||
}
|
||||
@ -192,7 +207,11 @@ public class User implements Serializable {
|
||||
return _currentFiatAccount;
|
||||
}
|
||||
|
||||
public KeyPair getP2pEncryptKeyPair() {
|
||||
public PrivateKey getP2pEncryptPrivateKey() {
|
||||
return p2pEncryptKeyPair.getPrivate();
|
||||
}
|
||||
|
||||
KeyPair getP2pEncryptKeyPair() {
|
||||
return p2pEncryptKeyPair;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public class DSAKeyUtil {
|
||||
return Utils.HEX.encode(x509EncodedKeySpec.getEncoded());
|
||||
}
|
||||
|
||||
public static KeyPair generateKeyPair() {
|
||||
public static KeyPair generateDSAKeyPair() {
|
||||
try {
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
|
||||
keyGen.initialize(1024);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -296,7 +296,7 @@ public class PlaceOfferProtocolTest {
|
||||
|
||||
private Offer getOffer() {
|
||||
return new Offer(OFFER_ID,
|
||||
DSAKeyUtil.generateKeyPair().getPublic(),
|
||||
DSAKeyUtil.generateDSAKeyPair().getPublic(),
|
||||
Direction.BUY,
|
||||
100L,
|
||||
Coin.CENT,
|
||||
|
Loading…
x
Reference in New Issue
Block a user