Compare commits

..
24 Commits
Author SHA1 Message Date
Chris Troutner f41cac9fc7 Merge pull request #16 from Permissionless-Software-Foundation/ct-unstable
fix(broadcast): Fixing bug in broadcast JSON RPC
2021-08-15 09:07:09 -07:00
Chris Troutner 8ad1400d3c fix(error reporting): Adding JSON RPC error reporting 2021-08-15 08:32:39 -07:00
Chris Troutner e48a9213c5 fix(broadcast): Fixing bug in broadcast JSON RPC 2021-08-13 16:15:44 -07:00
Chris Troutner 2e2d092b18 Merge pull request #15 from Permissionless-Software-Foundation/ct-unstable
fix(protocol): Adding protocol field to announceJsonLd
2021-08-05 17:18:31 -07:00
Chris Troutner c8aefae0cc fix(protocol): Adding protocol property to announceJsonLd 2021-08-05 17:16:37 -07:00
Chris Troutner 17e465b3ab Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-08-05 17:14:40 -07:00
Chris Troutner 40bb75bf33 Merge pull request #18 from Permissionless-Software-Foundation/ct-unstable
fix(protocol): Adding protocol field to announceJsonLd
2021-08-05 17:11:00 -07:00
Chris Troutner 02201afc59 fix(protocol): Adding protocol field to announceJsonLd 2021-08-05 17:08:56 -07:00
Chris Troutner bae98bba28 Merge pull request #14 from Permissionless-Software-Foundation/ct-unstable
feat(about): Adding npm version to JSON RPC About endpoint output
2021-08-03 13:13:25 -07:00
Chris Troutner 0eb7aeaed1 feat(version): Adding npm version to ipfs-coord announce payload 2021-08-03 13:12:02 -07:00
Chris Troutner dbd5022c4c Merge pull request #17 from Permissionless-Software-Foundation/ct-unstable
feat(about): Adding npm version to JSON RPC About endpoint output
2021-08-03 13:07:57 -07:00
Chris Troutner 72ac73c410 feat(about): Adding npm version to JSON RPC About endpoint output 2021-08-03 13:05:45 -07:00
Chris Troutner 9b52c81b25 Adding startup script to gitignore 2021-08-03 12:53:35 -07:00
Chris Troutner 7cc13b9ba9 Adding todo in comments 2021-07-31 16:07:47 -07:00
Chris Troutner 3ba866d2d6 Merge pull request #13 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2021-07-31 15:57:18 -07:00
Chris Troutner 3d058d9164 fix(ipfs-service-provider): Synced with upstream 2021-07-31 15:55:47 -07:00
Chris Troutner fde8b16fef Merge pull request #16 from Permissionless-Software-Foundation/dh-required
fix(users): Using the users entity in the use cases
2021-07-31 15:41:25 -07:00
Daniel Gonzalez c5a1eb6f81 fix(users): Using the users entity in the use cases 2021-07-31 15:00:38 -04:00
Chris Troutner 74f8b60472 Adding link to API documentation 2021-07-28 13:28:53 -07:00
Chris Troutner d57085949c Merge pull request #15 from Permissionless-Software-Foundation/ct-unstable
Removing comments
2021-07-25 17:31:48 -07:00
Chris Troutner 9dc40a417a Removing comments 2021-07-25 17:30:15 -07:00
Chris Troutner 81e5592b81 Merge pull request #14 from Permissionless-Software-Foundation/ct-unstable
Converting wlogger and Controller libraries to classes
2021-07-25 16:51:30 -07:00
Chris Troutner 44867f0173 fix(controllers): Made Controllers library a class 2021-07-25 16:49:01 -07:00
Chris Troutner c46f7357c3 fix(wlogger): Refactored into Class for better unit test control 2021-07-25 16:34:56 -07:00
15 changed files with 189 additions and 122 deletions
+1
View File
@@ -65,5 +65,6 @@ system-user-*.json
orbitdb
ipfsdata
ipfs-service-provider.sh
start-bch-wallet-service.sh
!README.md
+1
View File
@@ -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
+4 -3
View File
@@ -55,9 +55,10 @@ async function startServer () {
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)
// Attach REST API and JSON RPC controllersCt unstable to the app.
const Controllers = require('../src/controllers')
const controllers = new Controllers()
controllers.attachControllers(app)
// Enable CORS for testing
// THIS IS A SECURITY RISK. COMMENT OUT FOR PRODUCTION
-15
View File
@@ -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/
`
+6
View File
@@ -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'
@@ -52,6 +56,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/',
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ipfs-bch-wallet-service",
"version": "1.0.0",
"version": "1.9.1",
"description": "IPFS and REST service providing blockchain access needed by a wallet. ",
"main": "index.js",
"scripts": {
+78 -37
View File
@@ -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 }
+37 -30
View File
@@ -14,15 +14,18 @@ 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 = adapters
this.useCases = new UseCases({ 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()
@@ -30,34 +33,38 @@ async function attachControllers (app) {
adapters.bchjs = await adapters.fullStackJwt.instanceBchjs()
// Attach the REST controllers to the Koa app.
attachRESTControllers(app)
this.attachRESTControllers(app)
// Start IPFS.
await adapters.ipfs.start({ bchjs: adapters.bchjs })
await this.adapters.ipfs.start({ bchjs: adapters.bchjs })
attachRPCControllers()
} catch (err) {
console.error('Error in attachControllers()')
throw err
this.attachRPCControllers()
}
// 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
+3 -2
View File
@@ -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'
}
}
+13 -7
View File
@@ -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
+4 -11
View File
@@ -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'
+4
View File
@@ -20,6 +20,10 @@ async function startTest () {
await testUtils.testTransaction(testData.uutId)
// ToDo:
// testTransactions()
// testUtxos()
console.log('E2E TEST: Tests completed successfully!')
process.exit()
} catch (err) {
+20 -10
View File
@@ -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()
})
})
})
+16 -5
View File
@@ -7,14 +7,17 @@ const assert = require('chai').assert
const sinon = require('sinon')
const adapters = require('../../../src/adapters')
const { attachControllers } = require('../../../src/controllers')
// 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())
@@ -22,9 +25,9 @@ describe('#Controllers', () => {
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({})
sandbox.stub(adapters.ipfs, 'start').resolves({})
adapters.ipfs.ipfsCoordAdapter = {
attachRPCRouter: () => {}
}
@@ -33,7 +36,9 @@ 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 () => {
@@ -43,7 +48,13 @@ describe('#Controllers', () => {
.stub(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')
+1 -1
View File
@@ -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!")
}
})