From a6e19fe618299dbd7111dd308f252203e4af8d6f Mon Sep 17 00:00:00 2001 From: Morley Zhi Date: Tue, 6 Jul 2021 15:30:09 -0400 Subject: [PATCH] Validate fetchAuthTokens with stellar-sdk's utils (#247) - Upgrade the package's expected version of stellar-sdk to ~8.2.3 - KeyManager#fetchAuthToken now requires the previously-optional `authServerKey` param - KeyManager#fetchAuthToken now requires a new param, `authServerHomeDomains` - KeyManager#fetchAuthToken now runs challenge token XDR through stellar-sdk's Util.readChallengeTx, which performs additional checks --- CHANGELOG.md | 15 +- package.json | 6 +- src/KeyManager.test.ts | 527 +++++++++++++++++++++++++++++++++-------- src/KeyManager.ts | 86 +++---- src/types/keys.ts | 1 + yarn.lock | 53 ++--- 6 files changed, 502 insertions(+), 186 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3930f3c6..2c8ef9f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,20 @@ ## In master +## [v0.4.0-rc.0](https://github.com/stellar/js-stellar-wallets/compare/v0.3.0-rc.9...v0.4.0-rc.0) + +Validate fetchAuthTokens with stellar-sdk's utils + +- Upgrade the package's expected version of stellar-sdk to 8.x.x +- KeyManager#fetchAuthToken now requires the previously-optional `authServerKey` + param +- KeyManager#fetchAuthToken now requires a new param, `authServerHomeDomains` +- KeyManager#fetchAuthToken now runs challenge token XDR through stellar-sdk's + Util.readChallengeTx, which performs additional tests + ## [v0.3.0-rc.9](https://github.com/stellar/js-stellar-wallets/compare/v0.3.0-rc.8...v0.3.0-rc.9) -- Fix issue where zero fees were still being considered as "complex" - instead of "simple". +- Fix issue where zero fees were still being considered as "complex" instead of + "simple". ## [v0.3.0-rc.8](https://github.com/stellar/js-stellar-wallets/compare/v0.3.0-rc.7...v0.3.0-rc.8) diff --git a/package.json b/package.json index f2afefff..bc02c7cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stellar/wallet-sdk", - "version": "0.3.0-rc.9", + "version": "0.4.0-rc.0", "description": "Libraries to help you write Stellar-enabled wallets in Javascript", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -10,7 +10,7 @@ "prettier": "@stellar/prettier-config", "peerDependencies": { "bignumber.js": "*", - "stellar-sdk": "^7.x.x" + "stellar-sdk": "^8.2.3" }, "scripts": { "prepare": "yarn build ; yarn build:commonjs", @@ -67,7 +67,7 @@ "prettier": "^1.17.0", "regenerator-runtime": "^0.13.3", "sinon": "^7.3.1", - "stellar-sdk": "^6.0.0", + "stellar-sdk": "^8.2.3", "terser-webpack-plugin": "^2.3.0", "ts-loader": "^6.2.1", "tsc-watch": "^2.1.2", diff --git a/src/KeyManager.test.ts b/src/KeyManager.test.ts index 7b211e60..8cc915d0 100644 --- a/src/KeyManager.test.ts +++ b/src/KeyManager.test.ts @@ -1,6 +1,7 @@ import { mockRandomForEach } from "jest-mock-random"; +import randomBytes from "randombytes"; import sinon from "sinon"; -import StellarBase from "stellar-base"; +import StellarBase, { Operation } from "stellar-base"; import { KeyType } from "./constants/keys"; import { KeyManager } from "./KeyManager"; @@ -290,6 +291,7 @@ describe("KeyManager", function() { password, authServer, authServerKey: "no key needed", + authServerHomeDomains: ["stellar.org"], }); expect("This test failed").toBe(null); @@ -298,7 +300,7 @@ describe("KeyManager", function() { } }); - test("Accepts challenges with zero seqs", async () => { + test("Accepts challenges that are properly formatted", async () => { const authServer = "https://www.stellar.org/auth"; const password = "very secure password"; @@ -308,21 +310,51 @@ describe("KeyManager", function() { const accountKey = StellarBase.Keypair.random(); const account = new StellarBase.Account(accountKey.publicKey(), "-1"); - const txBuild = new StellarBase.TransactionBuilder(account, { - fee: "10000", + // set up the manager + const testStore = new MemoryKeyStore(); + const testKeyManager = new KeyManager({ + keyStore: testStore, + }); + + testKeyManager.registerEncrypter(IdentityEncrypter); + + const keypair = StellarBase.Keypair.master(keyNetwork); + + // A Base64 digit represents 6 bits, to generate a random 64 bytes + // base64 string, we need 48 random bytes = (64 * 6)/8 + // + // Each Base64 digit is in ASCII and each ASCII characters when + // turned into binary represents 8 bits = 1 bytes. + const value = randomBytes(48).toString("base64"); + + const tx = new StellarBase.TransactionBuilder(account, { + fee: StellarBase.BASE_FEE, networkPassphrase: keyNetwork, }) - .setTimeout(1000) + .addOperation( + Operation.manageData({ + name: `stellar.org auth`, + value, + source: keypair.publicKey(), + }), + ) + .addOperation( + Operation.manageData({ + name: "web_auth_domain", + value: new URL(authServer).hostname, + source: account.accountId(), + }), + ) + .setTimeout(300) .build(); - txBuild.sign(accountKey); - const tx = txBuild.toXDR(); + tx.sign(accountKey); fetch // @ts-ignore .mockResponseOnce( JSON.stringify({ - transaction: tx, + transaction: tx.toXDR(), network_passphrase: keyNetwork, }), ) @@ -335,6 +367,39 @@ describe("KeyManager", function() { }), ); + // save this key + const keyMetadata = await testKeyManager.storeKey({ + key: { + type: KeyType.plaintextKey, + publicKey: keypair.publicKey(), + privateKey: keypair.secret(), + network: keyNetwork, + }, + password, + encrypterName: "IdentityEncrypter", + }); + + const res = await testKeyManager.fetchAuthToken({ + id: keyMetadata.id, + password, + authServer, + authServerKey: account.accountId(), + authServerHomeDomains: ["stellar.org"], + }); + + expect(res).toBe(token); + }); + + test("Rejects TXs with non-zero seq numbers", async () => { + const authServer = "https://www.stellar.org/auth"; + const password = "very secure password"; + + const keyNetwork = StellarBase.Networks.TESTNET; + + const token = "👍"; + const accountKey = StellarBase.Keypair.random(); + const account = new StellarBase.Account(accountKey.publicKey(), "1"); + // set up the manager const testStore = new MemoryKeyStore(); const testKeyManager = new KeyManager({ @@ -345,6 +410,53 @@ describe("KeyManager", function() { const keypair = StellarBase.Keypair.master(keyNetwork); + // A Base64 digit represents 6 bits, to generate a random 64 bytes + // base64 string, we need 48 random bytes = (64 * 6)/8 + // + // Each Base64 digit is in ASCII and each ASCII characters when + // turned into binary represents 8 bits = 1 bytes. + const value = randomBytes(48).toString("base64"); + + const tx = new StellarBase.TransactionBuilder(account, { + fee: StellarBase.BASE_FEE, + networkPassphrase: keyNetwork, + }) + .addOperation( + Operation.manageData({ + name: `stellar.org auth`, + value, + source: keypair.publicKey(), + }), + ) + .addOperation( + Operation.manageData({ + name: "web_auth_domain", + value: new URL(authServer).hostname, + source: account.accountId(), + }), + ) + .setTimeout(300) + .build(); + + tx.sign(accountKey); + + fetch + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + transaction: tx.toXDR(), + network_passphrase: keyNetwork, + }), + ) + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + token, + status: 1, + message: "Good job friend", + }), + ); + // save this key const keyMetadata = await testKeyManager.storeKey({ key: { @@ -358,45 +470,32 @@ describe("KeyManager", function() { }); try { - const res = await testKeyManager.fetchAuthToken({ + await testKeyManager.fetchAuthToken({ id: keyMetadata.id, password, authServer, authServerKey: account.accountId(), + authServerHomeDomains: ["stellar.org"], }); - expect(res).toBe(token); + expect("This test failed: transaction didn't cause error").toBe(null); } catch (e) { - expect(e).toBe(null); + expect(e.toString()).toMatch( + `InvalidSep10ChallengeError: The transaction` + + ` sequence number should be zero`, + ); } }); - test("Rejects TXs with non-zero seq numbers", async () => { + test("Reject challenges that don't match key network", async () => { const authServer = "https://www.stellar.org/auth"; const password = "very secure password"; const keyNetwork = StellarBase.Networks.TESTNET; - const account = new StellarBase.Account( - StellarBase.Keypair.random().publicKey(), - "1", - ); - - const tx = new StellarBase.TransactionBuilder(account, { - fee: "10000", - networkPassphrase: keyNetwork, - }) - .setTimeout(1000) - .build() - .toXDR(); - - // @ts-ignore - fetch.mockResponseOnce( - JSON.stringify({ - transaction: tx, - network_passphrase: keyNetwork, - }), - ); + const token = "👍"; + const accountKey = StellarBase.Keypair.random(); + const account = new StellarBase.Account(accountKey.publicKey(), "-1"); // set up the manager const testStore = new MemoryKeyStore(); @@ -408,68 +507,188 @@ describe("KeyManager", function() { const keypair = StellarBase.Keypair.master(keyNetwork); + // A Base64 digit represents 6 bits, to generate a random 64 bytes + // base64 string, we need 48 random bytes = (64 * 6)/8 + // + // Each Base64 digit is in ASCII and each ASCII characters when + // turned into binary represents 8 bits = 1 bytes. + const value = randomBytes(48).toString("base64"); + + const tx = new StellarBase.TransactionBuilder(account, { + fee: StellarBase.BASE_FEE, + networkPassphrase: keyNetwork, + }) + .addOperation( + Operation.manageData({ + name: `stellar.org auth`, + value, + source: keypair.publicKey(), + }), + ) + .addOperation( + Operation.manageData({ + name: "web_auth_domain", + value: new URL(authServer).hostname, + source: account.accountId(), + }), + ) + .setTimeout(300) + .build(); + + tx.sign(accountKey); + + fetch + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + transaction: tx.toXDR(), + network_passphrase: keyNetwork, + }), + ) + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + token, + status: 1, + message: "Good job friend", + }), + ); + // save this key const keyMetadata = await testKeyManager.storeKey({ key: { type: KeyType.plaintextKey, publicKey: keypair.publicKey(), privateKey: keypair.secret(), - network: keyNetwork, + network: StellarBase.Networks.PUBLIC, }, password, encrypterName: "IdentityEncrypter", }); try { - await testKeyManager.fetchAuthToken({ + const res = await testKeyManager.fetchAuthToken({ id: keyMetadata.id, password, authServer, authServerKey: account.accountId(), + authServerHomeDomains: ["stellar.org"], }); - expect("This test failed: transaction didn't cause error").toBe(null); + expect(res).toBe(null); } catch (e) { - expect(e.toString()).toMatch(`Invalid transaction`); + expect(e.toString()).toContain("Network mismatch"); } }); - test("Accepts TXs with matching source and signature", async () => { + test("Reject TXs with matching source but no matching sig", async () => { const authServer = "https://www.stellar.org/auth"; const password = "very secure password"; const keyNetwork = StellarBase.Networks.TESTNET; + const token = "👍"; const accountKey = StellarBase.Keypair.random(); - + const badKey = StellarBase.Keypair.random(); const account = new StellarBase.Account(accountKey.publicKey(), "-1"); - const txBuilder = new StellarBase.TransactionBuilder(account, { - fee: "10000", + // set up the manager + const testStore = new MemoryKeyStore(); + const testKeyManager = new KeyManager({ + keyStore: testStore, + }); + + testKeyManager.registerEncrypter(IdentityEncrypter); + + const keypair = StellarBase.Keypair.master(keyNetwork); + + // A Base64 digit represents 6 bits, to generate a random 64 bytes + // base64 string, we need 48 random bytes = (64 * 6)/8 + // + // Each Base64 digit is in ASCII and each ASCII characters when + // turned into binary represents 8 bits = 1 bytes. + const value = randomBytes(48).toString("base64"); + + const tx = new StellarBase.TransactionBuilder(account, { + fee: StellarBase.BASE_FEE, networkPassphrase: keyNetwork, }) - .setTimeout(1000) + .addOperation( + Operation.manageData({ + name: `stellar.org auth`, + value, + source: keypair.publicKey(), + }), + ) + .addOperation( + Operation.manageData({ + name: "web_auth_domain", + value: new URL(authServer).hostname, + source: account.accountId(), + }), + ) + .setTimeout(300) .build(); - txBuilder.sign(accountKey); - - const tx = txBuilder.toXDR(); + tx.sign(badKey); fetch // @ts-ignore .mockResponseOnce( JSON.stringify({ - transaction: tx, + transaction: tx.toXDR(), network_passphrase: keyNetwork, }), - ) // @ts-ignore + ) + // @ts-ignore .mockResponseOnce( JSON.stringify({ - token: "Good job", + token, status: 1, message: "Good job friend", }), ); + + // save this key + const keyMetadata = await testKeyManager.storeKey({ + key: { + type: KeyType.plaintextKey, + publicKey: keypair.publicKey(), + privateKey: keypair.secret(), + network: keyNetwork, + }, + password, + encrypterName: "IdentityEncrypter", + }); + + try { + await testKeyManager.fetchAuthToken({ + id: keyMetadata.id, + password, + authServer, + authServerKey: accountKey.publicKey(), + authServerHomeDomains: ["stellar.org"], + }); + + expect("This test failed: transaction didn't cause error").toBe(null); + } catch (e) { + expect(e.toString()).toMatch( + `InvalidSep10ChallengeError: Transaction not signed by server`, + ); + } + }); + + test("Accept TXs with multiple sigs where 1 is good", async () => { + const authServer = "https://www.stellar.org/auth"; + const password = "very secure password"; + + const keyNetwork = StellarBase.Networks.TESTNET; + + const token = "👍"; + const accountKey = StellarBase.Keypair.random(); + const badKey = StellarBase.Keypair.random(); + const account = new StellarBase.Account(accountKey.publicKey(), "-1"); + // set up the manager const testStore = new MemoryKeyStore(); const testKeyManager = new KeyManager({ @@ -480,6 +699,54 @@ describe("KeyManager", function() { const keypair = StellarBase.Keypair.master(keyNetwork); + // A Base64 digit represents 6 bits, to generate a random 64 bytes + // base64 string, we need 48 random bytes = (64 * 6)/8 + // + // Each Base64 digit is in ASCII and each ASCII characters when + // turned into binary represents 8 bits = 1 bytes. + const value = randomBytes(48).toString("base64"); + + const tx = new StellarBase.TransactionBuilder(account, { + fee: StellarBase.BASE_FEE, + networkPassphrase: keyNetwork, + }) + .addOperation( + Operation.manageData({ + name: `stellar.org auth`, + value, + source: keypair.publicKey(), + }), + ) + .addOperation( + Operation.manageData({ + name: "web_auth_domain", + value: new URL(authServer).hostname, + source: account.accountId(), + }), + ) + .setTimeout(300) + .build(); + + tx.sign(accountKey); + tx.sign(badKey); + + fetch + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + transaction: tx.toXDR(), + network_passphrase: keyNetwork, + }), + ) + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + token, + status: 1, + message: "Good job friend", + }), + ); + // save this key const keyMetadata = await testKeyManager.storeKey({ key: { @@ -492,44 +759,27 @@ describe("KeyManager", function() { encrypterName: "IdentityEncrypter", }); - await testKeyManager.fetchAuthToken({ + const res = await testKeyManager.fetchAuthToken({ id: keyMetadata.id, password, authServer, - authServerKey: accountKey.publicKey(), + authServerKey: account.accountId(), + authServerHomeDomains: ["stellar.org"], }); + + expect(res).toBe(token); }); - test("Reject TXs with matching source but bad sig", async () => { + test("Reject TXs with incorrect auth server", async () => { const authServer = "https://www.stellar.org/auth"; const password = "very secure password"; const keyNetwork = StellarBase.Networks.TESTNET; + const token = "👍"; const accountKey = StellarBase.Keypair.random(); - - const account = new StellarBase.Account(accountKey.publicKey(), "-1"); - const badKey = StellarBase.Keypair.random(); - - const txBuilder = new StellarBase.TransactionBuilder(account, { - fee: "10000", - networkPassphrase: keyNetwork, - }) - .setTimeout(1000) - .build(); - - txBuilder.sign(badKey); - - const tx = txBuilder.toXDR(); - - // @ts-ignore - fetch.mockResponseOnce( - JSON.stringify({ - transaction: tx, - network_passphrase: keyNetwork, - }), - ); + const account = new StellarBase.Account(accountKey.publicKey(), "-1"); // set up the manager const testStore = new MemoryKeyStore(); @@ -541,6 +791,53 @@ describe("KeyManager", function() { const keypair = StellarBase.Keypair.master(keyNetwork); + // A Base64 digit represents 6 bits, to generate a random 64 bytes + // base64 string, we need 48 random bytes = (64 * 6)/8 + // + // Each Base64 digit is in ASCII and each ASCII characters when + // turned into binary represents 8 bits = 1 bytes. + const value = randomBytes(48).toString("base64"); + + const tx = new StellarBase.TransactionBuilder(account, { + fee: StellarBase.BASE_FEE, + networkPassphrase: keyNetwork, + }) + .addOperation( + Operation.manageData({ + name: `stellar.org auth`, + value, + source: keypair.publicKey(), + }), + ) + .addOperation( + Operation.manageData({ + name: "web_auth_domain", + value: "creepystellar.net", + source: account.accountId(), + }), + ) + .setTimeout(300) + .build(); + + tx.sign(badKey); + + fetch + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + transaction: tx.toXDR(), + network_passphrase: keyNetwork, + }), + ) + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + token, + status: 1, + message: "Good job friend", + }), + ); + // save this key const keyMetadata = await testKeyManager.storeKey({ key: { @@ -559,42 +856,27 @@ describe("KeyManager", function() { password, authServer, authServerKey: accountKey.publicKey(), + authServerHomeDomains: ["stellar.org"], }); expect("This test failed: transaction didn't cause error").toBe(null); } catch (e) { - expect(e.toString()).toMatch(`Signing key doesn't match`); + expect(e.toString()).toMatch( + `InvalidSep10ChallengeError: 'web_auth_domain' operation ` + + `value does not match www.stellar.org`, + ); } }); - test("Rejects TXs with non-matching signatures", async () => { + test("Rejects TXs where source doesn't match", async () => { const authServer = "https://www.stellar.org/auth"; const password = "very secure password"; const keyNetwork = StellarBase.Networks.TESTNET; - const badKey = StellarBase.Keypair.random(); - - const account = new StellarBase.Account(badKey.publicKey(), "-1"); - - const txBuilder = new StellarBase.TransactionBuilder(account, { - fee: "10000", - networkPassphrase: keyNetwork, - }) - .setTimeout(1000) - .build(); - - txBuilder.sign(badKey); - - const tx = txBuilder.toXDR(); - - // @ts-ignore - fetch.mockResponseOnce( - JSON.stringify({ - transaction: tx, - network_passphrase: keyNetwork, - }), - ); + const token = "👍"; + const accountKey = StellarBase.Keypair.random(); + const account = new StellarBase.Account(accountKey.publicKey(), "-1"); // set up the manager const testStore = new MemoryKeyStore(); @@ -606,6 +888,53 @@ describe("KeyManager", function() { const keypair = StellarBase.Keypair.master(keyNetwork); + // A Base64 digit represents 6 bits, to generate a random 64 bytes + // base64 string, we need 48 random bytes = (64 * 6)/8 + // + // Each Base64 digit is in ASCII and each ASCII characters when + // turned into binary represents 8 bits = 1 bytes. + const value = randomBytes(48).toString("base64"); + + const tx = new StellarBase.TransactionBuilder(account, { + fee: StellarBase.BASE_FEE, + networkPassphrase: keyNetwork, + }) + .addOperation( + Operation.manageData({ + name: `stellar.org auth`, + value, + source: keypair.publicKey(), + }), + ) + .addOperation( + Operation.manageData({ + name: "web_auth_domain", + value: new URL(authServer).hostname, + source: account.accountId(), + }), + ) + .setTimeout(300) + .build(); + + tx.sign(accountKey); + + fetch + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + transaction: tx.toXDR(), + network_passphrase: keyNetwork, + }), + ) + // @ts-ignore + .mockResponseOnce( + JSON.stringify({ + token, + status: 1, + message: "Good job friend", + }), + ); + // save this key const keyMetadata = await testKeyManager.storeKey({ key: { @@ -626,11 +955,15 @@ describe("KeyManager", function() { password, authServer, authServerKey: realKey, + authServerHomeDomains: ["stellar.org"], }); expect("This test failed: transaction didn't cause error").toBe(null); } catch (e) { - expect(e.toString()).toMatch(`Signing key doesn't match`); + expect(e.toString()).toMatch( + `InvalidSep10ChallengeError: The transaction source account` + + ` is not equal to the server's account`, + ); } }); }); diff --git a/src/KeyManager.ts b/src/KeyManager.ts index 544ad719..ea4c6c3e 100644 --- a/src/KeyManager.ts +++ b/src/KeyManager.ts @@ -1,4 +1,4 @@ -import StellarSdk, { Transaction } from "stellar-sdk"; +import StellarSdk, { Transaction, Utils } from "stellar-sdk"; import { albedoHandler } from "./keyTypeHandlers/albedo"; import { freighterHandler } from "./keyTypeHandlers/freighter"; @@ -281,6 +281,7 @@ export class KeyManager { * computed as `sha1(private key + public key)`. * @param {string} params.password The password that will decrypt that secret * @param {string} params.authServer The URL of the authentication server + * @param {array} params.authServerHomeDomains The home domain(s) of the authentication server * @param {string} params.authServerKey Check the challenge transaction * for this key as source and signature. * @param {string} [params.account] The authenticating public key. If not @@ -290,7 +291,13 @@ export class KeyManager { */ // tslint:enable max-line-length public async fetchAuthToken(params: GetAuthTokenParams): Promise { - const { id, password, authServer, authServerKey } = params; + const { + id, + password, + authServer, + authServerKey, + authServerHomeDomains, + } = params; let { account } = params; // throw errors for missing params @@ -303,6 +310,12 @@ export class KeyManager { if (!authServer) { throw new Error("Required parameter `authServer` is missing!"); } + if (!authServerKey) { + throw new Error("Required parameter `authServerKey` is missing!"); + } + if (!authServerHomeDomains) { + throw new Error("Required parameter `authServerHomeDomains` is missing!"); + } let key = this._readFromCache(id); @@ -340,69 +353,42 @@ export class KeyManager { const text = await challengeRes.text(); - let transaction; - let network_passphrase; - let error; + let json; try { - const json = JSON.parse(text); - - transaction = json.transaction; - network_passphrase = json.network_passphrase; - error = json.error; + json = JSON.parse(text); } catch (e) { throw new Error(`Request for challenge returned invalid JSON: ${text}`); } - if (error) { - throw new Error(error); + if (json.error) { + throw new Error(json.error); } // Throw error when network_passphrase is returned, and doesn't match - if (network_passphrase !== undefined && keyNetwork !== network_passphrase) { + if ( + json.network_passphrase !== undefined && + keyNetwork !== json.network_passphrase + ) { throw new Error( ` - Network mismatch: the transfer server expects "${network_passphrase}", - but you're using "${keyNetwork}" - `, - ); - } - - const keyHandler = this.keyHandlerMap[key.type]; - - const firstTransaction = new Transaction(transaction, keyNetwork); - - if (firstTransaction.sequence !== "0") { - throw new Error( - `Invalid transaction: Expected a sequence number 0, but got ${ - firstTransaction.sequence - }`, + Network mismatch: the transfer server expects "${ + json.network_passphrase + }", + but you're using "${keyNetwork}" + `, ); } - if (authServerKey) { - if (firstTransaction.source !== authServerKey) { - throw new Error( - `Signing key doesn't match: Expected ${authServerKey} but got - ${firstTransaction.source}`, - ); - } + const firstTransaction = Utils.readChallengeTx( + json.transaction, + authServerKey, + keyNetwork, + authServerHomeDomains, + new URL(authServer).hostname, + ).tx; - if ( - !firstTransaction.signatures.some((signature) => - signature - .hint() - .equals( - StellarSdk.Keypair.fromPublicKey(authServerKey).signatureHint(), - ), - ) - ) { - throw new Error( - `Signing key doesn't match: Expected ${authServerKey} but got - something different`, - ); - } - } + const keyHandler = this.keyHandlerMap[key.type]; const signedTransaction = await keyHandler.signTransaction({ transaction: firstTransaction, diff --git a/src/types/keys.ts b/src/types/keys.ts index 1b09b826..20a004cd 100644 --- a/src/types/keys.ts +++ b/src/types/keys.ts @@ -169,6 +169,7 @@ export interface GetAuthTokenParams { id: string; password: string; authServer: string; + authServerHomeDomains: [string]; authServerKey: string; account?: string; } diff --git a/yarn.lock b/yarn.lock index 76939ba3..daab0fc5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1547,13 +1547,12 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== -axios@^0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" - integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== +axios@0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== dependencies: - follow-redirects "1.5.10" - is-buffer "^2.0.2" + follow-redirects "^1.10.0" babel-jest@^24.5.0, babel-jest@^24.7.1: version "24.7.1" @@ -2381,13 +2380,6 @@ date-fns@^1.23.0, date-fns@^1.27.2: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -3003,12 +2995,10 @@ fn-name@~2.0.1: resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7" integrity sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc= -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" +follow-redirects@^1.10.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" + integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== for-in@^1.0.2: version "1.0.2" @@ -3590,11 +3580,6 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" - integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== - is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" @@ -6552,10 +6537,10 @@ stealthy-require@^1.1.1: resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= -stellar-base@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/stellar-base/-/stellar-base-4.0.0.tgz#5eb314c76a2054b4df8bcec1278b78172b0fe663" - integrity sha512-isn7FoecIcr6lr38oT132UkrYPOEsZy/XAkXteClZpuBBK2aZn0qjyyX4WAoA6cQhnJw/lQQwND+qfijRETvyg== +stellar-base@^5.2.1: + version "5.3.0" + resolved "https://registry.yarnpkg.com/stellar-base/-/stellar-base-5.3.0.tgz#15e8d9f3767a62bda14d55f0c4347d27987ae1f6" + integrity sha512-8LCOX/D/Zp5DBhcTwXQSh9v25sHivkCJc+FSPncqhvMYgvQQg8w+2kj9hCFg1SAxkLJOjSpfzObrUaTl+CFFjw== dependencies: base32.js "^0.1.0" bignumber.js "^4.0.0" @@ -6567,23 +6552,23 @@ stellar-base@^4.0.0: optionalDependencies: sodium-native "^2.3.0" -stellar-sdk@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/stellar-sdk/-/stellar-sdk-6.0.0.tgz#65dfe14f73fe534f29496e1f91f9153075c70f82" - integrity sha512-S51rODPjcypv4nvDjAEgnpIbKE7lYGFA+UjN/GbNYh45qgHjuDqK5279+DOfl6RrJ9AENR5OoDfh9jEuE/CFBw== +stellar-sdk@^8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/stellar-sdk/-/stellar-sdk-8.2.3.tgz#2970211877937e487b4e1f88021200cf0ddf8603" + integrity sha512-RlrR6DD+706vgA1iVDXteU/x3bdqFDthf+4M3C19D/owmF0GCR/FoRQpnPqqRJ0C/rbbdZ6YjAyKO6Q0GSbDWw== dependencies: "@types/eventsource" "^1.1.2" "@types/node" ">= 8" "@types/randombytes" "^2.0.0" "@types/urijs" "^1.19.6" - axios "^0.19.0" + axios "0.21.1" bignumber.js "^4.0.0" detect-node "^2.0.4" es6-promise "^4.2.4" eventsource "^1.0.7" lodash "^4.17.11" randombytes "^2.1.0" - stellar-base "^4.0.0" + stellar-base "^5.2.1" toml "^2.3.0" tslib "^1.10.0" urijs "^1.19.1"