From c32e663907369995130c8ee97936e6363febf4d4 Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Tue, 10 Nov 2020 21:41:24 +0800
Subject: [PATCH 1/6] feat: add support for SEP-10 v3.0.0.
---
.../java/org/stellar/sdk/Sep10Challenge.java | 115 +++++++++++--
.../org/stellar/sdk/Sep10ChallengeTest.java | 160 +++++++++++++++++-
2 files changed, 258 insertions(+), 17 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/Sep10Challenge.java b/src/main/java/org/stellar/sdk/Sep10Challenge.java
index 7ccbbb851..a3433d210 100644
--- a/src/main/java/org/stellar/sdk/Sep10Challenge.java
+++ b/src/main/java/org/stellar/sdk/Sep10Challenge.java
@@ -64,17 +64,19 @@ public static Transaction newChallenge(
* that any signatures other than the servers on the transaction are valid. Use
* one of the following functions to completely verify the transaction:
* {@link Sep10Challenge#verifyChallengeTransactionSigners(String, String, Network, String, Set)} or
- * {@link Sep10Challenge#verifyChallengeTransactionThreshold(String, String, Network, String, int, Set)}
+ * {@link Sep10Challenge#verifyChallengeTransactionThreshold(String, String, Network, String, int, Set)} or
+ * {@link Sep10Challenge#verifyChallengeTransactionSigners(String, String, Network, String[], Set)} or
+ * {@link Sep10Challenge#verifyChallengeTransactionThreshold(String, String, Network, String[], int, Set)} or
*
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainName The fully qualified domain name of the service requiring authentication.
+ * @param domainNames One of the home domains that is expected to be included in the first Manage Data operation's string key.
* @return {@link ChallengeTransaction}, the decoded transaction envelope and client account ID contained within.
* @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
* @throws IOException If read XDR string fails, the exception will be thrown.
*/
- public static ChallengeTransaction readChallengeTransaction(String challengeXdr, String serverAccountId, Network network, String domainName) throws InvalidSep10ChallengeException, IOException {
+ public static ChallengeTransaction readChallengeTransaction(String challengeXdr, String serverAccountId, Network network, String[] domainNames) throws InvalidSep10ChallengeException, IOException {
// decode the received input as a base64-urlencoded XDR representation of Stellar transaction envelope
AbstractTransaction parsed = Transaction.fromEnvelopeXdr(challengeXdr, network);
if (!(parsed instanceof Transaction)) {
@@ -128,7 +130,15 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
throw new InvalidSep10ChallengeException("Operation should have a source account.");
}
- if (!String.format("%s %s", domainName, MANAGER_DATA_NAME_FLAG).equals(manageDataOperation.getName())) {
+ String matchedDomainName = null;
+ for (String homeDomain: domainNames) {
+ if ((homeDomain + " " + MANAGER_DATA_NAME_FLAG).equals(manageDataOperation.getName())) {
+ matchedDomainName = homeDomain;
+ break;
+ }
+ }
+
+ if (matchedDomainName == null) {
throw new InvalidSep10ChallengeException("The transaction's operation key name does not include the expected home domain.");
}
@@ -136,6 +146,9 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
throw new InvalidSep10ChallengeException("clientAccountId: "+clientAccountId+" is not a valid account id");
}
+ if (manageDataOperation.getValue() == null) {
+ throw new InvalidSep10ChallengeException("The transaction's operation value should not be null.");
+ }
// verify manage data value
if (manageDataOperation.getValue().length != 64) {
throw new InvalidSep10ChallengeException("Random nonce encoded as base64 should be 64 bytes long.");
@@ -157,7 +170,32 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
throw new InvalidSep10ChallengeException(String.format("Transaction not signed by server: %s.", serverAccountId));
}
- return new ChallengeTransaction(transaction, clientAccountId);
+ return new ChallengeTransaction(transaction, clientAccountId, matchedDomainName);
+ }
+
+ /**
+ * Reads a SEP 10 challenge transaction and returns the decoded transaction envelope and client account ID contained within.
+ *
+ * It also verifies that transaction is signed by the server.
+ *
+ * It does not verify that the transaction has been signed by the client or
+ * that any signatures other than the servers on the transaction are valid. Use
+ * one of the following functions to completely verify the transaction:
+ * {@link Sep10Challenge#verifyChallengeTransactionSigners(String, String, Network, String, Set)} or
+ * {@link Sep10Challenge#verifyChallengeTransactionThreshold(String, String, Network, String, int, Set)} or
+ * {@link Sep10Challenge#verifyChallengeTransactionSigners(String, String, Network, String[], Set)} or
+ * {@link Sep10Challenge#verifyChallengeTransactionThreshold(String, String, Network, String[], int, Set)} or
+ *
+ * @param challengeXdr SEP-0010 transaction challenge transaction in base64.
+ * @param serverAccountId Account ID for server's account.
+ * @param network The network to connect to for verifying and retrieving.
+ * @param domainName The home domains that is expected to be included in the first Manage Data operation's string key.
+ * @return {@link ChallengeTransaction}, the decoded transaction envelope and client account ID contained within.
+ * @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
+ * @throws IOException If read XDR string fails, the exception will be thrown.
+ */
+ public static ChallengeTransaction readChallengeTransaction(String challengeXdr, String serverAccountId, Network network, String domainName) throws InvalidSep10ChallengeException, IOException {
+ return readChallengeTransaction(challengeXdr, serverAccountId, network, new String[]{domainName});
}
/**
@@ -172,19 +210,41 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainName The fully qualified domain name of the service requiring authentication.
+ * @param domainName One of the home domains that is expected to be included in the first Manage Data operation's string key.
* @param signers The signers of client account.
* @return a list of signers that were found is returned, excluding the server account ID.
* @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
* @throws IOException If read XDR string fails, the exception will be thrown.
*/
public static Set verifyChallengeTransactionSigners(String challengeXdr, String serverAccountId, Network network, String domainName, Set signers) throws InvalidSep10ChallengeException, IOException {
+ return verifyChallengeTransactionSigners(challengeXdr, serverAccountId, network, new String[]{domainName}, signers);
+ }
+
+ /**
+ * Verifies that for a SEP 10 challenge transaction
+ * all signatures on the transaction are accounted for. A transaction is
+ * verified if it is signed by the server account, and all other signatures
+ * match a signer that has been provided as an argument. Additional signers can
+ * be provided that do not have a signature, but all signatures must be matched
+ * to a signer for verification to succeed. If verification succeeds a list of
+ * signers that were found is returned, excluding the server account ID.
+ *
+ * @param challengeXdr SEP-0010 transaction challenge transaction in base64.
+ * @param serverAccountId Account ID for server's account.
+ * @param network The network to connect to for verifying and retrieving.
+ * @param domainNames One of the home domains that is expected to be included in the first Manage Data operation's string key.
+ * @param signers The signers of client account.
+ * @return a list of signers that were found is returned, excluding the server account ID.
+ * @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
+ * @throws IOException If read XDR string fails, the exception will be thrown.
+ */
+ public static Set verifyChallengeTransactionSigners(String challengeXdr, String serverAccountId, Network network, String[] domainNames, Set signers) throws InvalidSep10ChallengeException, IOException {
if (signers == null || signers.isEmpty()) {
throw new InvalidSep10ChallengeException("No verifiable signers provided, at least one G... address must be provided.");
}
// Read the transaction which validates its structure.
- ChallengeTransaction parsedChallengeTransaction = readChallengeTransaction(challengeXdr, serverAccountId, network, domainName);
+ ChallengeTransaction parsedChallengeTransaction = readChallengeTransaction(challengeXdr, serverAccountId, network, domainNames);
Transaction transaction = parsedChallengeTransaction.getTransaction();
// Ensure the server account ID is an address and not a seed.
@@ -262,14 +322,14 @@ public static Set verifyChallengeTransactionSigners(String challengeXdr,
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainName The fully qualified domain name of the service requiring authentication.
+ * @param domainNames One of the home domains that is expected to be included in the first Manage Data operation's string key.
* @param threshold The threshold on the client account.
* @param signers The signers of client account.
* @return a list of signers that were found is returned, excluding the server account ID.
* @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
* @throws IOException If read XDR string fails, the exception will be thrown.
*/
- public static Set verifyChallengeTransactionThreshold(String challengeXdr, String serverAccountId, Network network, String domainName, int threshold, Set signers) throws InvalidSep10ChallengeException, IOException {
+ public static Set verifyChallengeTransactionThreshold(String challengeXdr, String serverAccountId, Network network, String[] domainNames, int threshold, Set signers) throws InvalidSep10ChallengeException, IOException {
if (signers == null || signers.isEmpty()) {
throw new InvalidSep10ChallengeException("No verifiable signers provided, at least one G... address must be provided.");
}
@@ -279,7 +339,7 @@ public static Set verifyChallengeTransactionThreshold(String challengeXd
weightsForSigner.put(signer.getKey(), signer.getWeight());
}
- Set signersFound = verifyChallengeTransactionSigners(challengeXdr, serverAccountId, network, domainName, weightsForSigner.keySet());
+ Set signersFound = verifyChallengeTransactionSigners(challengeXdr, serverAccountId, network, domainNames, weightsForSigner.keySet());
int sum = 0;
for (String signer : signersFound) {
@@ -296,6 +356,28 @@ public static Set verifyChallengeTransactionThreshold(String challengeXd
return signersFound;
}
+ /**
+ * Verifies that for a SEP-0010 challenge transaction
+ * all signatures on the transaction are accounted for and that the signatures
+ * meet a threshold on an account. A transaction is verified if it is signed by
+ * the server account, and all other signatures match a signer that has been
+ * provided as an argument, and those signatures meet a threshold on the
+ * account.
+ *
+ * @param challengeXdr SEP-0010 transaction challenge transaction in base64.
+ * @param serverAccountId Account ID for server's account.
+ * @param network The network to connect to for verifying and retrieving.
+ * @param domainName The home domain that is expected to be included in the first Manage Data operation's string key.
+ * @param threshold The threshold on the client account.
+ * @param signers The signers of client account.
+ * @return a list of signers that were found is returned, excluding the server account ID.
+ * @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
+ * @throws IOException If read XDR string fails, the exception will be thrown.
+ */
+ public static Set verifyChallengeTransactionThreshold(String challengeXdr, String serverAccountId, Network network, String domainName, int threshold, Set signers) throws InvalidSep10ChallengeException, IOException {
+ return verifyChallengeTransactionThreshold(challengeXdr, serverAccountId, network, new String[]{domainName}, threshold, signers);
+ }
+
private static Set verifyTransactionSignatures(Transaction transaction, Set signers) throws InvalidSep10ChallengeException {
if (transaction.getSignatures().isEmpty()) {
throw new InvalidSep10ChallengeException("Transaction has no signatures.");
@@ -333,15 +415,17 @@ private static boolean verifyTransactionSignature(Transaction transaction, Strin
}
/**
- * Used to store the results produced by {@link Sep10Challenge#readChallengeTransaction(String, String, Network, String)}.
+ * Used to store the results produced by {@link Sep10Challenge#readChallengeTransaction(String, String, Network, String[])}.
*/
public static class ChallengeTransaction {
private final Transaction transaction;
private final String clientAccountId;
+ private final String matchedHomeDomain;
- public ChallengeTransaction(Transaction transaction, String clientAccountId) {
+ public ChallengeTransaction(Transaction transaction, String clientAccountId, String matchedHomeDomain) {
this.transaction = transaction;
this.clientAccountId = clientAccountId;
+ this.matchedHomeDomain = matchedHomeDomain;
}
public Transaction getTransaction() {
@@ -352,6 +436,10 @@ public String getClientAccountId() {
return clientAccountId;
}
+ public String getMatchedHomeDomain() {
+ return matchedHomeDomain;
+ }
+
@Override
public int hashCode() {
return Objects.hashCode(this.transaction.hashHex(), this.clientAccountId);
@@ -369,7 +457,8 @@ public boolean equals(Object object) {
ChallengeTransaction other = (ChallengeTransaction) object;
return Objects.equal(this.transaction.hashHex(), other.transaction.hashHex()) &&
- Objects.equal(this.clientAccountId, other.clientAccountId);
+ Objects.equal(this.clientAccountId, other.clientAccountId) &&
+ Objects.equal(this.matchedHomeDomain, other.matchedHomeDomain);
}
}
diff --git a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
index 02ca66685..29fa70471 100644
--- a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
+++ b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
@@ -101,7 +101,7 @@ public void testReadChallengeTransactionValidSignedByServer() throws InvalidSep1
);
Sep10Challenge.ChallengeTransaction challengeTransaction = Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, domainName);
- assertEquals(new Sep10Challenge.ChallengeTransaction(transaction, client.getAccountId()), challengeTransaction);
+ assertEquals(new Sep10Challenge.ChallengeTransaction(transaction, client.getAccountId(), domainName), challengeTransaction);
}
@Test
@@ -153,7 +153,7 @@ public void testReadChallengeTransactionAcceptsBothV0AndV1() throws InvalidSep10
server.getAccountId(),
Network.TESTNET, domainName
);
- assertEquals(new Sep10Challenge.ChallengeTransaction(transaction, client.getAccountId()), challengeTransaction);
+ assertEquals(new Sep10Challenge.ChallengeTransaction(transaction, client.getAccountId(), domainName), challengeTransaction);
}
}
@@ -255,7 +255,7 @@ public void testReadChallengeTransactionValidSignedByServerAndClient() throws In
transaction.sign(client);
Sep10Challenge.ChallengeTransaction challengeTransaction = Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, domainName);
- assertEquals(new Sep10Challenge.ChallengeTransaction(transaction, client.getAccountId()), challengeTransaction);
+ assertEquals(new Sep10Challenge.ChallengeTransaction(transaction, client.getAccountId(), domainName), challengeTransaction);
}
@Test
@@ -791,6 +791,44 @@ public void testReadChallengeTransactionInvalidDataValueWrongByteLength() throws
}
}
+ @Test
+ public void testReadChallengeTransactionInvalidDataValueIsNull() throws IOException {
+ KeyPair server = KeyPair.random();
+ KeyPair client = KeyPair.random();
+ String domainName = "example.com";
+
+ Network network = Network.TESTNET;
+
+ long now = System.currentTimeMillis() / 1000L;
+ long end = now + 300;
+ TimeBounds timeBounds = new TimeBounds(now, end);
+
+ Account sourceAccount = new Account(server.getAccountId(), -1L);
+ ManageDataOperation manageDataOperation1 = new ManageDataOperation.Builder(domainName + " auth", null)
+ .setSourceAccount(client.getAccountId())
+ .build();
+
+ Operation[] operations = new Operation[]{manageDataOperation1};
+ Transaction transaction = new Transaction(
+ sourceAccount.getAccountId(),
+ 100 * operations.length,
+ sourceAccount.getIncrementedSequenceNumber(),
+ operations,
+ Memo.none(),
+ timeBounds,
+ network
+ );
+ transaction.sign(server);
+ String challenge = transaction.toEnvelopeXdrBase64();
+
+ try {
+ Sep10Challenge.readChallengeTransaction(challenge, server.getAccountId(), Network.TESTNET, domainName);
+ fail();
+ } catch (InvalidSep10ChallengeException e) {
+ assertEquals("The transaction's operation value should not be null.", e.getMessage());
+ }
+ }
+
@Test
public void testReadChallengeTransactionInvalidDomainNameMismatch() throws IOException {
KeyPair server = KeyPair.random();
@@ -824,6 +862,65 @@ public void testReadChallengeTransactionInvalidDomainNameMismatch() throws IOExc
}
}
+ @Test
+ public void testReadChallengeTransactionValidMultipleDomainNames() throws IOException, InvalidSep10ChallengeException {
+ KeyPair server = KeyPair.random();
+ KeyPair client = KeyPair.random();
+ Network network = Network.TESTNET;
+ String domainName = "example.com";
+
+ long now = System.currentTimeMillis() / 1000L;
+ long end = now + 300;
+ TimeBounds timeBounds = new TimeBounds(now, end);
+
+ Transaction transaction = null;
+ try {
+ transaction = Sep10Challenge.newChallenge(
+ server,
+ network,
+ client.getAccountId(),
+ domainName,
+ timeBounds
+ );
+ } catch (InvalidSep10ChallengeException e) {
+ fail("Should not have thrown any exception.");
+ }
+
+ Sep10Challenge.ChallengeTransaction challengeTransaction = Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, new String[]{"example3.com", "example2.com", "example.com"});
+ assertEquals(new Sep10Challenge.ChallengeTransaction(transaction, client.getAccountId(), domainName), challengeTransaction);
+ }
+
+ @Test
+ public void testReadChallengeTransactionInvalidDomainNamesEmpty() throws IOException, InvalidSep10ChallengeException {
+ KeyPair server = KeyPair.random();
+ KeyPair client = KeyPair.random();
+ Network network = Network.TESTNET;
+ String domainName = "example.com";
+
+ long now = System.currentTimeMillis() / 1000L;
+ long end = now + 300;
+ TimeBounds timeBounds = new TimeBounds(now, end);
+
+ Transaction transaction = null;
+ try {
+ transaction = Sep10Challenge.newChallenge(
+ server,
+ network,
+ client.getAccountId(),
+ domainName,
+ timeBounds
+ );
+ } catch (InvalidSep10ChallengeException e) {
+ fail("Should not have thrown any exception.");
+ }
+
+ try {
+ Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, new String[]{});
+ } catch (InvalidSep10ChallengeException e) {
+ assertEquals("The transaction's operation key name does not include the expected home domain.", e.getMessage());
+ }
+ }
+
@Test
public void testVerifyChallengeTransactionThresholdInvalidNotSignedByServer() throws IOException {
Network network = Network.TESTNET;
@@ -874,7 +971,6 @@ public void testVerifyChallengeTransactionThresholdInvalidNotSignedByServer() th
} catch (InvalidSep10ChallengeException e) {
assertEquals(String.format("Transaction not signed by server: %s.", server.getAccountId()), e.getMessage());
}
-
}
@Test
@@ -907,6 +1003,36 @@ public void testVerifyChallengeTransactionThresholdValidServerAndClientKeyMeetin
assertEquals(new HashSet(Collections.singletonList(masterClient.getAccountId())), signersFound);
}
+ @Test
+ public void testVerifyChallengeTransactionThresholdValidMultipleDomainNames() throws IOException, InvalidSep10ChallengeException {
+ Network network = Network.TESTNET;
+ KeyPair server = KeyPair.random();
+ KeyPair masterClient = KeyPair.random();
+
+ long now = System.currentTimeMillis() / 1000L;
+ long end = now + 300;
+ TimeBounds timeBounds = new TimeBounds(now, end);
+ String domainName = "example.com";
+
+ Transaction transaction = Sep10Challenge.newChallenge(
+ server,
+ network,
+ masterClient.getAccountId(),
+ domainName,
+ timeBounds
+ );
+
+ transaction.sign(masterClient);
+
+ Set signers = new HashSet(Collections.singletonList(
+ new Sep10Challenge.Signer(masterClient.getAccountId(), 255)
+ ));
+
+ int threshold = 255;
+ Set signersFound = Sep10Challenge.verifyChallengeTransactionThreshold(transaction.toEnvelopeXdrBase64(), server.getAccountId(), network, new String[]{"example3.com", "example2.com", "example.com"}, threshold, signers);
+ assertEquals(new HashSet(Collections.singletonList(masterClient.getAccountId())), signersFound);
+ }
+
@Test
public void testVerifyChallengeTransactionThresholdValidServerAndMultipleClientKeyMeetingThreshold() throws IOException, InvalidSep10ChallengeException {
Network network = Network.TESTNET;
@@ -1283,6 +1409,32 @@ public void testVerifyChallengeTransactionSignersValidServerAndClientMasterKey()
assertEquals(signers, signersFound);
}
+ @Test
+ public void testVerifyChallengeTransactionSignersValidMultipleDomainNames() throws InvalidSep10ChallengeException, IOException {
+ KeyPair server = KeyPair.random();
+ KeyPair masterClient = KeyPair.random();
+ Network network = Network.TESTNET;
+
+ long now = System.currentTimeMillis() / 1000L;
+ long end = now + 300;
+ TimeBounds timeBounds = new TimeBounds(now, end);
+ String domainName = "example.com";
+
+ Transaction transaction = Sep10Challenge.newChallenge(
+ server,
+ network,
+ masterClient.getAccountId(),
+ domainName,
+ timeBounds
+ );
+
+ transaction.sign(masterClient);
+
+ Set signers = new HashSet(Collections.singletonList(masterClient.getAccountId()));
+ Set signersFound = Sep10Challenge.verifyChallengeTransactionSigners(transaction.toEnvelopeXdrBase64(), server.getAccountId(), network, new String[]{"example3.com", "example2.com", "example.com"}, signers);
+ assertEquals(signers, signersFound);
+ }
+
@Test
public void testVerifyChallengeTransactionSignersInvalidServerAndNoClient() throws InvalidSep10ChallengeException, IOException {
KeyPair server = KeyPair.random();
From 8b8fa49f17e2e8acfa868e8433a35fe4007df1f5 Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Tue, 10 Nov 2020 22:08:07 +0800
Subject: [PATCH 2/6] add more tests
---
CHANGELOG.md | 3 ++
.../java/org/stellar/sdk/Sep10Challenge.java | 4 +--
.../org/stellar/sdk/Sep10ChallengeTest.java | 34 ++++++++++++++++++-
3 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8474e302f..2fa4520e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,9 @@
As this project is pre 1.0, breaking changes may happen for minor version bumps. A breaking change will get clearly notified in this log.
+ ## 0.21.2
+- Update challenge transaction helpers for SEP-0010 v3.0.0. ([#308](https://github.com/stellar/java-stellar-sdk/pull/308)).
+
## 0.21.1
- Fix NullPointerException in `org.stellar.sdk.responses.operations.RevokeSponsorshipOperationResponse` accessor methods.
diff --git a/src/main/java/org/stellar/sdk/Sep10Challenge.java b/src/main/java/org/stellar/sdk/Sep10Challenge.java
index b0c77fe5d..0a435ae37 100644
--- a/src/main/java/org/stellar/sdk/Sep10Challenge.java
+++ b/src/main/java/org/stellar/sdk/Sep10Challenge.java
@@ -133,7 +133,7 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
}
String matchedDomainName = null;
- for (String homeDomain: domainNames) {
+ for (String homeDomain : domainNames) {
if ((homeDomain + " " + MANAGER_DATA_NAME_FLAG).equals(manageDataOperation.getName())) {
matchedDomainName = homeDomain;
break;
@@ -227,7 +227,7 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainName One of the home domains that is expected to be included in the first Manage Data operation's string key.
+ * @param domainName The home domains that is expected to be included in the first Manage Data operation's string key.
* @param signers The signers of client account.
* @return a list of signers that were found is returned, excluding the server account ID.
* @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
diff --git a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
index ff21770c5..5cf6bed9a 100644
--- a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
+++ b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
@@ -988,7 +988,39 @@ public void testReadChallengeTransactionValidMultipleDomainNames() throws IOExce
}
@Test
- public void testReadChallengeTransactionInvalidDomainNamesEmpty() throws IOException, InvalidSep10ChallengeException {
+ public void testReadChallengeTransactionInvalidDomainNamesMismatch() throws IOException {
+ KeyPair server = KeyPair.random();
+ KeyPair client = KeyPair.random();
+ Network network = Network.TESTNET;
+ String domainName = "example.com";
+
+ long now = System.currentTimeMillis() / 1000L;
+ long end = now + 300;
+ TimeBounds timeBounds = new TimeBounds(now, end);
+
+ Transaction transaction = null;
+ try {
+ transaction = Sep10Challenge.newChallenge(
+ server,
+ network,
+ client.getAccountId(),
+ domainName,
+ timeBounds
+ );
+ } catch (InvalidSep10ChallengeException e) {
+ fail("Should not have thrown any exception.");
+ }
+
+ try {
+ Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, new String[]{"example2.com", "example1.com"});
+ fail();
+ } catch (InvalidSep10ChallengeException e) {
+ assertEquals("The transaction's operation key name does not include the expected home domain.", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testReadChallengeTransactionInvalidDomainNamesEmpty() throws IOException {
KeyPair server = KeyPair.random();
KeyPair client = KeyPair.random();
Network network = Network.TESTNET;
From b20d850a0ba2ceacfa7dde2b274d8fd8ddb955c0 Mon Sep 17 00:00:00 2001
From: Jun Luo <4catcode@gmail.com>
Date: Fri, 13 Nov 2020 09:58:34 +0800
Subject: [PATCH 3/6] fix the error message in SEP-10
Co-authored-by: Jake Urban <10968980+JakeUrban@users.noreply.github.com>
---
src/main/java/org/stellar/sdk/Sep10Challenge.java | 2 +-
src/test/java/org/stellar/sdk/Sep10ChallengeTest.java | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/Sep10Challenge.java b/src/main/java/org/stellar/sdk/Sep10Challenge.java
index 0a435ae37..89a0f0b8b 100644
--- a/src/main/java/org/stellar/sdk/Sep10Challenge.java
+++ b/src/main/java/org/stellar/sdk/Sep10Challenge.java
@@ -141,7 +141,7 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
}
if (matchedDomainName == null) {
- throw new InvalidSep10ChallengeException("The transaction's operation key name does not include the expected home domain.");
+ throw new InvalidSep10ChallengeException("The transaction's operation key name does not include one of the expected home domains.");
}
if (StrKey.decodeVersionByte(clientAccountId) != StrKey.VersionByte.ACCOUNT_ID) {
diff --git a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
index 5cf6bed9a..536946254 100644
--- a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
+++ b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
@@ -1015,7 +1015,7 @@ public void testReadChallengeTransactionInvalidDomainNamesMismatch() throws IOEx
Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, new String[]{"example2.com", "example1.com"});
fail();
} catch (InvalidSep10ChallengeException e) {
- assertEquals("The transaction's operation key name does not include the expected home domain.", e.getMessage());
+ assertEquals("The transaction's operation key name does not include one of the expected home domains.", e.getMessage());
}
}
@@ -1047,7 +1047,7 @@ public void testReadChallengeTransactionInvalidDomainNamesEmpty() throws IOExcep
Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, new String[]{});
fail();
} catch (InvalidSep10ChallengeException e) {
- assertEquals("The transaction's operation key name does not include the expected home domain.", e.getMessage());
+ assertEquals("The transaction's operation key name does not include one of the expected home domains.", e.getMessage());
}
}
From 5d52a5f69ffdf0d216f58250778cc6375c539eb4 Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Tue, 17 Nov 2020 09:11:21 +0800
Subject: [PATCH 4/6] fix the docs in SEP-10
Co-authored-by: Jake Urban <10968980+JakeUrban@users.noreply.github.com>
---
src/main/java/org/stellar/sdk/Sep10Challenge.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/Sep10Challenge.java b/src/main/java/org/stellar/sdk/Sep10Challenge.java
index 89a0f0b8b..356f73ac7 100644
--- a/src/main/java/org/stellar/sdk/Sep10Challenge.java
+++ b/src/main/java/org/stellar/sdk/Sep10Challenge.java
@@ -71,7 +71,7 @@ public static Transaction newChallenge(
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainNames One of the home domains that is expected to be included in the first Manage Data operation's string key.
+ * @param domainNames An array of home domains, one of which is expected to be included in the first Manage Data operation's string key.
* @return {@link ChallengeTransaction}, the decoded transaction envelope and client account ID contained within.
* @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
* @throws IOException If read XDR string fails, the exception will be thrown.
@@ -206,7 +206,7 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainName The home domains that is expected to be included in the first Manage Data operation's string key.
+ * @param domainName The home domain that is expected to be included in the first Manage Data operation's string key.
* @return {@link ChallengeTransaction}, the decoded transaction envelope and client account ID contained within.
* @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
* @throws IOException If read XDR string fails, the exception will be thrown.
@@ -227,7 +227,7 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr,
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainName The home domains that is expected to be included in the first Manage Data operation's string key.
+ * @param domainName The home domain that is expected to be included in the first Manage Data operation's string key.
* @param signers The signers of client account.
* @return a list of signers that were found is returned, excluding the server account ID.
* @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
@@ -249,7 +249,7 @@ public static Set verifyChallengeTransactionSigners(String challengeXdr,
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainNames One of the home domains that is expected to be included in the first Manage Data operation's string key.
+ * @param domainNames An array of home domains, one of which is expected to be included in the first Manage Data operation's string key.
* @param signers The signers of client account.
* @return a list of signers that were found is returned, excluding the server account ID.
* @throws InvalidSep10ChallengeException If the SEP-0010 validation fails, the exception will be thrown.
@@ -339,7 +339,7 @@ public static Set verifyChallengeTransactionSigners(String challengeXdr,
* @param challengeXdr SEP-0010 transaction challenge transaction in base64.
* @param serverAccountId Account ID for server's account.
* @param network The network to connect to for verifying and retrieving.
- * @param domainNames One of the home domains that is expected to be included in the first Manage Data operation's string key.
+ * @param domainNames An array of home domains, one of which is expected to be included in the first Manage Data operation's string key.
* @param threshold The threshold on the client account.
* @param signers The signers of client account.
* @return a list of signers that were found is returned, excluding the server account ID.
From 54f5d206552b9e04853e83343fe8b0240cc9c4ea Mon Sep 17 00:00:00 2001
From: Jun Luo <4catcode@gmail.com>
Date: Thu, 10 Dec 2020 09:36:13 +0800
Subject: [PATCH 5/6] Update CHANGELOG.md
Co-authored-by: Leigh McCulloch
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b12cfd222..7dc51477d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,7 @@
As this project is pre 1.0, breaking changes may happen for minor version bumps. A breaking change will get clearly notified in this log.
- ## 0.21.2
+## 0.21.2
- Update challenge transaction helpers for SEP-0010 v3.0.0. ([#308](https://github.com/stellar/java-stellar-sdk/pull/308))
- Fix the decoding of `balanceId` in `org.stellar.sdk.ClaimClaimableBalanceOperation`. ([#310](https://github.com/stellar/java-stellar-sdk/pull/310))
From c8bcc32a598cd917fc15d013b19e1a3dd100eeee Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Thu, 10 Dec 2020 10:44:07 +0800
Subject: [PATCH 6/6] Add verification of the domainNames provided by the user.
---
.../java/org/stellar/sdk/Sep10Challenge.java | 4 ++
.../org/stellar/sdk/Sep10ChallengeTest.java | 40 +++++++++++++++++--
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/Sep10Challenge.java b/src/main/java/org/stellar/sdk/Sep10Challenge.java
index 356f73ac7..1836b4ae7 100644
--- a/src/main/java/org/stellar/sdk/Sep10Challenge.java
+++ b/src/main/java/org/stellar/sdk/Sep10Challenge.java
@@ -77,6 +77,10 @@ public static Transaction newChallenge(
* @throws IOException If read XDR string fails, the exception will be thrown.
*/
public static ChallengeTransaction readChallengeTransaction(String challengeXdr, String serverAccountId, Network network, String[] domainNames) throws InvalidSep10ChallengeException, IOException {
+ if (domainNames == null || domainNames.length == 0) {
+ throw new IllegalArgumentException("At least one domain name must be included in domainNames.");
+ }
+
// decode the received input as a base64-urlencoded XDR representation of Stellar transaction envelope
AbstractTransaction parsed = Transaction.fromEnvelopeXdr(challengeXdr, network);
if (!(parsed instanceof Transaction)) {
diff --git a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
index 536946254..b324944d2 100644
--- a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
+++ b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java
@@ -1020,7 +1020,7 @@ public void testReadChallengeTransactionInvalidDomainNamesMismatch() throws IOEx
}
@Test
- public void testReadChallengeTransactionInvalidDomainNamesEmpty() throws IOException {
+ public void testReadChallengeTransactionInvalidDomainNamesEmpty() throws IOException, InvalidSep10ChallengeException {
KeyPair server = KeyPair.random();
KeyPair client = KeyPair.random();
Network network = Network.TESTNET;
@@ -1044,10 +1044,44 @@ public void testReadChallengeTransactionInvalidDomainNamesEmpty() throws IOExcep
}
try {
- Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, new String[]{});
+ String[] domainNames = new String[]{};
+ Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, domainNames);
fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("At least one domain name must be included in domainNames.", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testReadChallengeTransactionInvalidDomainNamesNull() throws IOException, InvalidSep10ChallengeException {
+ KeyPair server = KeyPair.random();
+ KeyPair client = KeyPair.random();
+ Network network = Network.TESTNET;
+ String domainName = "example.com";
+
+ long now = System.currentTimeMillis() / 1000L;
+ long end = now + 300;
+ TimeBounds timeBounds = new TimeBounds(now, end);
+
+ Transaction transaction = null;
+ try {
+ transaction = Sep10Challenge.newChallenge(
+ server,
+ network,
+ client.getAccountId(),
+ domainName,
+ timeBounds
+ );
} catch (InvalidSep10ChallengeException e) {
- assertEquals("The transaction's operation key name does not include one of the expected home domains.", e.getMessage());
+ fail("Should not have thrown any exception.");
+ }
+
+ try {
+ String[] domainNames = null;
+ Sep10Challenge.readChallengeTransaction(transaction.toEnvelopeXdrBase64(), server.getAccountId(), Network.TESTNET, domainNames);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("At least one domain name must be included in domainNames.", e.getMessage());
}
}