From ce8c054262188cefeb636a387a4ef7c45793ed82 Mon Sep 17 00:00:00 2001 From: Jake Urban Date: Tue, 12 Jan 2021 13:45:51 -0800 Subject: [PATCH 1/7] added webAuthDomain parameter and validation to SEP-10 util functions --- src/utils.ts | 34 ++++- test/unit/utils_test.js | 300 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 318 insertions(+), 16 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 55c2b0638..963605505 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -29,11 +29,12 @@ export namespace Utils { * @param {string} homeDomain The fully qualified domain name of the service requiring authentication * @param {number} [timeout=300] Challenge duration (default to 5 minutes). * @param {string} networkPassphrase The network passphrase. If you pass this argument then timeout is required. + * @param {string} webAuthDomain The fully qualified domain name of the service issuing the challenge. * @example * import { Utils, Keypair, Networks } from 'stellar-sdk' * * let serverKeyPair = Keypair.fromSecret("server-secret") - * let challenge = Utils.buildChallengeTx(serverKeyPair, "client-stellar-account-id", "SDF", 300, Networks.TESTNET) + * let challenge = Utils.buildChallengeTx(serverKeyPair, "client-stellar-account-id", "stellar.org", 300, Networks.TESTNET) * @returns {string} A base64 encoded string of the raw TransactionEnvelope xdr struct for the transaction. */ export function buildChallengeTx( @@ -42,6 +43,7 @@ export namespace Utils { homeDomain: string, timeout: number = 300, networkPassphrase: string, + webAuthDomain: string, ): string { if (clientAccountID.startsWith("M")) { throw Error( @@ -74,6 +76,13 @@ export namespace Utils { source: clientAccountID, }), ) + .addOperation( + Operation.manageData({ + name: "web_auth_domain", + value: webAuthDomain, + source: account.accountId(), + }), + ) .build(); transaction.sign(serverKeypair); @@ -103,6 +112,7 @@ export namespace Utils { * @param {string} serverAccountID The server's stellar account (public key). * @param {string} networkPassphrase The network passphrase, e.g.: 'Test SDF Network ; September 2015'. * @param {string|string[]} [homeDomains] The home domain that is expected to be included in the first Manage Data operation's string key. If an array is provided, one of the domain names in the array must match. + * @param {string} webAuthDomain The home domain that is expected to be included as the value of the Manage Data operation with the 'web_auth_domain' key. If no such operation is included, this parameter is not used. * @returns {Transaction|string|string} The actual transaction and the stellar public key (master key) used to sign the Manage Data operation, and matched home domain. */ export function readChallengeTx( @@ -110,6 +120,7 @@ export namespace Utils { serverAccountID: string, networkPassphrase: string, homeDomains: string | string[], + webAuthDomain: string, ): { tx: Transaction; clientAccountID: string; matchedHomeDomain: string } { if (serverAccountID.startsWith("M")) { throw Error( @@ -187,7 +198,10 @@ export namespace Utils { } // verify base64 - if (Buffer.from(operation.value.toString(), "base64").length !== 48) { + if ( + !operation.value || + Buffer.from(operation.value.toString(), "base64").length !== 48 + ) { throw new InvalidSep10ChallengeError( "The transaction's operation value should be a 64 bytes base64 random string", ); @@ -234,6 +248,16 @@ export namespace Utils { "The transaction has operations that are unrecognized", ); } + if ( + op.name === "web_auth_domain" && + (!op.value || op.value.toString() !== webAuthDomain) + ) { + throw new InvalidSep10ChallengeError( + `Invalid 'web_auth_domain' value. Expected: ${webAuthDomain}; Contained: ${ + op.value ? op.value.toString() : op.value + }`, + ); + } } return { tx: transaction, clientAccountID, matchedHomeDomain }; @@ -266,6 +290,7 @@ export namespace Utils { * @param {number} threshold The required signatures threshold for verifying this transaction. * @param {ServerApi.AccountRecordSigners[]} signerSummary a map of all authorized signers to their weights. It's used to validate if the transaction signatures have met the given threshold. * @param {string|string[]} [homeDomains] The home domain(s) that should be included in the first Manage Data operation's string key. Required in verifyChallengeTxSigners() => readChallengeTx(). + * @param {string} webAuthDomain The home domain that is expected to be included as the value of the Manage Data operation with the 'web_auth_domain' key, if present. Used in verifyChallengeTxSigners() => readChallengeTx(). * @returns {string[]} The list of signers public keys that have signed the transaction, excluding the server account ID, given that the threshold was met. * @example * @@ -317,6 +342,7 @@ export namespace Utils { threshold: number, signerSummary: ServerApi.AccountRecordSigners[], homeDomains: string | string[], + webAuthDomain: string, ): string[] { const signers = signerSummary.map((signer) => signer.key); @@ -326,6 +352,7 @@ export namespace Utils { networkPassphrase, signers, homeDomains, + webAuthDomain, ); let weight = 0; @@ -369,6 +396,7 @@ export namespace Utils { * @param {string} networkPassphrase The network passphrase, e.g.: 'Test SDF Network ; September 2015'. * @param {string[]} signers The signers public keys. This list should contain the public keys for all signers that have signed the transaction. * @param {string|string[]} [homeDomains] The home domain(s) that should be included in the first Manage Data operation's string key. Required in readChallengeTx(). + * @param {string} webAuthDomain The home domain that is expected to be included as the value of the Manage Data operation with the 'web_auth_domain' key, if present. Used in readChallengeTx(). * @returns {string[]} The list of signers public keys that have signed the transaction, excluding the server account ID. * @example * @@ -406,6 +434,7 @@ export namespace Utils { networkPassphrase: string, signers: string[], homeDomains: string | string[], + webAuthDomain: string, ): string[] { // Read the transaction which validates its structure. const { tx } = readChallengeTx( @@ -413,6 +442,7 @@ export namespace Utils { serverAccountID, networkPassphrase, homeDomains, + webAuthDomain, ); // Ensure the server account ID is an address and not a seed. diff --git a/test/unit/utils_test.js b/test/unit/utils_test.js index dcd42de89..c8bc63d88 100644 --- a/test/unit/utils_test.js +++ b/test/unit/utils_test.js @@ -27,9 +27,10 @@ describe('Utils', function() { StellarSdk.Utils.buildChallengeTx( keypair, "MAAAAAAAAAAAAAB7BQ2L7E5NBWMXDUCMZSIPOBKRDSBYVLMXGSSKF6YNPIB7Y77ITLVL6", - "SDF", + "testanchor.stellar.org", 300, - StellarSdk.Networks.TESTNET + StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ) ).to.throw( /Invalid clientAccountID: multiplexed accounts are not supported./ @@ -44,26 +45,32 @@ describe('Utils', function() { "GBDIT5GUJ7R5BXO3GJHFXJ6AZ5UQK6MNOIDMPQUSMXLIHTUNR2Q5CFNF", "testanchor.stellar.org", 300, - StellarSdk.Networks.TESTNET + StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); const transaction = new StellarSdk.Transaction(challenge, StellarSdk.Networks.TESTNET); expect(transaction.sequence).to.eql("0"); expect(transaction.source).to.eql(keypair.publicKey()); - expect(transaction.operations.length).to.eql(1); + expect(transaction.operations.length).to.eql(2); const { maxTime, minTime } = transaction.timeBounds; expect(parseInt(maxTime) - parseInt(minTime)).to.eql(300); - const [ operation ] = transaction.operations; + const [ operation1, operation2 ] = transaction.operations; + + expect(operation1.name).to.eql("testanchor.stellar.org auth"); + expect(operation1.source).to.eql("GBDIT5GUJ7R5BXO3GJHFXJ6AZ5UQK6MNOIDMPQUSMXLIHTUNR2Q5CFNF"); + expect(operation1.type).to.eql("manageData"); + expect(operation1.value.length).to.eql(64); + expect(Buffer.from(operation1.value.toString(), 'base64').length).to.eql(48); - expect(operation.name).to.eql("testanchor.stellar.org auth"); - expect(operation.source).to.eql("GBDIT5GUJ7R5BXO3GJHFXJ6AZ5UQK6MNOIDMPQUSMXLIHTUNR2Q5CFNF"); - expect(operation.type).to.eql("manageData"); - expect(operation.value.length).to.eql(64); - expect(Buffer.from(operation.value.toString(), 'base64').length).to.eql(48); + expect(operation2.name).to.equal("web_auth_domain"); + expect(operation2.source).to.eql(keypair.publicKey()); + expect(operation2.type).to.eql("manageData"); + expect(operation2.value.toString()).to.eql("testanchor.stellar.org"); }); it('uses the passed-in timeout', function() { @@ -72,9 +79,10 @@ describe('Utils', function() { const challenge = StellarSdk.Utils.buildChallengeTx( keypair, "GBDIT5GUJ7R5BXO3GJHFXJ6AZ5UQK6MNOIDMPQUSMXLIHTUNR2Q5CFNF", - "SDF", + "testanchor.stellar.org", 600, - StellarSdk.Networks.TESTNET + StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); const transaction = new StellarSdk.Transaction(challenge, StellarSdk.Networks.TESTNET); @@ -98,6 +106,7 @@ describe('Utils', function() { 300, StellarSdk.Networks.TESTNET, "testanchor.stellar.org", + "testanchor.stellar.org" ) ).to.throw( /Invalid serverAccountID: multiplexed accounts are not supported./ @@ -113,6 +122,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); const innerTx = new StellarSdk.TransactionBuilder(new StellarSdk.Account(clientKP.publicKey(), "0"), { @@ -145,6 +155,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ) ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -157,6 +168,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ) ).to.not.throw(StellarSdk.InvalidSep10ChallengeError); expect(() => @@ -165,6 +177,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ) ).to.not.throw(StellarSdk.InvalidSep10ChallengeError); }); @@ -177,7 +190,8 @@ describe('Utils', function() { clientKP.publicKey(), "SDF", 300, - StellarSdk.Networks.TESTNET + StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -193,6 +207,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ) ).to.eql({ tx: transaction, @@ -223,6 +238,7 @@ describe('Utils', function() { keypair.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -239,6 +255,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); let serverAccountId = StellarSdk.Keypair.random().publicKey(); @@ -249,6 +266,7 @@ describe('Utils', function() { serverAccountId, StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -278,6 +296,7 @@ describe('Utils', function() { keypair.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -313,6 +332,7 @@ describe('Utils', function() { keypair.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -348,6 +368,7 @@ describe('Utils', function() { keypair.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -407,6 +428,7 @@ describe('Utils', function() { serverKeypair.publicKey(), StellarSdk.Networks.TESTNET, anchorName, + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -443,6 +465,7 @@ describe('Utils', function() { keypair.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -495,6 +518,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(350000); @@ -516,6 +540,7 @@ describe('Utils', function() { keypair.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -558,6 +583,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "testanchor.stellar.org", + "testanchor.stellar.org" ), ).to.eql({ tx: transactionRoundTripped, @@ -601,6 +627,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, ["SDF", "Test", "testanchor.stellar.org", "SDF-test"], + "testanchor.stellar.org" ), ).to.eql({ tx: transactionRoundTripped, @@ -714,6 +741,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "testanchor.stellar.org", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -751,6 +779,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, ["SDF", "Test", "testanchor.stellar.org", "SDF-test"], + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -800,6 +829,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.eql({ tx: transactionRoundTripped, @@ -850,6 +880,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -898,12 +929,208 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, /The transaction has operations that are not of type 'manageData'/, ); }); + + it("throws an error if the provided webAuthDomain does not match the 'web_auth_domain' operation's value", function() { + let serverKP = StellarSdk.Keypair.random(); + let clientKP = StellarSdk.Keypair.random(); + const serverAccount = new StellarSdk.Account(serverKP.publicKey(), "-1"); + const transaction = new StellarSdk.TransactionBuilder( + serverAccount, + txBuilderOpts, + ) + .addOperation( + StellarSdk.Operation.manageData({ + source: clientKP.publicKey(), + name: "testanchor.stellar.org auth", + value: randomBytes(48).toString("base64"), + }), + ) + .addOperation( + StellarSdk.Operation.manageData({ + source: serverKP.publicKey(), + name: "web_auth_domain", + value: "unexpected_web_auth_domain" + }), + ) + .setTimeout(30) + .build(); + + transaction.sign(serverKP); + const challenge = transaction + .toEnvelope() + .toXDR("base64") + .toString(); + + const transactionRoundTripped = new StellarSdk.Transaction( + challenge, + StellarSdk.Networks.TESTNET + ); + + expect(() => + StellarSdk.Utils.readChallengeTx( + challenge, + serverKP.publicKey(), + StellarSdk.Networks.TESTNET, + "testanchor.stellar.org", + "testanchor.stellar.org" + ), + ).to.throw( + StellarSdk.InvalidSep10ChallengeError, + /Invalid 'web_auth_domain' value. Expected: testanchor.stellar.org; Contained: unexpected_web_auth_domain/, + ); + }); + + it("throws an error if the 'web_auth_domain' operation's source account is not the server's public key", function() { + let serverKP = StellarSdk.Keypair.random(); + let clientKP = StellarSdk.Keypair.random(); + const serverAccount = new StellarSdk.Account(serverKP.publicKey(), "-1"); + const transaction = new StellarSdk.TransactionBuilder( + serverAccount, + txBuilderOpts, + ) + .addOperation( + StellarSdk.Operation.manageData({ + source: clientKP.publicKey(), + name: "testanchor.stellar.org auth", + value: randomBytes(48).toString("base64"), + }), + ) + .addOperation( + StellarSdk.Operation.manageData({ + source: clientKP.publicKey(), + name: "web_auth_domain", + value: "testanchor.stellar.org" + }), + ) + .setTimeout(30) + .build(); + + transaction.sign(serverKP); + const challenge = transaction + .toEnvelope() + .toXDR("base64") + .toString(); + + const transactionRoundTripped = new StellarSdk.Transaction( + challenge, + StellarSdk.Networks.TESTNET + ); + + expect(() => + StellarSdk.Utils.readChallengeTx( + challenge, + serverKP.publicKey(), + StellarSdk.Networks.TESTNET, + "testanchor.stellar.org", + "testanchor.stellar.org" + ), + ).to.throw( + StellarSdk.InvalidSep10ChallengeError, + /The transaction has operations that are unrecognized/ + ); + }); + + it("allows transaction to omit the 'web_auth_domain' operation", function() { + let serverKP = StellarSdk.Keypair.random(); + let clientKP = StellarSdk.Keypair.random(); + const serverAccount = new StellarSdk.Account(serverKP.publicKey(), "-1"); + const transaction = new StellarSdk.TransactionBuilder( + serverAccount, + txBuilderOpts, + ) + .addOperation( + StellarSdk.Operation.manageData({ + source: clientKP.publicKey(), + name: "testanchor.stellar.org auth", + value: randomBytes(48).toString("base64"), + }), + ) + .setTimeout(30) + .build(); + + transaction.sign(serverKP); + const challenge = transaction + .toEnvelope() + .toXDR("base64") + .toString(); + + const transactionRoundTripped = new StellarSdk.Transaction( + challenge, + StellarSdk.Networks.TESTNET + ); + + expect( + StellarSdk.Utils.readChallengeTx( + challenge, + serverKP.publicKey(), + StellarSdk.Networks.TESTNET, + "testanchor.stellar.org", + "testanchor.stellar.org" + ), + ).to.eql({ + tx: transactionRoundTripped, + clientAccountID: clientKP.publicKey(), + matchedHomeDomain: "testanchor.stellar.org", + }); + }); + + it("matches the 'web_auth_domain' operation value with webAuthDomain", function() { + let serverKP = StellarSdk.Keypair.random(); + let clientKP = StellarSdk.Keypair.random(); + const serverAccount = new StellarSdk.Account(serverKP.publicKey(), "-1"); + const transaction = new StellarSdk.TransactionBuilder( + serverAccount, + txBuilderOpts, + ) + .addOperation( + StellarSdk.Operation.manageData({ + source: clientKP.publicKey(), + name: "testanchor.stellar.org auth", + value: randomBytes(48).toString("base64"), + }), + ) + .addOperation( + StellarSdk.Operation.manageData({ + source: serverKP.publicKey(), + name: "web_auth_domain", + value: "testanchor.stellar.org" + }), + ) + .setTimeout(30) + .build(); + + transaction.sign(serverKP); + const challenge = transaction + .toEnvelope() + .toXDR("base64") + .toString(); + + const transactionRoundTripped = new StellarSdk.Transaction( + challenge, + StellarSdk.Networks.TESTNET + ); + + expect( + StellarSdk.Utils.readChallengeTx( + challenge, + serverKP.publicKey(), + StellarSdk.Networks.TESTNET, + "testanchor.stellar.org", + "testanchor.stellar.org" + ), + ).to.eql({ + tx: transactionRoundTripped, + clientAccountID: clientKP.publicKey(), + matchedHomeDomain: "testanchor.stellar.org", + }); + }); }); describe("Utils.verifyChallengeTxThreshold", function() { @@ -960,7 +1187,8 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, threshold, signerSummary, - "SDF-test" + "SDF-test", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -975,6 +1203,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1002,6 +1231,7 @@ describe('Utils', function() { threshold, signerSummary, "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP1.publicKey()]); }); @@ -1013,6 +1243,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1041,6 +1272,7 @@ describe('Utils', function() { threshold, signerSummary, "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP1.publicKey(), this.clientKP2.publicKey()]); }); @@ -1052,6 +1284,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1081,6 +1314,7 @@ describe('Utils', function() { threshold, signerSummary, "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP1.publicKey(), this.clientKP2.publicKey()]); }); @@ -1096,6 +1330,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1128,6 +1363,7 @@ describe('Utils', function() { threshold, signerSummary, "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP1.publicKey(), this.clientKP2.publicKey()]); }); @@ -1139,6 +1375,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1168,6 +1405,7 @@ describe('Utils', function() { threshold, signerSummary, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1182,6 +1420,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1210,6 +1449,7 @@ describe('Utils', function() { threshold, signerSummary, "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1224,6 +1464,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1248,6 +1489,7 @@ describe('Utils', function() { threshold, [], "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1288,6 +1530,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1310,6 +1553,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP1.publicKey()], "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP1.publicKey()]); }); @@ -1337,6 +1581,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP1.publicKey()], "SDF-test", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1351,6 +1596,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1362,6 +1608,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [], "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1376,6 +1623,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1397,6 +1645,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP1.publicKey()], "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1411,6 +1660,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1435,6 +1685,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, clientSignersPubKey, "SDF", + "testanchor.stellar.org" ), ).to.eql(clientSignersPubKey); }); @@ -1446,6 +1697,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1470,6 +1722,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, clientSignersPubKey, "SDF", + "testanchor.stellar.org" ), ).to.have.same.members(clientSignersPubKey); }); @@ -1481,6 +1734,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1503,6 +1757,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP2.publicKey()], "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP2.publicKey()]); }); @@ -1514,6 +1769,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1536,6 +1792,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP2.publicKey(), StellarSdk.Keypair.random().publicKey()], "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP2.publicKey()]); }); @@ -1547,6 +1804,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1569,6 +1827,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP2.publicKey(), this.serverKP.publicKey()], "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1583,6 +1842,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1605,6 +1865,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP2.publicKey(), this.clientKP2.publicKey()], "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP2.publicKey()]); }); @@ -1620,6 +1881,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1642,6 +1904,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP2.publicKey(), preauthTxHash, xHash, unknownSignerType], "SDF", + "testanchor.stellar.org" ), ).to.eql([this.clientKP2.publicKey()]); }); @@ -1653,6 +1916,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1674,6 +1938,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP2.publicKey(), this.clientKP2.publicKey()], "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1688,6 +1953,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1710,6 +1976,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP2.publicKey()], "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1724,6 +1991,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1746,6 +2014,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [this.clientKP2.secret()], "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1780,6 +2049,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, clientSigners, "SDF-test", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, @@ -1794,6 +2064,7 @@ describe('Utils', function() { "SDF", 300, StellarSdk.Networks.TESTNET, + "testanchor.stellar.org" ); clock.tick(200); @@ -1816,6 +2087,7 @@ describe('Utils', function() { StellarSdk.Networks.TESTNET, [], "SDF", + "testanchor.stellar.org" ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, From 30741430ee226f5789d07f24d2d7682b977491d0 Mon Sep 17 00:00:00 2001 From: Jake Urban Date: Sun, 17 Jan 2021 11:39:42 -0800 Subject: [PATCH 2/7] updated error message for multiple operations & compares buffers --- src/utils.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 963605505..7162ce012 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -193,15 +193,12 @@ export namespace Utils { if (operation.value === undefined) { throw new InvalidSep10ChallengeError( - "The transaction's operation value should not be null", + "The transaction's operation values should not be null", ); } // verify base64 - if ( - !operation.value || - Buffer.from(operation.value.toString(), "base64").length !== 48 - ) { + if (Buffer.from(operation.value.toString(), "base64").length !== 48) { throw new InvalidSep10ChallengeError( "The transaction's operation value should be a 64 bytes base64 random string", ); @@ -248,14 +245,17 @@ export namespace Utils { "The transaction has operations that are unrecognized", ); } + if (op.value === undefined) { + throw new InvalidSep10ChallengeError( + "The transaction's operation values should not be null", + ); + } if ( op.name === "web_auth_domain" && - (!op.value || op.value.toString() !== webAuthDomain) + !op.value.compare(Buffer.from(webAuthDomain)) ) { throw new InvalidSep10ChallengeError( - `Invalid 'web_auth_domain' value. Expected: ${webAuthDomain}; Contained: ${ - op.value ? op.value.toString() : op.value - }`, + `'web_auth_domain' operation value does not match ${webAuthDomain}`, ); } } From 503f3787ecc94560aa345c4bc57b787f3c1c5abb Mon Sep 17 00:00:00 2001 From: Jake Urban Date: Sun, 17 Jan 2021 11:43:26 -0800 Subject: [PATCH 3/7] updated test to match error message --- test/unit/utils_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/utils_test.js b/test/unit/utils_test.js index c8bc63d88..c5fdb0421 100644 --- a/test/unit/utils_test.js +++ b/test/unit/utils_test.js @@ -983,7 +983,7 @@ describe('Utils', function() { ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, - /Invalid 'web_auth_domain' value. Expected: testanchor.stellar.org; Contained: unexpected_web_auth_domain/, + /'web_auth_domain' operation value does not match testanchor.stellar.org/ ); }); From 2aabd3bc5ea011fcc7a95eed065933e287d927db Mon Sep 17 00:00:00 2001 From: Jake Urban Date: Sun, 17 Jan 2021 12:04:50 -0800 Subject: [PATCH 4/7] fixed boolean logic --- src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index 7162ce012..d90cb64f2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -252,7 +252,7 @@ export namespace Utils { } if ( op.name === "web_auth_domain" && - !op.value.compare(Buffer.from(webAuthDomain)) + op.value.compare(Buffer.from(webAuthDomain)) ) { throw new InvalidSep10ChallengeError( `'web_auth_domain' operation value does not match ${webAuthDomain}`, From 1b2ae423719554460b7c159bb3ce505114262b79 Mon Sep 17 00:00:00 2001 From: Jake Urban Date: Sun, 17 Jan 2021 12:09:38 -0800 Subject: [PATCH 5/7] updated relevant test after updating error message --- test/unit/utils_test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/utils_test.js b/test/unit/utils_test.js index c5fdb0421..b65f0cd16 100644 --- a/test/unit/utils_test.js +++ b/test/unit/utils_test.js @@ -504,7 +504,7 @@ describe('Utils', function() { ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, - /The transaction\'s operation value should not be null/, + /The transaction\'s operation values should not be null/, ); }); @@ -983,7 +983,7 @@ describe('Utils', function() { ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, - /'web_auth_domain' operation value does not match testanchor.stellar.org/ + /'web_auth_domain' operation value does not match testanchor.stellar.orrequires a envelopeTypeTxV0 or envelopeTypeTxg/ ); }); From 088730cecc86a52dbdfdbbe94343cc6e35c7aebd Mon Sep 17 00:00:00 2001 From: Jake Urban Date: Sun, 17 Jan 2021 12:14:35 -0800 Subject: [PATCH 6/7] fix bad copy paste --- test/unit/utils_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/utils_test.js b/test/unit/utils_test.js index b65f0cd16..9fd68978e 100644 --- a/test/unit/utils_test.js +++ b/test/unit/utils_test.js @@ -983,7 +983,7 @@ describe('Utils', function() { ), ).to.throw( StellarSdk.InvalidSep10ChallengeError, - /'web_auth_domain' operation value does not match testanchor.stellar.orrequires a envelopeTypeTxV0 or envelopeTypeTxg/ + /'web_auth_domain' operation value does not match testanchor.stellar.org/ ); }); From 3530d26a3f6f751dfd8eca916b465cbc7229be39 Mon Sep 17 00:00:00 2001 From: Jake Urban Date: Mon, 18 Jan 2021 11:32:54 -0800 Subject: [PATCH 7/7] ensure webAuthDomain parameter is used when matching --- test/unit/utils_test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/utils_test.js b/test/unit/utils_test.js index 9fd68978e..7c261f9b1 100644 --- a/test/unit/utils_test.js +++ b/test/unit/utils_test.js @@ -1100,7 +1100,7 @@ describe('Utils', function() { StellarSdk.Operation.manageData({ source: serverKP.publicKey(), name: "web_auth_domain", - value: "testanchor.stellar.org" + value: "auth.stellar.org" }), ) .setTimeout(30) @@ -1123,7 +1123,7 @@ describe('Utils', function() { serverKP.publicKey(), StellarSdk.Networks.TESTNET, "testanchor.stellar.org", - "testanchor.stellar.org" + "auth.stellar.org" ), ).to.eql({ tx: transactionRoundTripped,