mirror of
https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service.git
synced 2026-09-21 16:52:03 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1592eadd8c | ||
|
|
be1a4c750a | ||
|
|
4572ce3d6b | ||
|
|
fb7d4e6074 | ||
|
|
5467c991de | ||
|
|
ba93c6cc46 | ||
|
|
60b37e4f72 | ||
|
|
02a543323c | ||
|
|
c28bc22084 | ||
|
|
f796dd6076 | ||
|
|
5d624f5c23 | ||
|
|
3eacfb27a6 | ||
|
|
29b3d32743 | ||
|
|
a58e237122 | ||
|
|
c237b33677 | ||
|
|
b48b618d4c | ||
|
|
252834d727 | ||
|
|
04bcd9fd3a | ||
|
|
cc5aba7896 | ||
|
|
50bc5c2d02 | ||
|
|
3251b0dc58 | ||
|
|
090f524b9d | ||
|
|
1846b5da64 | ||
|
|
643dfd8fc0 | ||
|
|
944d721296 | ||
|
|
96e4afd6c8 | ||
|
|
002e6657ff | ||
|
|
fb215b11b7 | ||
|
|
1618289078 | ||
|
|
2ebe42d5f4 | ||
|
|
326271f703 | ||
|
|
0480f54287 | ||
|
|
f9df8c7fab | ||
|
|
2ae550c027 | ||
|
|
eca131fefc | ||
|
|
596645ad6b | ||
|
|
2a2d940e7c | ||
|
|
46b0c595f9 | ||
|
|
eab7a30926 | ||
|
|
85a8efb5bf | ||
|
|
e33ee49879 | ||
|
|
9c53204a91 | ||
|
|
6faf1ccf86 | ||
|
|
8fafe96e01 | ||
|
|
d06c995174 | ||
|
|
2d02904ed1 | ||
|
|
51d7ddb362 | ||
|
|
ee1fbad02a | ||
|
|
f5ae98cb9c | ||
|
|
e416478522 | ||
|
|
ce85dffc97 | ||
|
|
c9f7a43339 | ||
|
|
a885fb7edf | ||
|
|
93d1542522 | ||
|
|
62fadbb394 | ||
|
|
ae37b6533b | ||
|
|
c711fd0ce1 | ||
|
|
05af23b87c | ||
|
|
54b505449b | ||
|
|
8e5f5f2dbd | ||
|
|
c06a9ec874 | ||
|
|
8639a3d363 | ||
|
|
a9ef1ebd66 | ||
|
|
1053191835 | ||
|
|
7d0b536f73 | ||
|
|
cf45a1fc7e | ||
|
|
cc2ada5169 | ||
|
|
cf4029ff00 | ||
|
|
76e4feb1ac | ||
|
|
4a5103d760 | ||
|
|
0b72895102 | ||
|
|
f41cac9fc7 | ||
|
|
8ad1400d3c | ||
|
|
e48a9213c5 | ||
|
|
60e6a8b24f | ||
|
|
85af08b1aa | ||
|
|
2d4bbd9ab0 | ||
|
|
06631a81ad | ||
|
|
24684ac25a | ||
|
|
758de6b088 | ||
|
|
0346898501 | ||
|
|
2e2d092b18 | ||
|
|
c8aefae0cc | ||
|
|
17e465b3ab | ||
|
|
40bb75bf33 | ||
|
|
02201afc59 | ||
|
|
bae98bba28 | ||
|
|
0eb7aeaed1 | ||
|
|
dbd5022c4c | ||
|
|
72ac73c410 | ||
|
|
9b52c81b25 | ||
|
|
7cc13b9ba9 | ||
|
|
3ba866d2d6 | ||
|
|
3d058d9164 | ||
|
|
fde8b16fef | ||
|
|
c5a1eb6f81 | ||
|
|
74f8b60472 | ||
|
|
d57085949c | ||
|
|
9dc40a417a | ||
|
|
81e5592b81 | ||
|
|
44867f0173 | ||
|
|
c46f7357c3 |
@@ -64,6 +64,8 @@ database/
|
||||
system-user-*.json
|
||||
orbitdb
|
||||
ipfsdata
|
||||
.ipfsdata
|
||||
ipfs-service-provider.sh
|
||||
start-bch-wallet-service.sh
|
||||
|
||||
!README.md
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
This is a censorship-resistant, IPFS-based microservice that provides access for wallets to access the Bitcoin Cash (BCH) blockchain. It leverages [bch-js](https://github.com/Permissionless-Software-Foundation/bch-js).
|
||||
|
||||
- [Decentralized Blockchain Service Providers](https://youtu.be/m_33rRXEats) YouTube video demos this software.
|
||||
- [JSON RPC and REST API Documentation](https://ipfs-bch-wallet-service.fullstack.cash/)
|
||||
|
||||
## About This Repository
|
||||
|
||||
@@ -31,6 +32,7 @@ This repository is one step in a longer path. Here are the major milestones of t
|
||||
```bash
|
||||
git clone https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service
|
||||
cd ipfs-bch-wallet-service
|
||||
sudo npm install -g node-pre-gyp
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
+88
-70
@@ -1,3 +1,12 @@
|
||||
/*
|
||||
This Koa server has two interfaces:
|
||||
- REST API over HTTP
|
||||
- JSON RPC over IPFS
|
||||
|
||||
The architecture of the code follows the Clean Architecture pattern:
|
||||
https://troutsblog.com/blog/clean-architecture
|
||||
*/
|
||||
|
||||
// npm libraries
|
||||
const Koa = require('koa')
|
||||
const bodyParser = require('koa-bodyparser')
|
||||
@@ -12,81 +21,90 @@ const cors = require('kcors')
|
||||
|
||||
// Local libraries
|
||||
const config = require('../config') // this first.
|
||||
// const IPFSLib = require('../src/lib/ipfs')
|
||||
const AdminLib = require('../src/adapters/admin')
|
||||
const adminLib = new AdminLib()
|
||||
// const JSONRPC = require('../src/rpc')
|
||||
// const rpc = new JSONRPC()
|
||||
|
||||
const errorMiddleware = require('../src/controllers/rest-api/middleware/error')
|
||||
const { wlogger } = require('../src/adapters/wlogger')
|
||||
|
||||
async function startServer () {
|
||||
// Create a Koa instance.
|
||||
const app = new Koa()
|
||||
app.keys = [config.session]
|
||||
|
||||
// Connect to the Mongo Database.
|
||||
mongoose.Promise = global.Promise
|
||||
mongoose.set('useCreateIndex', true) // Stop deprecation warning.
|
||||
console.log(
|
||||
`Connecting to MongoDB with this connection string: ${config.database}`
|
||||
)
|
||||
await mongoose.connect(config.database, {
|
||||
useUnifiedTopology: true,
|
||||
useNewUrlParser: true
|
||||
})
|
||||
|
||||
// MIDDLEWARE START
|
||||
|
||||
app.use(convert(logger()))
|
||||
app.use(bodyParser())
|
||||
app.use(session())
|
||||
app.use(errorMiddleware())
|
||||
|
||||
// Used to generate the docs.
|
||||
app.use(mount('/', serve(`${process.cwd()}/docs`)))
|
||||
|
||||
// Mount the page for displaying logs.
|
||||
app.use(mount('/logs', serve(`${process.cwd()}/config/logs`)))
|
||||
|
||||
// User Authentication
|
||||
require('../config/passport')
|
||||
app.use(passport.initialize())
|
||||
app.use(passport.session())
|
||||
|
||||
// Attach REST API and JSON RPC controllers to the app.
|
||||
const controllers = require('../src/controllers')
|
||||
await controllers.attachControllers(app)
|
||||
|
||||
// Enable CORS for testing
|
||||
// THIS IS A SECURITY RISK. COMMENT OUT FOR PRODUCTION
|
||||
app.use(cors({ origin: '*' }))
|
||||
|
||||
// MIDDLEWARE END
|
||||
|
||||
console.log(`Running server in environment: ${config.env}`)
|
||||
wlogger.info(`Running server in environment: ${config.env}`)
|
||||
|
||||
await app.listen(config.port)
|
||||
console.log(`Server started on ${config.port}`)
|
||||
|
||||
// Create the system admin user.
|
||||
try {
|
||||
const success = await adminLib.createSystemUser()
|
||||
if (success) console.log('System admin user created.')
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
'Error trying to create system admin. Perhaps one already exists?'
|
||||
)
|
||||
class Server {
|
||||
constructor () {
|
||||
this.adminLib = new AdminLib()
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
// startServer()
|
||||
async startServer () {
|
||||
try {
|
||||
// Create a Koa instance.
|
||||
const app = new Koa()
|
||||
app.keys = [config.session]
|
||||
|
||||
// export default app
|
||||
// module.exports = app
|
||||
module.exports = {
|
||||
startServer
|
||||
// Connect to the Mongo Database.
|
||||
mongoose.Promise = global.Promise
|
||||
mongoose.set('useCreateIndex', true) // Stop deprecation warning.
|
||||
console.log(
|
||||
`Connecting to MongoDB with this connection string: ${config.database}`
|
||||
)
|
||||
await mongoose.connect(config.database, {
|
||||
useUnifiedTopology: true,
|
||||
useNewUrlParser: true
|
||||
})
|
||||
|
||||
console.log(`Starting environment: ${config.env}`)
|
||||
console.log(`Debug level: ${config.debugLevel}`)
|
||||
|
||||
// MIDDLEWARE START
|
||||
|
||||
app.use(convert(logger()))
|
||||
app.use(bodyParser())
|
||||
app.use(session())
|
||||
app.use(errorMiddleware())
|
||||
|
||||
// Used to generate the docs.
|
||||
app.use(mount('/', serve(`${process.cwd()}/docs`)))
|
||||
|
||||
// Mount the page for displaying logs.
|
||||
app.use(mount('/logs', serve(`${process.cwd()}/config/logs`)))
|
||||
|
||||
// User Authentication
|
||||
require('../config/passport')
|
||||
app.use(passport.initialize())
|
||||
app.use(passport.session())
|
||||
|
||||
// Attach REST API and JSON RPC controllers to the app.
|
||||
const Controllers = require('../src/controllers')
|
||||
const controllers = new Controllers()
|
||||
await controllers.attachRESTControllers(app)
|
||||
|
||||
app.controllers = controllers
|
||||
|
||||
// Enable CORS for testing
|
||||
// THIS IS A SECURITY RISK. COMMENT OUT FOR PRODUCTION
|
||||
app.use(cors({ origin: '*' }))
|
||||
|
||||
// MIDDLEWARE END
|
||||
|
||||
console.log(`Running server in environment: ${config.env}`)
|
||||
wlogger.info(`Running server in environment: ${config.env}`)
|
||||
|
||||
await app.listen(config.port)
|
||||
console.log(`Server started on ${config.port}`)
|
||||
|
||||
// Create the system admin user.
|
||||
try {
|
||||
const success = await this.adminLib.createSystemUser()
|
||||
if (success) console.log('System admin user created.')
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
'Error trying to create system admin. Perhaps one already exists?'
|
||||
)
|
||||
}
|
||||
|
||||
// Attach the other IPFS controllers
|
||||
await controllers.attachControllers(app)
|
||||
|
||||
return app
|
||||
} catch (err) {
|
||||
console.error('Could not start server. Error: ', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Server
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
This file should be customized for your app. The string in this file is
|
||||
displayed when a user makes the 'about' JSON RPC call.
|
||||
*/
|
||||
|
||||
module.exports = `
|
||||
This is the about string for the ipfs-service-provider repository:
|
||||
https://github.com/Permissionless-Software-Foundation/ipfs-service-provider
|
||||
|
||||
Brought to you by the Permissionless Software Foundation:
|
||||
https://PSFoundation.cash
|
||||
|
||||
Documentation:
|
||||
https://ipfs-service-provider.fullstack.cash/
|
||||
`
|
||||
Vendored
+19
-5
@@ -5,6 +5,10 @@
|
||||
|
||||
/* eslint no-unneeded-ternary:0 */
|
||||
|
||||
// Get the version from the package.json file.
|
||||
const pkgInfo = require('../../package.json')
|
||||
const version = pkgInfo.version
|
||||
|
||||
const ipfsCoordName = process.env.COORD_NAME
|
||||
? process.env.COORD_NAME
|
||||
: 'ipfs-bch-wallet-service'
|
||||
@@ -28,16 +32,19 @@ module.exports = {
|
||||
: 'emailpassword',
|
||||
|
||||
// FullStack.cash account information, used for automatic JWT handling.
|
||||
AUTHSERVER: process.env.AUTHSERVER
|
||||
getJwtAtStartup: false,
|
||||
authServer: process.env.AUTHSERVER
|
||||
? process.env.AUTHSERVER
|
||||
: 'https://auth.fullstack.cash',
|
||||
APISERVER: process.env.APISERVER
|
||||
apiServer: process.env.APISERVER
|
||||
? process.env.APISERVER
|
||||
: 'https://api.fullstack.cash/v5/',
|
||||
FULLSTACKLOGIN: process.env.FULLSTACKLOGIN
|
||||
fullstackLogin: process.env.FULLSTACKLOGIN
|
||||
? process.env.FULLSTACKLOGIN
|
||||
: 'demo@demo.com',
|
||||
FULLSTACKPASS: process.env.FULLSTACKPASS ? process.env.FULLSTACKPASS : 'demo',
|
||||
fullstackPassword: process.env.FULLSTACKPASS
|
||||
? process.env.FULLSTACKPASS
|
||||
: 'demo',
|
||||
|
||||
// IPFS settings.
|
||||
isCircuitRelay: process.env.ENABLE_CIRCUIT_RELAY ? true : false,
|
||||
@@ -52,6 +59,8 @@ module.exports = {
|
||||
'@context': 'https://schema.org/',
|
||||
'@type': 'WebAPI',
|
||||
name: ipfsCoordName,
|
||||
version,
|
||||
protocol: 'bch-wallet',
|
||||
description:
|
||||
'IPFS service providing BCH blockchain access needed by a wallet.',
|
||||
documentation: 'https://ipfs-bch-wallet-service.fullstack.cash/',
|
||||
@@ -64,5 +73,10 @@ module.exports = {
|
||||
|
||||
// IPFS Ports
|
||||
ipfsTcpPort: process.env.IPFS_TCP_PORT ? process.env.IPFS_TCP_PORT : 5668,
|
||||
ipfsWsPort: process.env.IPFS_WS_PORT ? process.env.IPFS_WS_PORT : 5669
|
||||
ipfsWsPort: process.env.IPFS_WS_PORT ? process.env.IPFS_WS_PORT : 5669,
|
||||
|
||||
// BCH Mnemonic for generating encryption keys and payment address
|
||||
mnemonic: process.env.MNEMONIC ? process.env.MNEMONIC : '',
|
||||
|
||||
debugLevel: process.env.DEBUG_LEVEL ? parseInt(process.env.DEBUG_LEVEL) : 2
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
This is where the mongodb docker container stores its db files.
|
||||
@@ -1,3 +1,4 @@
|
||||
const server = require('./bin/server.js')
|
||||
const Server = require('./bin/server.js')
|
||||
const server = new Server()
|
||||
|
||||
server.startServer()
|
||||
|
||||
Generated
+17560
-19065
File diff suppressed because it is too large
Load Diff
+5
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ipfs-bch-wallet-service",
|
||||
"version": "1.0.0",
|
||||
"version": "1.11.4",
|
||||
"description": "IPFS and REST service providing blockchain access needed by a wallet. ",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -23,12 +23,12 @@
|
||||
},
|
||||
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-service",
|
||||
"dependencies": {
|
||||
"@psf/bch-js": "^4.20.2",
|
||||
"@psf/bch-js": "^4.20.3",
|
||||
"axios": "^0.21.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"glob": "^7.1.6",
|
||||
"ipfs": "^0.54.4",
|
||||
"ipfs-coord": "^4.0.1",
|
||||
"@chris.troutner/ipfs": "2.0.2",
|
||||
"ipfs-coord": "^6.5.6",
|
||||
"jsonrpc-lite": "^2.2.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jwt-bch-lib": "^1.3.0",
|
||||
@@ -45,6 +45,7 @@
|
||||
"koa2-ratelimit": "^0.9.0",
|
||||
"line-reader": "^0.4.0",
|
||||
"mongoose": "^5.11.15",
|
||||
"node-fetch": "npm:@achingbrain/node-fetch@^2.6.7",
|
||||
"nodemailer": "^6.4.17",
|
||||
"passport-local": "^1.0.0",
|
||||
"winston": "^3.3.3",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#IMAGE BUILD COMMANDS
|
||||
# ct-base-ubuntu = ubuntu 18.04 + nodejs v10 LTS
|
||||
FROM christroutner/ct-base-ubuntu
|
||||
FROM christroutner/ct-base-ubuntu:latest
|
||||
MAINTAINER Chris Troutner <chris.troutner@gmail.com>
|
||||
|
||||
#Create the user 'safeuser' and add them to the sudo group.
|
||||
@@ -23,34 +23,33 @@ WORKDIR /home/safeuser
|
||||
#RUN runuser -l safeuser -c "npm config set prefix '~/.npm-global'"
|
||||
|
||||
# Switch to user account.
|
||||
USER safeuser
|
||||
#USER safeuser
|
||||
# Prep 'sudo' commands.
|
||||
RUN echo 'abcd8765' | sudo -S pwd
|
||||
#RUN echo 'abcd8765' | sudo -S pwd
|
||||
|
||||
# Clone the rest.bitcoin.com repository
|
||||
WORKDIR /home/safeuser
|
||||
RUN git clone https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service
|
||||
# RUN mv koa-api-boilerplate koa
|
||||
# RUN mkdir keys
|
||||
|
||||
# Switch to the desired branch. `master` is usually stable,
|
||||
# and `stage` has the most up-to-date changes.
|
||||
WORKDIR /home/safeuser/ipfs-bch-wallet-service
|
||||
|
||||
# For development: switch to unstable branch
|
||||
# RUN git checkout unstable
|
||||
RUN git checkout ct-unstable
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install -g @mapbox/node-pre-gyp
|
||||
RUN npm install
|
||||
|
||||
# Generate the API docs
|
||||
RUN npm run docs
|
||||
|
||||
# Calling out the directorys that should be mounted as external volumes.
|
||||
RUN mkdir /home/safeuser/ipfsdata
|
||||
RUN mkdir /home/safeuser/orbitdb
|
||||
VOLUME /home/safeuser/ipfsdata
|
||||
VOLUME /home/safeuser/orbitdb
|
||||
RUN mkdir /home/safeuser/.ipfsdata
|
||||
#RUN mkdir /home/safeuser/orbitdb
|
||||
#VOLUME /home/safeuser/ipfsdata
|
||||
#VOLUME /home/safeuser/orbitdb
|
||||
|
||||
# Start the application.
|
||||
COPY start-production.sh start-production.sh
|
||||
@@ -6,7 +6,7 @@ bch-wallet-mongodb:
|
||||
ports:
|
||||
- '5555:27017' # <host port>:<container port>
|
||||
volumes:
|
||||
- ./database:/data/db
|
||||
- ../data/database:/data/db
|
||||
command: mongod --logpath=/dev/null # -- quiet
|
||||
restart: always
|
||||
|
||||
@@ -22,7 +22,6 @@ bch-wallet-service:
|
||||
- '5668:5668' # IPFS TCP Port
|
||||
- '5669:5669' # IPFS WS Port
|
||||
volumes:
|
||||
- ../ipfsdata:/home/safeuser/ipfsdata
|
||||
- ../orbitdb:/home/safeuser/orbitdb
|
||||
- ../data/ipfsdata:/home/safeuser/ipfs-service-provider/.ipfsdata
|
||||
|
||||
restart: always
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# BEGIN: Optional configuration settings
|
||||
|
||||
# This mnemonic is used to set up persistent public key for e2ee
|
||||
# Replace this with your own 12-word mnemonic.
|
||||
export MNEMONIC="olive two muscle bottom coral ancient wait legend bronze useful process session"
|
||||
|
||||
# The human readable name this IPFS node identifies as.
|
||||
export COORD_NAME=ipfs-service-provider-generic
|
||||
|
||||
# Allow this node to function as a circuit relay. It must not be behind a firewall.
|
||||
#export ENABLE_CIRCUIT_RELAY=true
|
||||
|
||||
# Debug level. 0 = minimal info. 2 = max info.
|
||||
export DEBUG_LEVEL=1
|
||||
|
||||
# END: Optional configuration settings
|
||||
|
||||
|
||||
# Production database connection string.
|
||||
export DBURL=mongodb://172.17.0.1:5555/ipfs-service-prod
|
||||
|
||||
# Customize these environment variables for your own installation.
|
||||
export AUTHSERVER=https://auth.fullstack.cash
|
||||
export APISERVER=https://api.fullstack.cash/v5/
|
||||
export FULLSTACKLOGIN=demo@demo.com
|
||||
export FULLSTACKPASS=demo
|
||||
|
||||
# Ports
|
||||
export PORT=5001 # REST API
|
||||
export IPFS_TCP_PORT=5668 # IPSF TCP Port
|
||||
export IPFS_WS_PORT=5669 # IPFS WS Port
|
||||
|
||||
export SVC_ENV=production
|
||||
npm start
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Customize these environment variables for your own installation.
|
||||
export AUTHSERVER=https://auth.fullstack.cash
|
||||
export APISERVER=https://api.fullstack.cash/v5/
|
||||
export FULLSTACKLOGIN=demo@demo.com
|
||||
export FULLSTACKPASS=demo
|
||||
|
||||
# Ports
|
||||
export PORT=5001 # REST API
|
||||
export IPFS_TCP_PORT=5668 # IPSF TCP Port
|
||||
export IPFS_WS_PORT=5669 # IPFS WS Port
|
||||
|
||||
# Production database connection string.
|
||||
export DBURL=mongodb://172.17.0.1:5555/ipfs-service-prod
|
||||
|
||||
#export ENABLE_CIRCUIT_RELAY=1
|
||||
|
||||
export SVC_ENV=production
|
||||
npm start
|
||||
@@ -23,13 +23,13 @@ class FullStackJWT {
|
||||
'Must pass a url for the API server when instantiating FullStackJWT class.'
|
||||
)
|
||||
}
|
||||
this.login = localConfig.login
|
||||
this.login = localConfig.fullstackLogin
|
||||
if (!this.login || typeof this.login !== 'string') {
|
||||
throw new Error(
|
||||
'Must pass a FullStack.cash login (email) instantiating FullStackJWT class.'
|
||||
)
|
||||
}
|
||||
this.password = localConfig.password
|
||||
this.password = localConfig.fullstackPassword
|
||||
if (!this.password || typeof this.password !== 'string') {
|
||||
throw new Error(
|
||||
'Must pass a FullStack.cash account password when instantiating FullStackJWT class.'
|
||||
@@ -39,7 +39,7 @@ class FullStackJWT {
|
||||
// Encapsulate dependencies
|
||||
this.jwtLib = new JwtLib({
|
||||
// Overwrite default values with the values in the config file.
|
||||
server: this.server,
|
||||
server: this.authServer,
|
||||
login: this.login,
|
||||
password: this.password
|
||||
})
|
||||
@@ -53,7 +53,7 @@ class FullStackJWT {
|
||||
async getJWT () {
|
||||
try {
|
||||
// Skip connecting FullStack.cash auth server to the network if this is an E2E test.
|
||||
if (process.env.E2ETEST) {
|
||||
if (process.env.TEST_TYPE === 'e2e') {
|
||||
this.apiToken = 'faketoken'
|
||||
return this.apiToken
|
||||
}
|
||||
|
||||
+38
-28
@@ -4,8 +4,8 @@
|
||||
https://troutsblog.com/blog/clean-architecture
|
||||
*/
|
||||
|
||||
// Load the config file
|
||||
const config = require('../../config')
|
||||
// Public NPM libraries
|
||||
const BCHJS = require('@psf/bch-js')
|
||||
|
||||
// Load individual adapter libraries.
|
||||
const IPFSAdapter = require('./ipfs')
|
||||
@@ -13,35 +13,45 @@ const LocalDB = require('./localdb')
|
||||
const LogsAPI = require('./logapi')
|
||||
const Passport = require('./passport')
|
||||
const Nodemailer = require('./nodemailer')
|
||||
const { wlogger } = require('./wlogger')
|
||||
// const { wlogger } = require('./wlogger')
|
||||
const JSONFiles = require('./json-files')
|
||||
const FullStackJWT = require('./fullstack-jwt')
|
||||
|
||||
// Instantiate adapter libraries.
|
||||
const ipfs = new IPFSAdapter()
|
||||
const localdb = new LocalDB()
|
||||
const logapi = new LogsAPI()
|
||||
const passport = new Passport()
|
||||
const nodemailer = new Nodemailer()
|
||||
const jsonFiles = new JSONFiles()
|
||||
const config = require('../../config')
|
||||
|
||||
// Get a valid JWT API key and instance bch-js.
|
||||
const fullStackJwt = new FullStackJWT({
|
||||
authServer: config.AUTHSERVER,
|
||||
apiServer: config.APISERVER,
|
||||
login: config.FULLSTACKLOGIN,
|
||||
password: config.FULLSTACKPASS
|
||||
})
|
||||
const bchjs = {} // Placeholder.
|
||||
class Adapters {
|
||||
constructor (localConfig = {}) {
|
||||
// Encapsulate dependencies
|
||||
this.ipfs = new IPFSAdapter()
|
||||
this.localdb = new LocalDB()
|
||||
this.logapi = new LogsAPI()
|
||||
this.passport = new Passport()
|
||||
this.nodemailer = new Nodemailer()
|
||||
this.jsonFiles = new JSONFiles()
|
||||
this.bchjs = new BCHJS()
|
||||
this.config = config
|
||||
|
||||
module.exports = {
|
||||
ipfs,
|
||||
localdb,
|
||||
logapi,
|
||||
passport,
|
||||
nodemailer,
|
||||
wlogger,
|
||||
jsonFiles,
|
||||
fullStackJwt,
|
||||
bchjs
|
||||
// Get a valid JWT API key and instance bch-js.
|
||||
this.fullStackJwt = new FullStackJWT(config)
|
||||
}
|
||||
|
||||
async start () {
|
||||
try {
|
||||
if (this.config.getJwtAtStartup) {
|
||||
// Get a JWT token and instantiate bch-js with it. Then pass that instance
|
||||
// to all the rest of the apps controllers and adapters.
|
||||
await this.fullStackJwt.getJWT()
|
||||
// Instantiate bch-js with the JWT token, and overwrite the placeholder for bch-js.
|
||||
this.bchjs = await this.fullStackJwt.instanceBchjs()
|
||||
}
|
||||
|
||||
// Start the IPFS node.
|
||||
await this.ipfs.start({ bchjs: this.bchjs })
|
||||
} catch (err) {
|
||||
console.error('Error in adapters/index.js/start()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Adapters
|
||||
|
||||
@@ -43,6 +43,8 @@ class IpfsCoordAdapter {
|
||||
}
|
||||
|
||||
async start (localConfig = {}) {
|
||||
// console.log('this.config.announceJsonLd: ', this.config.announceJsonLd)
|
||||
|
||||
this.ipfsCoord = new this.IpfsCoord({
|
||||
ipfs: this.ipfs,
|
||||
type: 'node.js',
|
||||
@@ -51,15 +53,13 @@ class IpfsCoordAdapter {
|
||||
privateLog: console.log, // Default to console.log
|
||||
isCircuitRelay: this.config.isCircuitRelay,
|
||||
apiInfo: this.config.apiInfo,
|
||||
announceJsonLd: this.config.announceJsonLd
|
||||
announceJsonLd: this.config.announceJsonLd,
|
||||
mnemonic: this.config.mnemonic,
|
||||
debugLevel: this.config.debugLevel
|
||||
})
|
||||
|
||||
// Skip connecting ipfs-coord to the network if this is an E2E test.
|
||||
if (!process.env.E2ETEST) {
|
||||
// Wait for the ipfs-coord library to signal that it is ready.
|
||||
await this.ipfsCoord.ipfs.start()
|
||||
await this.ipfsCoord.isReady()
|
||||
}
|
||||
// Wait for the ipfs-coord library to signal that it is ready.
|
||||
await this.ipfsCoord.start({ type: 'node.js' })
|
||||
|
||||
// Signal that this adapter is ready.
|
||||
this.isReady = true
|
||||
@@ -72,7 +72,7 @@ class IpfsCoordAdapter {
|
||||
attachRPCRouter (router) {
|
||||
try {
|
||||
_this.ipfsCoord.privateLog = router
|
||||
_this.ipfsCoord.ipfs.orbitdb.privateLog = router
|
||||
_this.ipfsCoord.adapters.orbit.privateLog = router
|
||||
} catch (err) {
|
||||
console.error('Error in attachRPCRouter()')
|
||||
throw err
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
const IPFS = require('ipfs')
|
||||
// const IPFS = require('ipfs')
|
||||
const IPFS = require('@chris.troutner/ipfs')
|
||||
|
||||
// Local libraries
|
||||
const config = require('../../../config')
|
||||
@@ -25,7 +26,7 @@ class IpfsAdapter {
|
||||
try {
|
||||
// Ipfs Options
|
||||
const ipfsOptions = {
|
||||
repo: './ipfsdata',
|
||||
repo: './.ipfsdata/ipfs',
|
||||
start: true,
|
||||
config: {
|
||||
relay: {
|
||||
@@ -56,17 +57,6 @@ class IpfsAdapter {
|
||||
// Set the 'server' profile so the node does not scan private networks.
|
||||
await this.ipfs.config.profiles.apply('server')
|
||||
|
||||
// const nodeConfig = await this.ipfs.config.getAll()
|
||||
// console.log(
|
||||
// `IPFS node configuration: ${JSON.stringify(nodeConfig, null, 2)}`
|
||||
// )
|
||||
|
||||
// Stop the IPFS node if we're running tests.
|
||||
if (this.config.env === 'test') {
|
||||
console.log('Stopping IPFS for tests.')
|
||||
await this.ipfs.stop()
|
||||
}
|
||||
|
||||
// Signal that this adapter is ready.
|
||||
this.isReady = true
|
||||
|
||||
@@ -76,6 +66,10 @@ class IpfsAdapter {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async stop () {
|
||||
await this.ipfs.stop()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IpfsAdapter
|
||||
|
||||
+78
-37
@@ -11,52 +11,93 @@ require('winston-daily-rotate-file')
|
||||
|
||||
const config = require('../../config')
|
||||
|
||||
// Configure daily-rotation transport.
|
||||
const transport = new winston.transports.DailyRotateFile({
|
||||
filename: `${__dirname.toString()}/../../logs/koa-${config.env}-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: false,
|
||||
maxSize: '1m', // 1 megabyte
|
||||
maxFiles: '5d', // 5 days
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.json()
|
||||
)
|
||||
})
|
||||
class Wlogger {
|
||||
constructor (localConfig = {}) {
|
||||
this.config = config
|
||||
|
||||
transport.on('rotate', notifyRotation)
|
||||
// Configure daily-rotation transport.
|
||||
this.transport = new winston.transports.DailyRotateFile({
|
||||
filename: `${__dirname.toString()}/../../logs/koa-${
|
||||
this.config.env
|
||||
}-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: false,
|
||||
maxSize: '1m', // 1 megabyte
|
||||
maxFiles: '5d', // 5 days
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.json()
|
||||
)
|
||||
})
|
||||
|
||||
function notifyRotation (oldFilename, newFilename) {
|
||||
wlogger.info('Rotating log files')
|
||||
this.transport.on('rotate', this.notifyRotation)
|
||||
|
||||
// This controls what goes into the log FILES
|
||||
this.wlogger = winston.createLogger({
|
||||
level: 'verbose',
|
||||
format: winston.format.json(),
|
||||
transports: [
|
||||
//
|
||||
// - Write to all logs with level `info` and below to `combined.log`
|
||||
// - Write all logs error (and below) to `error.log`.
|
||||
//
|
||||
// new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
|
||||
// new winston.transports.File({ filename: 'logs/combined.log' })
|
||||
this.transport
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
notifyRotation (oldFilename, newFilename) {
|
||||
this.wlogger.info('Rotating log files')
|
||||
}
|
||||
|
||||
outputToConsole () {
|
||||
this.wlogger.add(
|
||||
new winston.transports.Console({
|
||||
format: winston.format.simple(),
|
||||
level: 'info'
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// transport.on('rotate', notifyRotation)
|
||||
|
||||
// function notifyRotation (oldFilename, newFilename) {
|
||||
// wlogger.info('Rotating log files')
|
||||
// }
|
||||
|
||||
// This controls what goes into the log FILES
|
||||
const wlogger = winston.createLogger({
|
||||
level: 'verbose',
|
||||
format: winston.format.json(),
|
||||
transports: [
|
||||
//
|
||||
// - Write to all logs with level `info` and below to `combined.log`
|
||||
// - Write all logs error (and below) to `error.log`.
|
||||
//
|
||||
// new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
|
||||
// new winston.transports.File({ filename: 'logs/combined.log' })
|
||||
transport
|
||||
]
|
||||
})
|
||||
// const wlogger = winston.createLogger({
|
||||
// level: 'verbose',
|
||||
// format: winston.format.json(),
|
||||
// transports: [
|
||||
// //
|
||||
// // - Write to all logs with level `info` and below to `combined.log`
|
||||
// // - Write all logs error (and below) to `error.log`.
|
||||
// //
|
||||
// // new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
|
||||
// // new winston.transports.File({ filename: 'logs/combined.log' })
|
||||
// transport
|
||||
// ]
|
||||
// })
|
||||
|
||||
function outputToConsole () {
|
||||
wlogger.add(
|
||||
new winston.transports.Console({
|
||||
format: winston.format.simple(),
|
||||
level: 'info'
|
||||
})
|
||||
)
|
||||
}
|
||||
// function outputToConsole () {
|
||||
// wlogger.add(
|
||||
// new winston.transports.Console({
|
||||
// format: winston.format.simple(),
|
||||
// level: 'info'
|
||||
// })
|
||||
// )
|
||||
// }
|
||||
|
||||
// This controls the logs to CONSOLE
|
||||
// if (config.env !== 'test') {
|
||||
// outputToConsole()
|
||||
// }
|
||||
|
||||
module.exports = { wlogger, notifyRotation, outputToConsole }
|
||||
const logger = new Wlogger()
|
||||
const wlogger = logger.wlogger
|
||||
|
||||
module.exports = { wlogger, Wlogger }
|
||||
|
||||
+41
-34
@@ -7,57 +7,64 @@
|
||||
// Public npm libraries.
|
||||
|
||||
// Load the Clean Architecture Adapters library
|
||||
const adapters = require('../adapters')
|
||||
const Adapters = require('../adapters')
|
||||
|
||||
// Load the JSON RPC Controller.
|
||||
const JSONRPC = require('./json-rpc')
|
||||
|
||||
// Load the Clean Architecture Use Case libraries.
|
||||
const UseCases = require('../use-cases')
|
||||
const useCases = new UseCases({ adapters })
|
||||
// const useCases = new UseCases({ adapters })
|
||||
|
||||
// Load the REST API Controllers.
|
||||
const RESTControllers = require('./rest-api')
|
||||
|
||||
// Top-level function for this library.
|
||||
// Start the various Controllers and attach them to the app.
|
||||
async function attachControllers (app) {
|
||||
try {
|
||||
class Controllers {
|
||||
constructor (localConfig = {}) {
|
||||
this.adapters = new Adapters()
|
||||
this.useCases = new UseCases({ adapters: this.adapters })
|
||||
}
|
||||
|
||||
async attachControllers (app) {
|
||||
// Get a JWT token and instantiate bch-js with it. Then pass that instance
|
||||
// to all the rest of the apps controllers and adapters.
|
||||
await adapters.fullStackJwt.getJWT()
|
||||
await this.adapters.fullStackJwt.getJWT()
|
||||
// Instantiate bch-js with the JWT token, and overwrite the placeholder for bch-js.
|
||||
adapters.bchjs = await adapters.fullStackJwt.instanceBchjs()
|
||||
this.adapters.bchjs = await this.adapters.fullStackJwt.instanceBchjs()
|
||||
|
||||
// Wait for any startup processes to complete for the Adapters libraries.
|
||||
await this.adapters.start()
|
||||
|
||||
// Attach the REST controllers to the Koa app.
|
||||
attachRESTControllers(app)
|
||||
// this.attachRESTControllers(app)
|
||||
|
||||
// Start IPFS.
|
||||
await adapters.ipfs.start({ bchjs: adapters.bchjs })
|
||||
this.attachRPCControllers()
|
||||
}
|
||||
|
||||
attachRPCControllers()
|
||||
} catch (err) {
|
||||
console.error('Error in attachControllers()')
|
||||
throw err
|
||||
// Top-level function for this library.
|
||||
// Start the various Controllers and attach them to the app.
|
||||
attachRESTControllers (app) {
|
||||
const restControllers = new RESTControllers({
|
||||
adapters: this.adapters,
|
||||
useCases: this.useCases
|
||||
})
|
||||
|
||||
// Attach the REST API Controllers associated with the boilerplate code to the Koa app.
|
||||
restControllers.attachRESTControllers(app)
|
||||
}
|
||||
|
||||
// Add the JSON RPC router to the ipfs-coord adapter.
|
||||
attachRPCControllers () {
|
||||
const jsonRpcController = new JSONRPC({
|
||||
adapters: this.adapters,
|
||||
useCases: this.useCases
|
||||
})
|
||||
|
||||
// Attach the input of the JSON RPC router to the output of ipfs-coord.
|
||||
this.adapters.ipfs.ipfsCoordAdapter.attachRPCRouter(
|
||||
jsonRpcController.router
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function attachRESTControllers (app) {
|
||||
const rESTControllers = new RESTControllers({
|
||||
adapters,
|
||||
useCases
|
||||
})
|
||||
|
||||
// Attach the REST API Controllers associated with the boilerplate code to the Koa app.
|
||||
rESTControllers.attachRESTControllers(app)
|
||||
}
|
||||
|
||||
// Add the JSON RPC router to the ipfs-coord adapter.
|
||||
function attachRPCControllers () {
|
||||
const jsonRpcController = new JSONRPC({ adapters, useCases })
|
||||
|
||||
// Attach the input of the JSON RPC router to the output of ipfs-coord.
|
||||
adapters.ipfs.ipfsCoordAdapter.attachRPCRouter(jsonRpcController.router)
|
||||
}
|
||||
|
||||
module.exports = { attachControllers }
|
||||
module.exports = Controllers
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
const jsonrpc = require('jsonrpc-lite')
|
||||
|
||||
// Local libraries
|
||||
const aboutStr = require('../../../../config/about')
|
||||
const config = require('../../../../config')
|
||||
|
||||
class AboutRPC {
|
||||
constructor (localConfig) {
|
||||
@@ -36,7 +36,8 @@ class AboutRPC {
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
message: aboutStr,
|
||||
// message: aboutStr,
|
||||
message: JSON.stringify(config.announceJsonLd),
|
||||
endpoint: 'about'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ class BCHRPC {
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
// console.error('Error in createUser()')
|
||||
console.error('Error in JSON RPC BCH transactions()')
|
||||
// throw err
|
||||
|
||||
// Return an error response
|
||||
@@ -223,7 +223,7 @@ class BCHRPC {
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
// console.error('Error in createUser()')
|
||||
console.error('Error in JSON RPC BCH balance()')
|
||||
// throw err
|
||||
|
||||
// Return an error response
|
||||
@@ -336,7 +336,8 @@ class BCHRPC {
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
// console.error('Error in createUser()')
|
||||
console.error('Error in JSON RPC BCH utxos()')
|
||||
console.error('Error in JSON RPC utxos(): ', err)
|
||||
// throw err
|
||||
|
||||
// Return an error response
|
||||
@@ -388,12 +389,17 @@ class BCHRPC {
|
||||
const data = await this.bchjs.RawTransactions.sendRawTransaction(hex)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
const retObj = data
|
||||
retObj.status = 200
|
||||
const retObj = {
|
||||
success: true,
|
||||
status: 200,
|
||||
endpoint: 'broadcast',
|
||||
txid: data
|
||||
}
|
||||
// retObj.status = 200
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
// console.error('Error in createUser()')
|
||||
console.error('Error in JSON RPC BCH broadcast()')
|
||||
// throw err
|
||||
|
||||
// Return an error response
|
||||
@@ -514,7 +520,7 @@ class BCHRPC {
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
// console.error('Error in createUser()')
|
||||
console.error('Error in JSON RPC BCH transaction()')
|
||||
// throw err
|
||||
|
||||
// Return an error response
|
||||
|
||||
@@ -100,8 +100,19 @@ class JSONRPC {
|
||||
|
||||
// Encrypt and publish the response to the originators private OrbitDB,
|
||||
// if ipfs-coord has been initialized and the peers ID is registered.
|
||||
if (_this.ipfsCoord.ipfs) {
|
||||
await _this.ipfsCoord.ipfs.orbitdb.sendToDb(from, retStr)
|
||||
|
||||
// console.log('responding to JSON RPC command')
|
||||
const thisNode = _this.ipfsCoord.thisNode
|
||||
// console.log('thisNode: ', thisNode)
|
||||
|
||||
try {
|
||||
await _this.ipfsCoord.useCases.peer.sendPrivateMessage(
|
||||
from,
|
||||
retStr,
|
||||
thisNode
|
||||
)
|
||||
} catch (err) {
|
||||
console.log('sendPrivateMessage() err: ', err)
|
||||
}
|
||||
|
||||
// Return the response and originator. Useful for testing.
|
||||
|
||||
+4
-11
@@ -3,7 +3,7 @@
|
||||
functions are called by the /user REST API endpoints.
|
||||
*/
|
||||
|
||||
// const UserModel = require('../adapters/localdb/models/users')
|
||||
const UserEntity = require('../entities/user')
|
||||
const { wlogger } = require('../adapters/wlogger')
|
||||
|
||||
class UserLib {
|
||||
@@ -17,6 +17,7 @@ class UserLib {
|
||||
}
|
||||
|
||||
// Encapsulate dependencies
|
||||
this.UserEntity = new UserEntity()
|
||||
this.UserModel = this.adapters.localdb.Users
|
||||
}
|
||||
|
||||
@@ -24,17 +25,9 @@ class UserLib {
|
||||
async createUser (userObj) {
|
||||
try {
|
||||
// Input Validation
|
||||
if (!userObj.email || typeof userObj.email !== 'string') {
|
||||
throw new Error("Property 'email' must be a string!")
|
||||
}
|
||||
if (!userObj.password || typeof userObj.password !== 'string') {
|
||||
throw new Error("Property 'password' must be a string!")
|
||||
}
|
||||
if (!userObj.name || typeof userObj.name !== 'string') {
|
||||
throw new Error("Property 'name' must be a string!")
|
||||
}
|
||||
|
||||
const user = new this.UserModel(userObj)
|
||||
const userEntity = this.UserEntity.validate(userObj)
|
||||
const user = new this.UserModel(userEntity)
|
||||
|
||||
// Enforce default value of 'user'
|
||||
user.type = 'user'
|
||||
|
||||
@@ -10,7 +10,7 @@ const axios = require('axios').default
|
||||
|
||||
// Local support libraries
|
||||
const config = require('../../../config')
|
||||
const app = require('../../../bin/server')
|
||||
const Server = require('../../../bin/server')
|
||||
const testUtils = require('../../utils/test-utils')
|
||||
const AdminLib = require('../../../src/adapters/admin')
|
||||
const adminLib = new AdminLib()
|
||||
@@ -23,11 +23,14 @@ const LOCALHOST = `http://localhost:${config.port}`
|
||||
describe('Auth', () => {
|
||||
before(async () => {
|
||||
try {
|
||||
process.env.E2ETEST = 'true'
|
||||
const app = new Server()
|
||||
|
||||
// This should be the first instruction. It starts the REST API server.
|
||||
await app.startServer()
|
||||
|
||||
// Stop the IPFS node for the rest of the e2e tests.
|
||||
// await app.controllers.adapters.ipfs.stop()
|
||||
|
||||
// Delete all previous users in the database.
|
||||
await testUtils.deleteAllUsers()
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ const LOCALHOST = `http://localhost:${config.port}`
|
||||
const context = {}
|
||||
|
||||
const UserController = require('../../../src/controllers/rest-api/users/controller')
|
||||
const adapters = require('../../../src/adapters')
|
||||
const Adapters = require('../../../src/adapters')
|
||||
const adapters = new Adapters()
|
||||
const UseCases = require('../../../src/use-cases/')
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
@@ -20,6 +20,10 @@ async function startTest () {
|
||||
|
||||
await testUtils.testTransaction(testData.uutId)
|
||||
|
||||
await testUtils.testTransactions(testData.uutId)
|
||||
|
||||
await testUtils.testUtxos(testData.uutId)
|
||||
|
||||
console.log('E2E TEST: Tests completed successfully!')
|
||||
process.exit()
|
||||
} catch (err) {
|
||||
|
||||
@@ -45,12 +45,17 @@ class TestUtils {
|
||||
async sendRPC (ipfsId, cmdStr) {
|
||||
try {
|
||||
// Send the RPC command to the server/service.
|
||||
await this.ipfsCoord.ipfs.orbitdb.sendToDb(ipfsId, cmdStr)
|
||||
// await this.ipfsCoord.ipfs.orbitdb.sendToDb(ipfsId, cmdStr)
|
||||
await this.ipfsCoord.useCases.peer.sendPrivateMessage(
|
||||
ipfsId,
|
||||
cmdStr,
|
||||
this.ipfsCoord.thisNode
|
||||
)
|
||||
|
||||
let retData
|
||||
|
||||
// This event is triggered when the response comes back.
|
||||
this.eventEmitter.on('rpcData', inData => {
|
||||
this.eventEmitter.on('rpcData', (inData) => {
|
||||
retData = inData
|
||||
})
|
||||
|
||||
@@ -98,8 +103,8 @@ class TestUtils {
|
||||
apiInfo: 'none',
|
||||
announceJsonLd: announceJsonLd
|
||||
})
|
||||
await this.ipfsCoord.ipfs.start()
|
||||
await this.ipfsCoord.isReady()
|
||||
|
||||
await this.ipfsCoord.start()
|
||||
|
||||
// Wait to let ipfs-coord connect to subnet peers.
|
||||
await this.bchjs.Util.sleep(30000)
|
||||
@@ -123,10 +128,17 @@ class TestUtils {
|
||||
// 'ipfs-coord peer info: ',
|
||||
// this.ipfsCoord.ipfs.peers.state.peers[ipfsId]
|
||||
// )
|
||||
if (!this.ipfsCoord.ipfs.peers.state.peers[ipfsId]) {
|
||||
|
||||
const peers = this.ipfsCoord.thisNode.peerList
|
||||
// console.log('peers: ', peers)
|
||||
// console.log('Target peer in peerList? ', peers.includes(ipfsId))
|
||||
|
||||
// if (!this.ipfsCoord.ipfs.peers.state.peers[ipfsId]) {
|
||||
if (!peers.includes(ipfsId)) {
|
||||
throw new Error('Could not find UUT in ipfs-coord list of peers.')
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
console.error('Error in connectToUut()')
|
||||
console.log(
|
||||
'Is the service running? Did you update the test-data.json file?'
|
||||
@@ -195,6 +207,72 @@ class TestUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// Get the info a on transaction over JSON RPC.
|
||||
async testTransactions (ipfsId) {
|
||||
try {
|
||||
// Generate the JSON RPC command
|
||||
const id = uid()
|
||||
const cmd = jsonrpc.request(id, 'bch', {
|
||||
endpoint: 'transactions',
|
||||
addresses: ['bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj']
|
||||
})
|
||||
const cmdStr = JSON.stringify(cmd)
|
||||
|
||||
// console.log(`Publishing message to ${ipfsId}`)
|
||||
|
||||
console.log('E2E TEST: Sending Transactions command...')
|
||||
const result = await this.sendRPC(ipfsId, cmdStr)
|
||||
// console.log('result: ', result)
|
||||
|
||||
if (
|
||||
result.result.value.status &&
|
||||
Array.isArray(result.result.value.transactions)
|
||||
) {
|
||||
console.log('E2E TEST: transactions test passed.')
|
||||
return true
|
||||
} else {
|
||||
console.log('E2E TEST: transactions test failed.')
|
||||
this.failTest()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error in testTransactions()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Get the utxos for a BCH address over JSON RPC.
|
||||
async testUtxos (ipfsId) {
|
||||
try {
|
||||
// Generate the JSON RPC command
|
||||
const id = uid()
|
||||
const cmd = jsonrpc.request(id, 'bch', {
|
||||
endpoint: 'utxos',
|
||||
address: 'bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj'
|
||||
})
|
||||
const cmdStr = JSON.stringify(cmd)
|
||||
|
||||
// console.log(`Publishing message to ${ipfsId}`)
|
||||
|
||||
console.log('E2E TEST: Sending Utxos command...')
|
||||
const result = await this.sendRPC(ipfsId, cmdStr)
|
||||
// console.log('result', result.result.value)
|
||||
|
||||
const bchUtxos = result.result.value[0].bchUtxos
|
||||
const slpUtxos = result.result.value[0].slpUtxos
|
||||
|
||||
if (result.result.value && bchUtxos && slpUtxos) {
|
||||
console.log('E2E TEST: utxos test passed.')
|
||||
return true
|
||||
} else {
|
||||
console.log('E2E TEST: utxos test failed.')
|
||||
this.failTest()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error in testUtxos()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
failTest () {
|
||||
console.log('Exiting test program.')
|
||||
process.exit()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"uutAddr": "/ip4/127.0.0.1/tcp/5668/p2p/QmZSyLnRQWMBknVNjUroLQnrcmDnUVAUU4pMQ2LGhh6b9v",
|
||||
"uutId": "QmZSyLnRQWMBknVNjUroLQnrcmDnUVAUU4pMQ2LGhh6b9v"
|
||||
"uutAddr": "/ip4/127.0.0.1/tcp/5701/p2p/QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2",
|
||||
"uutId": "QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2"
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ describe('#FullStackJWT', () => {
|
||||
const localConfig = {
|
||||
authServer: 'someserver',
|
||||
apiServer: 'someserver',
|
||||
login: 'somelogin',
|
||||
password: 'somepassword'
|
||||
fullstackLogin: 'somelogin',
|
||||
fullstackPassword: 'somepassword'
|
||||
}
|
||||
uut = new FullStackJWT(localConfig)
|
||||
})
|
||||
@@ -81,7 +81,7 @@ describe('#FullStackJWT', () => {
|
||||
const localConfig = {
|
||||
authServer: 'someserver',
|
||||
apiServer: 'someserver',
|
||||
login: 'somelogin'
|
||||
fullstackLogin: 'somelogin'
|
||||
}
|
||||
uut = new FullStackJWT(localConfig)
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ describe('#IPFS', () => {
|
||||
})
|
||||
|
||||
describe('#attachRPCRouter', () => {
|
||||
it('should attached a router output', async () => {
|
||||
it('should attach a router output', async () => {
|
||||
// Mock dependencies
|
||||
uut.ipfsCoord = {
|
||||
privateLog: {},
|
||||
@@ -73,6 +73,11 @@ describe('#IPFS', () => {
|
||||
orbitdb: {
|
||||
privateLog: {}
|
||||
}
|
||||
},
|
||||
adapters: {
|
||||
orbit: {
|
||||
privateLog: () => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,16 +86,16 @@ describe('#IPFS', () => {
|
||||
uut.attachRPCRouter(router)
|
||||
})
|
||||
|
||||
it('should throw an error if ipfs-coord has not been instantiated', () => {
|
||||
try {
|
||||
const router = console.log
|
||||
|
||||
uut.attachRPCRouter(router)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
}
|
||||
})
|
||||
// it('should throw an error if ipfs-coord has not been instantiated', () => {
|
||||
// try {
|
||||
// const router = console.log
|
||||
//
|
||||
// uut.attachRPCRouter(router)
|
||||
//
|
||||
// assert.fail('Unexpected code path')
|
||||
// } catch (err) {
|
||||
// assert.include(err.message, 'Cannot read property')
|
||||
// }
|
||||
// })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,30 +1,40 @@
|
||||
// const assert = require('chai').assert
|
||||
const {
|
||||
notifyRotation,
|
||||
outputToConsole
|
||||
} = require('../../../src/adapters/wlogger')
|
||||
const assert = require('chai').assert
|
||||
const { Wlogger } = require('../../../src/adapters/wlogger')
|
||||
|
||||
const sinon = require('sinon')
|
||||
|
||||
// let uut
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
describe('#wlogger.js', () => {
|
||||
describe('#wlogger', () => {
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
afterEach(() => {
|
||||
sandbox.restore()
|
||||
|
||||
uut = new Wlogger()
|
||||
})
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should create a new wlogger instance', () => {
|
||||
uut = new Wlogger()
|
||||
// console.log('uut: ', uut)
|
||||
|
||||
assert.property(uut, 'transport')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#notifyRotation', () => {
|
||||
it('should notify of a log rotation', () => {
|
||||
notifyRotation()
|
||||
uut.notifyRotation()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#envronment', () => {
|
||||
it('should write to console in non-test environment', () => {
|
||||
outputToConsole()
|
||||
uut.outputToConsole()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,26 +6,30 @@
|
||||
const assert = require('chai').assert
|
||||
const sinon = require('sinon')
|
||||
|
||||
const adapters = require('../../../src/adapters')
|
||||
const { attachControllers } = require('../../../src/controllers')
|
||||
const Controllers = require('../../../src/controllers')
|
||||
|
||||
describe('#Controllers', () => {
|
||||
// let uut
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
uut = new Controllers()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#attachControllers', () => {
|
||||
it('should attach the controllers', async () => {
|
||||
// mock IPFS
|
||||
sandbox.stub(adapters.ipfs, 'start').resolves({})
|
||||
sandbox.stub(adapters.fullStackJwt, 'getJWT').resolves({})
|
||||
sandbox.stub(adapters.fullStackJwt, 'instanceBchjs').resolves({})
|
||||
adapters.ipfs.ipfsCoordAdapter = {
|
||||
// mock dependencies
|
||||
// sandbox.stub(adapters.fullStackJwt, 'getJWT').resolves({})
|
||||
// sandbox.stub(adapters.fullStackJwt, 'instanceBchjs').resolves({})
|
||||
// sandbox.stub(adapters.ipfs, 'start').resolves({})
|
||||
// adapters.ipfs.ipfsCoordAdapter = {
|
||||
|
||||
sandbox.stub(uut.adapters, 'start').resolves({})
|
||||
uut.adapters.ipfs.ipfsCoordAdapter = {
|
||||
attachRPCRouter: () => {}
|
||||
}
|
||||
|
||||
@@ -33,17 +37,25 @@ describe('#Controllers', () => {
|
||||
use: () => {}
|
||||
}
|
||||
|
||||
await attachControllers(app)
|
||||
await uut.attachControllers(app)
|
||||
|
||||
assert.isOk(true, 'Not throwing an error is a success')
|
||||
})
|
||||
|
||||
it('should catch and throw errors', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(adapters.fullStackJwt, 'getJWT')
|
||||
.stub(uut.adapters.fullStackJwt, 'getJWT')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
await attachControllers()
|
||||
const app = {
|
||||
use: () => {}
|
||||
}
|
||||
|
||||
await uut.attachControllers(app)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log('err.message: ', err.message)
|
||||
assert.include(err.message, 'test error')
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('#users-use-case', () => {
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
// assert.equal(err.status, 422)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, "Property 'email' must be a string!")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user