From 1e8e7b79f203984a66a03effa5229aac1740e661 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 11 Nov 2020 14:11:13 -0800 Subject: [PATCH 1/3] Updating comments in e2e rate limit tests --- test/e2e/rate-limits/anonymous-rate-limits.js | 11 +++- .../e2e/rate-limits/basic-auth-rate-limits.js | 55 +++++++++++++++++++ test/e2e/rate-limits/free-rate-limits.js | 4 ++ test/e2e/rate-limits/full-node-rate-limits.js | 4 ++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 test/e2e/rate-limits/basic-auth-rate-limits.js diff --git a/test/e2e/rate-limits/anonymous-rate-limits.js b/test/e2e/rate-limits/anonymous-rate-limits.js index 3b3fcde..c11f15b 100644 --- a/test/e2e/rate-limits/anonymous-rate-limits.js +++ b/test/e2e/rate-limits/anonymous-rate-limits.js @@ -5,12 +5,17 @@ To Run Test: - Update the RESTURL for bch-api you want to test against. - Ensure the BCHJSTOKEN environment variable is set to an empty string. + - If working with bch-api locally, eliminate the local IP address from the + whitelist in bch-api/src/middleware/route-ratelimit.js + + Run this test with this command: + mocha --timeout=30000 anonymous-rate-limits.js */ const assert = require("chai").assert -const RESTURL = `https://api.fullstack.cash/v3/` -// const RESTURL = `http://localhost:3000/v3/` +// const RESTURL = `https://abc.fullstack.cash/v3/` +const RESTURL = `http://localhost:3000/v3/` const BCHJS = require("../../../src/bch-js") const bchjs = new BCHJS({ restURL: RESTURL }) @@ -32,7 +37,7 @@ describe("#anonymous rate limits", () => { it("should throw error when rate limit exceeded", async () => { try { - for (let i = 0; i < 22; i++) await bchjs.Control.getNetworkInfo() + for (let i = 0; i < 35; i++) await bchjs.Control.getNetworkInfo() assert.fail("Unexpected result") } catch (err) { diff --git a/test/e2e/rate-limits/basic-auth-rate-limits.js b/test/e2e/rate-limits/basic-auth-rate-limits.js new file mode 100644 index 0000000..d80a963 --- /dev/null +++ b/test/e2e/rate-limits/basic-auth-rate-limits.js @@ -0,0 +1,55 @@ +/* + Mocha test that verifies that the bch-api server is enforcing its + access rules for Basic Authentication. + + To Run Test: + - Update the restURL for bch-api you want to test against. + - Update the PRO_PASS value with a current PRO_PASSES string used by bch-api. +*/ + +const assert = require("chai").assert + +const PRO_PASS = "testpassword" + +const BCHJS = require("../../../src/bch-js") +const bchjs = new BCHJS({ + restURL: `https://api.fullstack.cash/v3/`, + // restURL: `http://localhost:3000/v3/`, + apiToken: JWT_TOKEN +}) + +describe("#full node rate limits", () => { + it("should allow more than 20 RPM to full node", async () => { + for (let i = 0; i < 22; i++) { + const result = await bchjs.Control.getNetworkInfo() + + if (i === 5) { + // console.log(`validating 5th call: ${i}`) + assert.property(result, "version", "more than 3 calls allowed") + } + + if (i === 15) { + // console.log(`validating 5th call: ${i}`) + assert.property(result, "version", "more than 10 calls allowed") + } + } + }).timeout(45000) + + it("should allow more than 20 RPM to an indexer", async () => { + const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" + + for (let i = 0; i < 22; i++) { + const result = await bchjs.Blockbook.balance(addr) + + if (i === 5) { + // console.log(`validating 5th call: ${i}`) + assert.property(result, "balance", "more than 3 calls allowed") + } + + if (i === 15) { + // console.log(`validating 5th call: ${i}`) + assert.property(result, "balance", "more than 10 calls allowed") + } + } + }).timeout(45000) +}) diff --git a/test/e2e/rate-limits/free-rate-limits.js b/test/e2e/rate-limits/free-rate-limits.js index f31d1d4..736b9a8 100644 --- a/test/e2e/rate-limits/free-rate-limits.js +++ b/test/e2e/rate-limits/free-rate-limits.js @@ -1,4 +1,8 @@ /* + CT 11/11/2020: + There is no longer a free tier. These tests have been deprecated. + + -------- Mocha test that verifies that the bch-api server is enforcing its FREE access rules diff --git a/test/e2e/rate-limits/full-node-rate-limits.js b/test/e2e/rate-limits/full-node-rate-limits.js index 2e7deb9..5996b3d 100644 --- a/test/e2e/rate-limits/full-node-rate-limits.js +++ b/test/e2e/rate-limits/full-node-rate-limits.js @@ -1,4 +1,8 @@ /* + CT 11/11/2020: + There is no longer a free tier. These tests have been deprecated. + + ---- Mocha test that verifies that the bch-api server is enforcing its full-node access rules From 731987b35b949065cd38d1c5db1a339fe4499a40 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 11 Nov 2020 14:56:53 -0800 Subject: [PATCH 2/3] fix(Basic Authentication): Adding back in --- src/bch-js.js | 20 ++++++++++++++++++- src/blockbook.js | 18 +++++++++++++---- src/control.js | 18 +++++++++++++---- .../e2e/rate-limits/basic-auth-rate-limits.js | 6 +++--- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/bch-js.js b/src/bch-js.js index 62d0cc8..23517ba 100644 --- a/src/bch-js.js +++ b/src/bch-js.js @@ -55,9 +55,27 @@ class BCHJS { else if (process.env.BCHJSTOKEN && process.env.BCHJSTOKEN !== "") this.apiToken = process.env.BCHJSTOKEN + // Retrieve the Basic Authentication password. + this.authPass = "" // default value. + if (config && config.authPass && config.authPass !== "") + this.authPass = config.authPass + else if (process.env.BCHJSAUTHPASS && process.env.BCHJSAUTHPASS !== "") + this.authPass = process.env.BCHJSAUTHPASS + + // Generate a Basic Authentication token from an auth password + this.authToken = "" + if (this.authPass) { + console.log(`bch-js initialized with authPass: ${this.authPass}`) + // Generate the header for Basic Authentication. + const combined = `fullstackcash:${this.authPass}` + var base64Credential = Buffer.from(combined).toString("base64") + this.authToken = `Basic ${base64Credential}` + } + const libConfig = { restURL: this.restURL, - apiToken: this.apiToken + apiToken: this.apiToken, + authToken: this.authToken } // console.log(`apiToken: ${this.apiToken}`) diff --git a/src/blockbook.js b/src/blockbook.js index 52eaddd..9494441 100644 --- a/src/blockbook.js +++ b/src/blockbook.js @@ -15,12 +15,22 @@ class Blockbook { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken // console.log(`Blockbook apiToken: ${this.apiToken}`) - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/src/control.js b/src/control.js index 4f52ec3..e11cab6 100644 --- a/src/control.js +++ b/src/control.js @@ -10,11 +10,21 @@ class Control { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/test/e2e/rate-limits/basic-auth-rate-limits.js b/test/e2e/rate-limits/basic-auth-rate-limits.js index d80a963..6bcb1c5 100644 --- a/test/e2e/rate-limits/basic-auth-rate-limits.js +++ b/test/e2e/rate-limits/basic-auth-rate-limits.js @@ -13,9 +13,9 @@ const PRO_PASS = "testpassword" const BCHJS = require("../../../src/bch-js") const bchjs = new BCHJS({ - restURL: `https://api.fullstack.cash/v3/`, - // restURL: `http://localhost:3000/v3/`, - apiToken: JWT_TOKEN + // restURL: `https://api.fullstack.cash/v3/`, + restURL: `http://localhost:3000/v3/`, + authPass: PRO_PASS }) describe("#full node rate limits", () => { From fbbd855145ecf3cc61c5f2f51b6ffe1c6e75e1f1 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 11 Nov 2020 17:47:46 -0800 Subject: [PATCH 3/3] feat(Basic Authentication): Adding authPass for auth token to all libraries --- src/address.js | 17 +++++++++++++++++ src/blockchain.js | 18 ++++++++++++++---- src/electrumx.js | 19 ++++++++++++++----- src/encryption.js | 19 ++++++++++++++----- src/generating.js | 18 ++++++++++++++---- src/mining.js | 18 ++++++++++++++---- src/price.js | 24 ++++++++++++++++-------- src/raw-transactions.js | 18 ++++++++++++++---- src/schnorr.js | 18 ++++++++++++++---- src/slp/slp.js | 31 ++++++++++++++++++++----------- src/util.js | 18 ++++++++++++++---- test/unit/bitbox-shim.js | 25 ------------------------- 12 files changed, 165 insertions(+), 78 deletions(-) delete mode 100644 test/unit/bitbox-shim.js diff --git a/src/address.js b/src/address.js index 270eaad..841a9ee 100644 --- a/src/address.js +++ b/src/address.js @@ -11,6 +11,23 @@ class Address { this.restURL = tmp.restURL this.apiToken = tmp.apiToken + this.authToken = config.authToken + + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } + } + } } /** diff --git a/src/blockchain.js b/src/blockchain.js index 86cbf02..f76e3fb 100644 --- a/src/blockchain.js +++ b/src/blockchain.js @@ -11,11 +11,21 @@ class Blockchain { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/src/electrumx.js b/src/electrumx.js index e2b5ea8..2d38a88 100644 --- a/src/electrumx.js +++ b/src/electrumx.js @@ -11,12 +11,21 @@ class ElectrumX { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}`, - timeout: 15000 + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/src/encryption.js b/src/encryption.js index 4749bef..f035380 100644 --- a/src/encryption.js +++ b/src/encryption.js @@ -11,12 +11,21 @@ class Encryption { this.restURL = config.restURL this.apiToken = config.apiToken this.axios = axios - // console.log(`Blockbook apiToken: ${this.apiToken}`) + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/src/generating.js b/src/generating.js index e465607..e8e6230 100644 --- a/src/generating.js +++ b/src/generating.js @@ -6,11 +6,21 @@ class Generating { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/src/mining.js b/src/mining.js index fe9475b..6890936 100644 --- a/src/mining.js +++ b/src/mining.js @@ -6,11 +6,21 @@ class Mining { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/src/price.js b/src/price.js index 35b41a4..2bc3743 100644 --- a/src/price.js +++ b/src/price.js @@ -6,15 +6,23 @@ class Price { constructor(config) { _this = this - if (config) { - this.restURL = config.restURL - this.apiToken = config.apiToken - } + this.restURL = config.restURL + this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/src/raw-transactions.js b/src/raw-transactions.js index 6b2ceb7..636d903 100644 --- a/src/raw-transactions.js +++ b/src/raw-transactions.js @@ -6,11 +6,21 @@ class RawTransactions { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/src/schnorr.js b/src/schnorr.js index 4db8877..c947526 100644 --- a/src/schnorr.js +++ b/src/schnorr.js @@ -4,11 +4,21 @@ class Schnorr { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } } diff --git a/src/slp/slp.js b/src/slp/slp.js index b91c366..478ba33 100644 --- a/src/slp/slp.js +++ b/src/slp/slp.js @@ -18,22 +18,31 @@ const Utils = require("./utils") // SLP is a superset of BITBOX class SLP { constructor(config) { - const tmp = {} - if (!config || !config.restURL) { - tmp.restURL = `https://api.fullstack.cash/v3/` + this.restURL = config.restURL + this.apiToken = config.apiToken + this.authToken = config.authToken + + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } } else { - tmp.restURL = config.restURL - tmp.apiToken = config.apiToken + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } + } } - this.restURL = tmp.restURL - this.apiToken = tmp.apiToken - - this.Address = new Address(tmp) + this.Address = new Address(config) this.ECPair = ECPair - this.TokenType1 = new TokenType1(tmp) + this.TokenType1 = new TokenType1(config) this.NFT1 = new NFT1(this.restURL) - this.Utils = new Utils(tmp) + this.Utils = new Utils(config) } } diff --git a/src/util.js b/src/util.js index e4ea352..ce3eab2 100644 --- a/src/util.js +++ b/src/util.js @@ -6,11 +6,21 @@ class Util { constructor(config) { this.restURL = config.restURL this.apiToken = config.apiToken + this.authToken = config.authToken - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } } } diff --git a/test/unit/bitbox-shim.js b/test/unit/bitbox-shim.js deleted file mode 100644 index 7d9b74e..0000000 --- a/test/unit/bitbox-shim.js +++ /dev/null @@ -1,25 +0,0 @@ -const chai = require("chai") -const assert = chai.assert -const BCHJS = require("../../src/bch-js") - -// Used for debugging and iterrogating JS objects. -const util = require("util") -util.inspect.defaultOptions = { depth: 1 } - -describe(`#BitboxShim`, () => { - it("should create the shim library", () => { - const BitboxShim = BCHJS.BitboxShim() - const bitbox = new BitboxShim() - - //console.log(`bitbox.Address: ${util.inspect(bitbox.Address)}`) - - assert.hasAnyKeys(bitbox.Address, [ - // "details", - // "utxo", - // "unconfirmed", - // "transactions", - // "toLegacyAddress" - "restURL" - ]) - }) -})