mirror of
https://github.com/fullstack-cash/bch-api.git
synced 2026-09-22 09:12:05 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9e976cc24 | ||
|
|
5644b53cf8 | ||
|
|
236637f0e0 | ||
|
|
fb1bb0b7ed | ||
|
|
8a91f3ae3a | ||
|
|
80dc296dee | ||
|
|
f01c82631b | ||
|
|
ef2a681edb | ||
|
|
44ce5f2aa9 | ||
|
|
f52a04a337 | ||
|
|
9aa3e5b52a | ||
|
|
71452f4834 | ||
|
|
96f1cb6ad4 | ||
|
|
36dd64db22 | ||
|
|
05de04a569 | ||
|
|
c661799095 | ||
|
|
4f416d6423 | ||
|
|
58dc4da92c | ||
|
|
7b8710d3da | ||
|
|
7976909dbb | ||
|
|
24b85e410d | ||
|
|
ae13d2c42e | ||
|
|
bf0fc2437a |
@@ -28,6 +28,7 @@ test-fullstack-abc.sh
|
|||||||
test-fullstack-bchn.sh
|
test-fullstack-bchn.sh
|
||||||
start-fullstack-abc.sh
|
start-fullstack-abc.sh
|
||||||
start-fullstack-bchn.sh
|
start-fullstack-bchn.sh
|
||||||
|
start-ss-main.sh
|
||||||
|
|
||||||
coverage
|
coverage
|
||||||
start-my-infra
|
start-my-infra
|
||||||
|
|||||||
@@ -93,3 +93,4 @@ Copies of this repository will occasionally be uploaded and hosted on [IPFS](htt
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
[MIT](./LICENSE.md)
|
[MIT](./LICENSE.md)
|
||||||
|
a
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ export RPC_USERNAME=bitcoin
|
|||||||
export RPC_PASSWORD=password
|
export RPC_PASSWORD=password
|
||||||
|
|
||||||
# SLPDB
|
# SLPDB
|
||||||
|
export SLPDB_PASS_GP=somelongpassword
|
||||||
export SLPDB_URL=http://172.17.0.1:12300/
|
export SLPDB_URL=http://172.17.0.1:12300/
|
||||||
export SLPDB_PASS=somelongpassword
|
|
||||||
# Use the same address as SLPDB_URL if you don't have a separate whitelist server.
|
# Use the same address as SLPDB_URL if you don't have a separate whitelist server.
|
||||||
|
export SLPDB_PASS_WL=somelongpassword
|
||||||
export SLPDB_WHITELIST_URL=http://172.17.0.1:12300/
|
export SLPDB_WHITELIST_URL=http://172.17.0.1:12300/
|
||||||
# slp-api alternative SLP validator using slp-validate:
|
# slp-api alternative SLP validator using slp-validate:
|
||||||
# https://github.com/Permissionless-Software-Foundation/slp-api
|
# https://github.com/Permissionless-Software-Foundation/slp-api
|
||||||
@@ -54,4 +55,10 @@ export ANON_RATE_LIMIT=50
|
|||||||
# 10 = 100 RPM
|
# 10 = 100 RPM
|
||||||
export WHITELIST_RATE_LIMIT=10
|
export WHITELIST_RATE_LIMIT=10
|
||||||
|
|
||||||
|
# Set logging parameters
|
||||||
|
#1m means no more than 1 megabyte
|
||||||
|
export LOG_MAX_SIZE=1m
|
||||||
|
#5d means store no more than 5 days
|
||||||
|
export LOG_MAX_FILES=5d
|
||||||
|
|
||||||
npm start
|
npm start
|
||||||
|
|||||||
Generated
+330
-1225
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -29,7 +29,7 @@
|
|||||||
"node": ">=10.15.1"
|
"node": ">=10.15.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@psf/bch-js": "^4.11.1",
|
"@psf/bch-js": "^4.15.4",
|
||||||
"apidoc": "^0.26.0",
|
"apidoc": "^0.26.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"bitcore-lib-cash": "^8.23.1",
|
"bitcore-lib-cash": "^8.23.1",
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
"nock": "^13.0.5",
|
"nock": "^13.0.5",
|
||||||
"nyc": "^15.0.0",
|
"nyc": "^15.0.0",
|
||||||
"prettier": "^2.0.0",
|
"prettier": "^2.0.0",
|
||||||
"semantic-release": "^17.3.1",
|
"semantic-release": "^17.3.9",
|
||||||
"sinon": "^9.0.0",
|
"sinon": "^9.0.0",
|
||||||
"standard": "^14.3.1"
|
"standard": "^14.3.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -129,9 +129,19 @@ class RateLimits {
|
|||||||
const resource = _this.getResource(req.url)
|
const resource = _this.getResource(req.url)
|
||||||
wlogger.debug(`resource: ${resource}`)
|
wlogger.debug(`resource: ${resource}`)
|
||||||
|
|
||||||
|
// Key will be the JWT ID if it exists, otherwise the IP address of the caller.
|
||||||
let key = userId || req.ip
|
let key = userId || req.ip
|
||||||
res.locals.key = key // Feedback for tests.
|
res.locals.key = key // Feedback for tests.
|
||||||
|
|
||||||
|
// For internal calls that make a lot of internal calls, like
|
||||||
|
// hydrateUtxoDetails(), the origin of the caller will be passed in
|
||||||
|
// via the POST body.
|
||||||
|
const keyIsLocal = key.includes('172.17.0.1') || key.includes('127.0.0.1')
|
||||||
|
if (req.body && req.body.ip && keyIsLocal) {
|
||||||
|
key = req.body.ip
|
||||||
|
}
|
||||||
|
console.log(`key: ${key}`)
|
||||||
|
|
||||||
// const pointsToConsume = userId ? 1 : 30
|
// const pointsToConsume = userId ? 1 : 30
|
||||||
decoded.resource = resource
|
decoded.resource = resource
|
||||||
let pointsToConsume = _this.calcPoints(decoded)
|
let pointsToConsume = _this.calcPoints(decoded)
|
||||||
|
|||||||
+41
-14
@@ -35,7 +35,10 @@ util.inspect.defaultOptions = { depth: 5 }
|
|||||||
|
|
||||||
// Determine the Access password for a private instance of SLPDB.
|
// Determine the Access password for a private instance of SLPDB.
|
||||||
// https://gist.github.com/christroutner/fc717ca704dec3dded8b52fae387eab2
|
// https://gist.github.com/christroutner/fc717ca704dec3dded8b52fae387eab2
|
||||||
const SLPDB_PASS = process.env.SLPDB_PASS ? process.env.SLPDB_PASS : 'BITBOX'
|
// Password for General Purpose (GP) SLPDB.
|
||||||
|
const SLPDB_PASS_GP = process.env.SLPDB_PASS_GP ? process.env.SLPDB_PASS_GP : 'BITBOX'
|
||||||
|
// Password for Whitelist (WL) SLPDB.
|
||||||
|
const SLPDB_PASS_WL = process.env.SLPDB_PASS_WL ? process.env.SLPDB_PASS_WL : 'BITBOX'
|
||||||
|
|
||||||
// const rawtransactions = require('./full-node/rawtransactions')
|
// const rawtransactions = require('./full-node/rawtransactions')
|
||||||
const RawTransactions = require('./full-node/rawtransactions')
|
const RawTransactions = require('./full-node/rawtransactions')
|
||||||
@@ -43,9 +46,9 @@ const rawTransactions = new RawTransactions()
|
|||||||
|
|
||||||
// Setup REST and TREST URLs used by slpjs
|
// Setup REST and TREST URLs used by slpjs
|
||||||
// Dev note: this allows for unit tests to mock the URL.
|
// Dev note: this allows for unit tests to mock the URL.
|
||||||
if (!process.env.REST_URL) process.env.REST_URL = 'https://rest.bitcoin.com/v2/'
|
if (!process.env.REST_URL) process.env.REST_URL = 'https://bchn.fullstack.cash/v4/'
|
||||||
if (!process.env.TREST_URL) {
|
if (!process.env.TREST_URL) {
|
||||||
process.env.TREST_URL = 'https://trest.bitcoin.com/v2/'
|
process.env.TREST_URL = 'https://testnet.fullstack.cash/v4/'
|
||||||
}
|
}
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
@@ -434,7 +437,7 @@ class Slp {
|
|||||||
const b64 = Buffer.from(s).toString('base64')
|
const b64 = Buffer.from(s).toString('base64')
|
||||||
const url = `${process.env.SLPDB_URL}q/${b64}`
|
const url = `${process.env.SLPDB_URL}q/${b64}`
|
||||||
|
|
||||||
const options = _this.generateCredentials()
|
const options = _this.generateCredentialsGP()
|
||||||
// Request options
|
// Request options
|
||||||
const opt = {
|
const opt = {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -585,7 +588,7 @@ class Slp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = _this.generateCredentials()
|
const options = _this.generateCredentialsGP()
|
||||||
|
|
||||||
// Collect an array of promises, one for each request to slpserve.
|
// Collect an array of promises, one for each request to slpserve.
|
||||||
// This is a nested array of promises.
|
// This is a nested array of promises.
|
||||||
@@ -807,7 +810,7 @@ class Slp {
|
|||||||
const b64 = Buffer.from(s).toString('base64')
|
const b64 = Buffer.from(s).toString('base64')
|
||||||
const url = `${process.env.SLPDB_URL}q/${b64}`
|
const url = `${process.env.SLPDB_URL}q/${b64}`
|
||||||
|
|
||||||
const options = _this.generateCredentials()
|
const options = _this.generateCredentialsGP()
|
||||||
const opt = {
|
const opt = {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
baseURL: url,
|
baseURL: url,
|
||||||
@@ -996,7 +999,7 @@ class Slp {
|
|||||||
const url = `${process.env.SLPDB_URL}q/${b64}`
|
const url = `${process.env.SLPDB_URL}q/${b64}`
|
||||||
// console.log('url: ', url)
|
// console.log('url: ', url)
|
||||||
|
|
||||||
const options = _this.generateCredentials()
|
const options = _this.generateCredentialsGP()
|
||||||
|
|
||||||
// Get data from SLPDB.
|
// Get data from SLPDB.
|
||||||
const opt = {
|
const opt = {
|
||||||
@@ -1130,7 +1133,7 @@ class Slp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = _this.generateCredentials()
|
const options = _this.generateCredentialsGP()
|
||||||
|
|
||||||
const s = JSON.stringify(query)
|
const s = JSON.stringify(query)
|
||||||
const b64 = Buffer.from(s).toString('base64')
|
const b64 = Buffer.from(s).toString('base64')
|
||||||
@@ -1330,7 +1333,7 @@ class Slp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = _this.generateCredentials()
|
const options = _this.generateCredentialsWL()
|
||||||
|
|
||||||
const s = JSON.stringify(query)
|
const s = JSON.stringify(query)
|
||||||
const b64 = Buffer.from(s).toString('base64')
|
const b64 = Buffer.from(s).toString('base64')
|
||||||
@@ -1424,7 +1427,7 @@ class Slp {
|
|||||||
const url = `${process.env.SLPDB_WHITELIST_URL}q/${b64}`
|
const url = `${process.env.SLPDB_WHITELIST_URL}q/${b64}`
|
||||||
// console.log('url: ', url)
|
// console.log('url: ', url)
|
||||||
|
|
||||||
const options = _this.generateCredentials()
|
const options = _this.generateCredentialsWL()
|
||||||
|
|
||||||
// Get data from SLPDB.
|
// Get data from SLPDB.
|
||||||
const opt = {
|
const opt = {
|
||||||
@@ -1567,7 +1570,7 @@ class Slp {
|
|||||||
const b64 = Buffer.from(s).toString('base64')
|
const b64 = Buffer.from(s).toString('base64')
|
||||||
const url = `${process.env.SLPDB_URL}q/${b64}`
|
const url = `${process.env.SLPDB_URL}q/${b64}`
|
||||||
|
|
||||||
const options = _this.generateCredentials()
|
const options = _this.generateCredentialsGP()
|
||||||
const opt = {
|
const opt = {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
baseURL: url,
|
baseURL: url,
|
||||||
@@ -1727,11 +1730,32 @@ class Slp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generates a Basic Authorization header for slpserve.
|
// Generates a Basic Authorization header for slpserve.
|
||||||
generateCredentials () {
|
generateCredentialsGP () {
|
||||||
// Generate the Basic Authentication header for a private instance of SLPDB.
|
// Generate the Basic Authentication header for a private instance of SLPDB.
|
||||||
const username = 'BITBOX'
|
const username = 'BITBOX'
|
||||||
const password = SLPDB_PASS
|
const password = SLPDB_PASS_GP
|
||||||
const combined = `${username}:${password}`
|
const combined = `${username}:${password}`
|
||||||
|
// console.log(`combined: ${combined}`)
|
||||||
|
var base64Credential = Buffer.from(combined).toString('base64')
|
||||||
|
var readyCredential = `Basic ${base64Credential}`
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
headers: {
|
||||||
|
authorization: readyCredential
|
||||||
|
},
|
||||||
|
timeout: 15000
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a Basic Authorization header for slpserve.
|
||||||
|
generateCredentialsWL () {
|
||||||
|
// Generate the Basic Authentication header for a private instance of SLPDB.
|
||||||
|
const username = 'BITBOX'
|
||||||
|
const password = SLPDB_PASS_WL
|
||||||
|
const combined = `${username}:${password}`
|
||||||
|
// console.log(`combined: ${combined}`)
|
||||||
var base64Credential = Buffer.from(combined).toString('base64')
|
var base64Credential = Buffer.from(combined).toString('base64')
|
||||||
var readyCredential = `Basic ${base64Credential}`
|
var readyCredential = `Basic ${base64Credential}`
|
||||||
|
|
||||||
@@ -1955,6 +1979,9 @@ class Slp {
|
|||||||
try {
|
try {
|
||||||
const utxos = req.body.utxos
|
const utxos = req.body.utxos
|
||||||
|
|
||||||
|
console.log(`req._remoteAddress: ${req._remoteAddress}`)
|
||||||
|
const ip = req._remoteAddress
|
||||||
|
|
||||||
// Validate inputs
|
// Validate inputs
|
||||||
if (!Array.isArray(utxos)) {
|
if (!Array.isArray(utxos)) {
|
||||||
res.status(422)
|
res.status(422)
|
||||||
@@ -1989,7 +2016,7 @@ class Slp {
|
|||||||
const theseUtxos = utxos[i].utxos
|
const theseUtxos = utxos[i].utxos
|
||||||
|
|
||||||
// Get SLP token details.
|
// Get SLP token details.
|
||||||
const details = await _this.bchjs.SLP.Utils.tokenUtxoDetails(theseUtxos)
|
const details = await _this.bchjs.SLP.Utils.tokenUtxoDetails(theseUtxos, ip)
|
||||||
// console.log('details: ', details)
|
// console.log('details: ', details)
|
||||||
|
|
||||||
// Replace the original UTXO data with the hydrated data.
|
// Replace the original UTXO data with the hydrated data.
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ export RPC_USERNAME=bitcoin
|
|||||||
export RPC_PASSWORD=password
|
export RPC_PASSWORD=password
|
||||||
|
|
||||||
# SLPDB
|
# SLPDB
|
||||||
|
export SLPDB_PASS_GP=somelongpassword
|
||||||
export SLPDB_URL=http://<SLPDB IP>:12300/
|
export SLPDB_URL=http://<SLPDB IP>:12300/
|
||||||
export SLPDB_PASS=somelongpassword
|
|
||||||
# Use the same address as SLPDB_URL if you don't have a separate whitelist server.
|
# Use the same address as SLPDB_URL if you don't have a separate whitelist server.
|
||||||
|
export SLPDB_PASS_WL=somelongpassword
|
||||||
export SLPDB_WHITELIST_URL=http://<SLPDB IP>:12300/
|
export SLPDB_WHITELIST_URL=http://<SLPDB IP>:12300/
|
||||||
# slp-api alternative SLP validator using slp-validate:
|
# slp-api alternative SLP validator using slp-validate:
|
||||||
# https://github.com/Permissionless-Software-Foundation/slp-api
|
# https://github.com/Permissionless-Software-Foundation/slp-api
|
||||||
|
|||||||
+23
-19
@@ -425,25 +425,29 @@ describe('#route-ratelimits & jwt-auth', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle misconfigured token secret', async () => {
|
// CT 2/24/21 This test may have been invalidated by the interal IP address
|
||||||
// Create a new instance of the rate limit so we start with zeroed tracking.
|
// passing that I implemented to get hydrateUtxos() working properly.
|
||||||
rateLimits = new RateLimits()
|
// I'm commenting this out until I can study the side effects of this change,
|
||||||
|
// and why exactly this test is breaking.
|
||||||
req.baseUrl = '/v4'
|
// it('should handle misconfigured token secret', async () => {
|
||||||
req.path = '/control/getNetworkInfo'
|
// // Create a new instance of the rate limit so we start with zeroed tracking.
|
||||||
req.url = req.path
|
// rateLimits = new RateLimits()
|
||||||
req.method = 'GET'
|
//
|
||||||
|
// req.baseUrl = '/v4'
|
||||||
req.locals.jwtToken = 'some-token'
|
// req.path = '/control/getNetworkInfo'
|
||||||
|
// req.url = req.path
|
||||||
next.reset() // reset the stubbed next() function.
|
// req.method = 'GET'
|
||||||
|
//
|
||||||
await rateLimits.rateLimitByResource(req, res, next)
|
// req.locals.jwtToken = 'some-token'
|
||||||
|
//
|
||||||
// Issues with token secret should treat incoming requests as anonymous
|
// next.reset() // reset the stubbed next() function.
|
||||||
// calls with 30 points or 3 RPM.
|
//
|
||||||
assert.equal(res.locals.pointsToConsume, 50)
|
// await rateLimits.rateLimitByResource(req, res, next)
|
||||||
})
|
//
|
||||||
|
// // Issues with token secret should treat incoming requests as anonymous
|
||||||
|
// // calls with 50 points, or 20 RPM.
|
||||||
|
// assert.equal(res.locals.pointsToConsume, 50)
|
||||||
|
// })
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#isInWhitelist', () => {
|
describe('#isInWhitelist', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user