diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index 6f057ca2ec..0dd5217de8 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -21,6 +21,8 @@ import bisq.core.api.model.PaymentAccountForm; import bisq.core.api.model.TxFeeRateInfo; import bisq.core.proto.CoreProtoResolver; +import bisq.common.util.Utilities; + import bisq.proto.grpc.AddressBalanceInfo; import bisq.proto.grpc.BalancesInfo; import bisq.proto.grpc.BsqBalanceInfo; @@ -57,8 +59,6 @@ import bisq.proto.grpc.WithdrawFundsRequest; import protobuf.PaymentAccount; import protobuf.PaymentMethod; -import java.nio.charset.StandardCharsets; - import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -70,6 +70,7 @@ import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static bisq.apitest.config.BisqAppConfig.arbdaemon; import static bisq.apitest.config.BisqAppConfig.bobdaemon; import static bisq.common.app.DevEnv.DEV_PRIVILEGE_PRIV_KEY; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.stream; import static java.util.Comparator.comparing; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -278,7 +279,7 @@ public class MethodTest extends ApiTestCase { .getPaymentAccountFormJson(); // Write the json string to a file here in the test case. File jsonFile = PaymentAccountForm.getTmpJsonFile(paymentMethodId); - try (PrintWriter out = new PrintWriter(jsonFile, StandardCharsets.UTF_8)) { + try (PrintWriter out = new PrintWriter(jsonFile, UTF_8)) { out.println(jsonString); } catch (IOException ex) { fail("Could not create tmp payment account form.", ex); @@ -393,6 +394,10 @@ public class MethodTest extends ApiTestCase { disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(REFUND_AGENT)); } + protected static String encodeToHex(String s) { + return Utilities.bytesAsHexString(s.getBytes(UTF_8)); + } + private bisq.core.payment.PaymentAccount fromProto(PaymentAccount proto) { return bisq.core.payment.PaymentAccount.fromProto(proto, CORE_PROTO_RESOLVER); } diff --git a/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java b/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java index 913ddad30c..e83bfe6db7 100644 --- a/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java +++ b/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java @@ -18,6 +18,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,8 +42,12 @@ import bisq.apitest.method.MethodTest; @Slf4j public class AbstractPaymentAccountTest extends MethodTest { - static final String PROPERTY_NAME_COMMENT = "_COMMENT_"; - static final String PROPERTY_VALUE_COMMENT = "Do not manually edit the paymentMethodId field."; + static final String PROPERTY_NAME_JSON_COMMENTS = "_COMMENTS_"; + static final List PROPERTY_VALUE_JSON_COMMENTS = new ArrayList<>() {{ + add("Do not manually edit the paymentMethodId field."); + add("Edit the salt field only if you are recreating a payment" + + " account on a new installation and wish to preserve the account age."); + }}; static final String PROPERTY_NAME_PAYMENT_METHOD_ID = "paymentMethodId"; @@ -79,6 +84,7 @@ public class AbstractPaymentAccountTest extends MethodTest { static final String PROPERTY_NAME_PROMPT_PAY_ID = "promptPayId"; static final String PROPERTY_NAME_QUESTION = "question"; static final String PROPERTY_NAME_REQUIREMENTS = "requirements"; + static final String PROPERTY_NAME_SALT = "salt"; static final String PROPERTY_NAME_SORT_CODE = "sortCode"; static final String PROPERTY_NAME_STATE = "state"; static final String PROPERTY_NAME_USERNAME = "userName"; @@ -107,8 +113,10 @@ public class AbstractPaymentAccountTest extends MethodTest { File emptyForm = getPaymentAccountForm(alicedaemon, paymentMethodId); // A short cut over the API: // File emptyForm = PAYMENT_ACCOUNT_FORM.getPaymentAccountForm(paymentMethodId); + log.debug("{} Empty form saved to {}", + testName(testInfo), + PAYMENT_ACCOUNT_FORM.getClickableURI(emptyForm)); emptyForm.deleteOnExit(); - log.debug("{} Empty form saved to {}", testName(testInfo), PAYMENT_ACCOUNT_FORM.getClickableURI(emptyForm)); return emptyForm; } @@ -118,11 +126,11 @@ public class AbstractPaymentAccountTest extends MethodTest { PAYMENT_ACCOUNT_FORM.toJsonString(jsonForm), Object.class); assertNotNull(emptyForm); - assertEquals(PROPERTY_VALUE_COMMENT, emptyForm.get(PROPERTY_NAME_COMMENT)); + assertEquals(PROPERTY_VALUE_JSON_COMMENTS, emptyForm.get(PROPERTY_NAME_JSON_COMMENTS)); assertEquals(paymentMethodId, emptyForm.get(PROPERTY_NAME_PAYMENT_METHOD_ID)); - assertEquals("Your accountname", emptyForm.get(PROPERTY_NAME_ACCOUNT_NAME)); + assertEquals("your accountname", emptyForm.get(PROPERTY_NAME_ACCOUNT_NAME)); for (String field : fields) { - assertEquals("Your " + field.toLowerCase(), emptyForm.get(field)); + assertEquals("your " + field.toLowerCase(), emptyForm.get(field)); } } @@ -171,8 +179,14 @@ public class AbstractPaymentAccountTest extends MethodTest { tmpJsonForm.deleteOnExit(); JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(tmpJsonForm), UTF_8)); writer.beginObject(); - writer.name(PROPERTY_NAME_COMMENT); - writer.value(PROPERTY_VALUE_COMMENT); + + writer.name(PROPERTY_NAME_JSON_COMMENTS); + writer.beginArray(); + for (String s : PROPERTY_VALUE_JSON_COMMENTS) { + writer.value(s); + } + writer.endArray(); + for (Map.Entry entry : COMPLETED_FORM_MAP.entrySet()) { String k = entry.getKey(); Object v = entry.getValue(); @@ -187,5 +201,4 @@ public class AbstractPaymentAccountTest extends MethodTest { } return tmpJsonForm; } - } diff --git a/apitest/src/test/java/bisq/apitest/method/payment/CreatePaymentAccountTest.java b/apitest/src/test/java/bisq/apitest/method/payment/CreatePaymentAccountTest.java index 77955b5ef7..9795eec28c 100644 --- a/apitest/src/test/java/bisq/apitest/method/payment/CreatePaymentAccountTest.java +++ b/apitest/src/test/java/bisq/apitest/method/payment/CreatePaymentAccountTest.java @@ -94,12 +94,14 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, ADVANCED_CASH_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Advanced Cash Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NR, "0000 1111 2222"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Advanced Cash Acct Salt")); String jsonString = getCompletedFormAsJsonString(); AdvancedCashAccount paymentAccount = (AdvancedCashAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); verifyAccountTradeCurrencies(getAllAdvancedCashCurrencies(), paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -112,6 +114,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, ALI_PAY_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Ali Pay Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NR, "2222 3333 4444"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); AliPayAccount paymentAccount = (AliPayAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -128,9 +131,10 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { AUSTRALIA_PAYID_ID, PROPERTY_NAME_BANK_ACCOUNT_NAME); COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, AUSTRALIA_PAYID_ID); - COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Australia Pay ID Account"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Australia Pay ID Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAY_ID, "123 456 789"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_BANK_ACCOUNT_NAME, "Credit Union Australia"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Australia Pay ID Acct Salt")); String jsonString = getCompletedFormAsJsonString(); AustraliaPayid paymentAccount = (AustraliaPayid) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -138,6 +142,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_PAY_ID), paymentAccount.getPayid()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BANK_ACCOUNT_NAME), paymentAccount.getBankAccountName()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -170,6 +175,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_TAX_ID, "123456789"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_NATIONAL_ACCOUNT_ID, "123456789"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_REQUIREMENTS, "Requirements..."); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); CashDepositAccount paymentAccount = (CashDepositAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -215,6 +221,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Joao da Silva"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_TAX_ID, "123456789"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_NATIONAL_ACCOUNT_ID, "123456789"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Banco do Brasil Acct Salt")); String jsonString = getCompletedFormAsJsonString(); NationalBankAccount paymentAccount = (NationalBankAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -232,6 +239,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), payload.getHolderName()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_TAX_ID), payload.getHolderTaxId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_NATIONAL_ACCOUNT_ID), payload.getNationalAccountId()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -246,6 +254,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Quick Pay Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "johndoe@quickpay.com"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "John Doe"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); ChaseQuickPayAccount paymentAccount = (ChaseQuickPayAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -264,9 +273,10 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { PROPERTY_NAME_EMAIL_OR_MOBILE_NR, PROPERTY_NAME_HOLDER_NAME); COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, CLEAR_X_CHANGE_ID); - COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "USD Zelle Account"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "USD Zelle Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL_OR_MOBILE_NR, "jane@doe.com"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Jane Doe"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Zelle Acct Salt")); String jsonString = getCompletedFormAsJsonString(); ClearXchangeAccount paymentAccount = (ClearXchangeAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -274,6 +284,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_EMAIL_OR_MOBILE_NR), paymentAccount.getEmailOrMobileNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -292,6 +303,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_CITY, "Rio de Janeiro"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_CONTACT, "Freddy Beira Mar"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_EXTRA_INFO, "So fim de semana"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); F2FAccount paymentAccount = (F2FAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -316,6 +328,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Faster Payments Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NR, "9999 8888 7777"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_SORT_CODE, "3127"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Faster Payments Acct Salt")); String jsonString = getCompletedFormAsJsonString(); FasterPaymentsAccount paymentAccount = (FasterPaymentsAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -323,6 +336,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SORT_CODE), paymentAccount.getSortCode()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -335,6 +349,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, HAL_CASH_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Hal Cash Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_MOBILE_NR, "798 123 456"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); HalCashAccount paymentAccount = (HalCashAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -359,6 +374,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "john@doe.info"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_QUESTION, "What is my dog's name?"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ANSWER, "Fido"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Interac Transfer Acct Salt")); String jsonString = getCompletedFormAsJsonString(); InteracETransferAccount paymentAccount = (InteracETransferAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -368,6 +384,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_EMAIL), paymentAccount.getEmail()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_QUESTION), paymentAccount.getQuestion()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ANSWER), paymentAccount.getAnswer()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -392,6 +409,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_BANK_ACCOUNT_NAME, "Fukuoka Account"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_BANK_ACCOUNT_TYPE, "Yen Account"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_BANK_ACCOUNT_NUMBER, "8100-8727-0000"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); JapanBankAccount paymentAccount = (JapanBankAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -416,12 +434,14 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, MONEY_BEAM_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Money Beam Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_ID, "MB 0000 1111"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Money Beam Acct Salt")); String jsonString = getCompletedFormAsJsonString(); MoneyBeamAccount paymentAccount = (MoneyBeamAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); verifyAccountSingleTradeCurrency("EUR", paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_ID), paymentAccount.getAccountId()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -440,6 +460,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "john@doe.info"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_COUNTRY, "US"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_STATE, "NY"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); MoneyGramAccount paymentAccount = (MoneyGramAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -462,12 +483,14 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, PERFECT_MONEY_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Perfect Money Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NR, "PM 0000 1111"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Perfect Money Acct Salt")); String jsonString = getCompletedFormAsJsonString(); PerfectMoneyAccount paymentAccount = (PerfectMoneyAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); verifyAccountSingleTradeCurrency("USD", paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -482,6 +505,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Pop Money Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_ID, "POPMONEY 0000 1111"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Jane Doe"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); PopmoneyAccount paymentAccount = (PopmoneyAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -501,12 +525,14 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, PROMPT_PAY_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Prompt Pay Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_PROMPT_PAY_ID, "PP 0000 1111"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Prompt Pay Acct Salt")); String jsonString = getCompletedFormAsJsonString(); PromptPayAccount paymentAccount = (PromptPayAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); verifyAccountSingleTradeCurrency("THB", paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_PROMPT_PAY_ID), paymentAccount.getPromptPayId()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -519,6 +545,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, REVOLUT_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Revolut Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_USERNAME, "revolut123"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); RevolutAccount paymentAccount = (RevolutAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -551,6 +578,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Jane Doe"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_TAX_ID, "123456789"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_NATIONAL_ACCOUNT_ID, "123456789"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Same Bank Acct Salt")); String jsonString = getCompletedFormAsJsonString(); SameBankAccount paymentAccount = (SameBankAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -568,6 +596,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), payload.getHolderName()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_TAX_ID), payload.getHolderTaxId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_NATIONAL_ACCOUNT_ID), payload.getNationalAccountId()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -586,6 +615,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Jose da Silva"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_IBAN, "909-909"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_BIC, "909"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); SepaInstantAccount paymentAccount = (SepaInstantAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -616,6 +646,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Jose da Silva"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_IBAN, "909-909"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_BIC, "909"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Conta Sepa Salt")); String jsonString = getCompletedFormAsJsonString(); SepaAccount paymentAccount = (SepaAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -628,6 +659,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BIC), paymentAccount.getBic()); // bankId == bic assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BIC), paymentAccount.getBankId()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -657,6 +689,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Jane Doe"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_TAX_ID, "123456789"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_NATIONAL_ACCOUNT_ID, "123456789"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); SpecificBanksAccount paymentAccount = (SpecificBanksAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -685,9 +718,10 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { PROPERTY_NAME_MOBILE_NR, PROPERTY_NAME_HOLDER_NAME); COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, SWISH_ID); - COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Swish Account"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Swish Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_MOBILE_NR, "+46 7 6060 0101"); - COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Swish Account Holder"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Swish Acct Holder"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Swish Acct Salt")); String jsonString = getCompletedFormAsJsonString(); SwishAccount paymentAccount = (SwishAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -695,6 +729,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_MOBILE_NR), paymentAccount.getMobileNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -707,6 +742,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, TRANSFERWISE_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Transferwise Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "jan@doe.info"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); TransferwiseAccount paymentAccount = (TransferwiseAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -725,12 +761,14 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, UPHOLD_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Uphold Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_ID, "UA 9876"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored Uphold Acct Salt")); String jsonString = getCompletedFormAsJsonString(); UpholdAccount paymentAccount = (UpholdAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); verifyAccountTradeCurrencies(getAllUpholdCurrencies(), paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_ID), paymentAccount.getAccountId()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -745,6 +783,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Bubba's Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_HOLDER_NAME, "Bubba"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_POSTAL_ADDRESS, "000 Westwood Terrace Austin, TX 78700"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); USPostalMoneyOrderAccount paymentAccount = (USPostalMoneyOrderAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); @@ -764,12 +803,14 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, WECHAT_PAY_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "WeChat Pay Acct"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NR, "WC 1234"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, encodeToHex("Restored WeChat Pay Acct Salt")); String jsonString = getCompletedFormAsJsonString(); WeChatPayAccount paymentAccount = (WeChatPayAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); verifyAccountSingleTradeCurrency("CNY", paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); } @@ -790,6 +831,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { COMPLETED_FORM_MAP.put(PROPERTY_NAME_STATE, "North Dakota"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_COUNTRY, "US"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "jane@doe.info"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); WesternUnionAccount paymentAccount = (WesternUnionAccount) createPaymentAccount(alicedaemon, jsonString); verifyUserPayloadHasPaymentAccountWithId(paymentAccount.getId()); diff --git a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java index 8496d426be..dae437d265 100644 --- a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java +++ b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java @@ -71,10 +71,14 @@ import static java.nio.charset.StandardCharsets.UTF_8; * get the json Hal Cash payment account form: *
  * {
- *   "_COMMENT_": "Do not manually edit the paymentMethodId field.",
+ *   "_COMMENTS_": [
+ *     "Do not manually edit the paymentMethodId field.",
+ *     "Edit the salt field only if you are recreating a payment account on a new installation and wish to preserve the account age."
+ *   ],
  *   "paymentMethodId": "HAL_CASH",
  *   "accountName": "Your accountname",
  *   "mobileNr": "Your mobilenr"
+ *   "salt": ""
  * }
  * 
*

@@ -82,10 +86,14 @@ import static java.nio.charset.StandardCharsets.UTF_8; * (2) Save the Hal Cash payment account form to disk, and edit it: *
  * {
- *   "_COMMENT_": "Do not manually edit the paymentMethodId field.",
+ *   "_COMMENTS_": [
+ *     "Do not manually edit the paymentMethodId field.",
+ *     "Edit the salt field only if you are recreating a payment account on a new installation and wish to preserve the account age."
+ *   ],
  *   "paymentMethodId": "HAL_CASH",
  *   "accountName": "Hal Cash Acct",
  *   "mobileNr": "798 123 456"
+ *   "salt": ""
  * }
  * 
*

@@ -115,7 +123,7 @@ public class PaymentAccountForm { .setPrettyPrinting() .serializeNulls(); - // Names of PaymentAccount fields to exclude from json forms. + // A list of PaymentAccount fields to exclude from json forms. private final String[] excludedFields = new String[]{ "log", "id", @@ -126,11 +134,11 @@ public class PaymentAccountForm { "maxTradePeriod", "paymentAccountPayload", "paymentMethod", - "paymentMethodId", + "paymentMethodId", // This field will be included, but handled differently. "selectedTradeCurrency", "tradeCurrencies", "HOLDER_NAME", - "SALT" + "SALT" // This field will be included, but handled differently. }; /** diff --git a/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java b/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java index 66b0d2cf03..f49809a50c 100644 --- a/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java +++ b/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java @@ -54,6 +54,7 @@ import static bisq.common.util.ReflectionUtils.getSetterMethodForFieldInClassHie import static bisq.common.util.ReflectionUtils.getVisibilityModifierAsString; import static bisq.common.util.ReflectionUtils.isSetterOnClass; import static bisq.common.util.ReflectionUtils.loadFieldListForClassHierarchy; +import static bisq.common.util.Utilities.decodeFromHex; import static bisq.core.locale.CountryUtil.findCountryByCode; import static bisq.core.locale.CurrencyUtil.getCurrencyByCountryCode; import static com.google.common.base.Preconditions.checkNotNull; @@ -63,6 +64,12 @@ import static java.util.Comparator.comparing; @Slf4j class PaymentAccountTypeAdapter extends TypeAdapter { + private static final String[] JSON_COMMENTS = new String[]{ + "Do not manually edit the paymentMethodId field.", + "Edit the salt field only if you are recreating a payment" + + " account on a new installation and wish to preserve the account age." + }; + private final Class paymentAccountType; private final Class paymentAccountPayloadType; private final Map> fieldSettersMap; @@ -97,9 +104,30 @@ class PaymentAccountTypeAdapter extends TypeAdapter { public void write(JsonWriter out, PaymentAccount account) throws IOException { // We write a blank payment acct form for a payment method id. // We're not serializing a real payment account instance here. - log.debug("Writing PaymentAccount json form for fields with accessors..."); out.beginObject(); - writeCommonFields(out, account); + + // All json forms start with immutable _COMMENTS_ and paymentMethodId fields. + out.name("_COMMENTS_"); + out.beginArray(); + for (String s : JSON_COMMENTS) { + out.value(s); + } + out.endArray(); + + out.name("paymentMethodId"); + out.value(account.getPaymentMethod().getId()); + + // Write the editable, PaymentAccount subclass specific fields. + writeInnerMutableFields(out, account); + + // The last field in all json forms is the empty, editable salt field. + out.name("salt"); + out.value(""); + + out.endObject(); + } + + private void writeInnerMutableFields(JsonWriter out, PaymentAccount account) { fieldSettersMap.forEach((field, value) -> { try { // Write out a json element if there is a @Setter for this field. @@ -112,7 +140,7 @@ class PaymentAccountTypeAdapter extends TypeAdapter { String fieldName = field.getName(); out.name(fieldName); - out.value("Your " + fieldName.toLowerCase()); + out.value("your " + fieldName.toLowerCase()); } } catch (Exception ex) { String errMsg = format("cannot create a new %s json form", @@ -121,13 +149,10 @@ class PaymentAccountTypeAdapter extends TypeAdapter { throw new IllegalStateException("programmer error: " + errMsg); } }); - out.endObject(); - log.debug("Done writing PaymentAccount json form."); } @Override public PaymentAccount read(JsonReader in) throws IOException { - log.debug("De-serializing json to new {} ...", paymentAccountType.getSimpleName()); PaymentAccount account = initNewPaymentAccount(); in.beginObject(); while (in.hasNext()) { @@ -155,7 +180,6 @@ class PaymentAccountTypeAdapter extends TypeAdapter { }); } in.endObject(); - log.debug("Done de-serializing json."); return account; } @@ -250,27 +274,27 @@ class PaymentAccountTypeAdapter extends TypeAdapter { } } - private void writeCommonFields(JsonWriter out, PaymentAccount account) throws IOException { - log.debug("writeCommonFields(out, {}) -> paymentMethodId = {}", - account, account.getPaymentMethod().getId()); - - out.name("_COMMENT_"); - out.value("Do not manually edit the paymentMethodId field."); - - out.name("paymentMethodId"); - out.value(account.getPaymentMethod().getId()); - } - - private boolean didReadCommonField(JsonReader in, PaymentAccount account, String fieldName) { + private boolean didReadCommonField(JsonReader in, + PaymentAccount account, + String fieldName) throws IOException { switch (fieldName) { - case "_COMMENT_": + case "_COMMENTS_": case "paymentMethodId": - // skip - nextStringOrNull(in); + // Skip over the the comments and paymentMethodId, which is already + // set on the PaymentAccount instance. + in.skipValue(); return true; case "accountName": + // Set the acct name using the value read from json. account.setAccountName(nextStringOrNull(in)); return true; + case "salt": + // Set the acct salt using the value read from json. + String saltAsHex = nextStringOrNull(in); + if (saltAsHex != null && !saltAsHex.trim().isEmpty()) { + account.setSalt(decodeFromHex(saltAsHex)); + } + return true; default: return false; }