mirror of
https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service.git
synced 2026-09-21 16:52:03 -07:00
Fixed merge conflicts
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
# Permissionless Software Foundation Community Contributing Guide 1.0
|
||||||
|
|
||||||
|
This document describes a very simple process suitable for most projects under
|
||||||
|
the PSF umbrella. It is based on [this Medium article](https://medium.com/the-node-js-collection/healthy-open-source-967fa8be7951) and the [Node.js Community Contribution Guide](https://github.com/nodejs/TSC/blob/master/BasePolicies/CONTRIBUTING.md).
|
||||||
|
Projects are encouraged to adopt this whether they
|
||||||
|
are hosted under the PSF or not.
|
||||||
|
|
||||||
|
The goal of this document is to create a contribution process that:
|
||||||
|
|
||||||
|
* Encourages new contributions.
|
||||||
|
* Encourages contributors to remain involved.
|
||||||
|
* Avoids unnecessary processes and bureaucracy whenever possible.
|
||||||
|
* Creates a transparent decision making process which makes it clear how
|
||||||
|
contributors can be involved in decision making.
|
||||||
|
|
||||||
|
This document is based on much prior art in the Node.js community, io.js,
|
||||||
|
and the Node.js project.
|
||||||
|
|
||||||
|
Additional guidance can be found at the [Permissionless Software Foundation Telegram Channel](https://t.me/permissionless_software).
|
||||||
|
|
||||||
|
## Vocabulary
|
||||||
|
|
||||||
|
* A **Contributor** is any individual creating or commenting on an issue or pull request.
|
||||||
|
* A **Committer** is a subset of contributors who have been given write access to the repository.
|
||||||
|
* A **TC (Technical Committee)** is a group of committers representing the required technical
|
||||||
|
expertise to resolve rare disputes.
|
||||||
|
|
||||||
|
# Logging Issues
|
||||||
|
|
||||||
|
Log an issue for any question or problem you might have. When in doubt, log an issue,
|
||||||
|
any additional policies about what to include will be provided in the responses. The only
|
||||||
|
exception is security disclosures which should be sent privately.
|
||||||
|
|
||||||
|
Committers may direct you to another repository, ask for additional clarifications, and
|
||||||
|
add appropriate metadata before the issue is addressed.
|
||||||
|
|
||||||
|
Please be courteous, respectful, and every participant is expected to follow the
|
||||||
|
project's Code of Conduct.
|
||||||
|
|
||||||
|
# Contributions
|
||||||
|
|
||||||
|
Any change to resources in this repository must be through pull requests. This applies to all changes
|
||||||
|
to documentation, code, binary files, etc. Even long term committers and TC members must use
|
||||||
|
pull requests.
|
||||||
|
|
||||||
|
No pull request can be merged without being reviewed.
|
||||||
|
|
||||||
|
For non-trivial contributions, pull requests should sit for at least 36 hours to ensure that
|
||||||
|
contributors in other timezones have time to review. Consideration should also be given to
|
||||||
|
weekends and other holiday periods to ensure active committers all have reasonable time to
|
||||||
|
become involved in the discussion and review process if they wish.
|
||||||
|
|
||||||
|
The default for each contribution is that it is accepted once no committer has an objection.
|
||||||
|
During review committers may also request that a specific contributor who is most versed in a
|
||||||
|
particular area gives a "LGTM" before the PR can be merged. There is no additional "sign off"
|
||||||
|
process for contributions to land. Once all issues brought by committers are addressed it can
|
||||||
|
be landed by any committer.
|
||||||
|
|
||||||
|
In the case of an objection being raised in a pull request by another committer, all involved
|
||||||
|
committers should seek to arrive at a consensus by way of addressing concerns being expressed
|
||||||
|
by discussion, compromise on the proposed change, or withdrawal of the proposed change.
|
||||||
|
|
||||||
|
If a contribution is controversial and committers cannot agree about how to get it to land
|
||||||
|
or if it should land then it should be escalated to the TC. TC members should regularly
|
||||||
|
discuss pending contributions in order to find a resolution. It is expected that only a
|
||||||
|
small minority of issues be brought to the TC for resolution and that discussion and
|
||||||
|
compromise among committers be the default resolution mechanism.
|
||||||
|
|
||||||
|
# Becoming a Committer
|
||||||
|
|
||||||
|
All contributors who land a non-trivial contribution should be on-boarded in a timely manner,
|
||||||
|
and added as a committer, and be given write access to the repository.
|
||||||
|
|
||||||
|
Committers are expected to follow this policy and continue to send pull requests, go through
|
||||||
|
proper review, and have other committers merge their pull requests.
|
||||||
|
|
||||||
|
# TC Process
|
||||||
|
|
||||||
|
The TC uses a "consensus seeking" process for issues that are escalated to the TC.
|
||||||
|
The group tries to find a resolution that has no open objections among TC members.
|
||||||
|
If a consensus cannot be reached that has no objections then a majority wins vote
|
||||||
|
is called. It is also expected that the majority of decisions made by the TC are via
|
||||||
|
a consensus seeking process and that voting is only used as a last-resort.
|
||||||
|
|
||||||
|
Resolution may involve returning the issue to committers with suggestions on how to
|
||||||
|
move forward towards a consensus. It is not expected that a meeting of the TC
|
||||||
|
will resolve all issues on its agenda during that meeting and may prefer to continue
|
||||||
|
the discussion happening among the committers.
|
||||||
|
|
||||||
|
Members can be added to the TC at any time. Any committer can nominate another committer
|
||||||
|
to the TC and the TC uses its standard consensus seeking process to evaluate whether or
|
||||||
|
not to add this new member. Members who do not participate consistently at the level of
|
||||||
|
a majority of the other members are expected to resign.
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
Copyright (c) 2022 Permissionless Software Foundation
|
Copyright (c) 2021-2024 Permissionless Software Foundation
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Pedigree
|
||||||
|
|
||||||
|
This repository was forked from [koa-api-boilerplate](https://github.com/christroutner/koa-api-boilerplate). Code changes from that upstream repository is frequently pulled in and merged to this repository.
|
||||||
@@ -24,8 +24,8 @@ This repository is one step in a longer path. Here are the major milestones of t
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- node **^14.18.2**
|
- node **^16.20.2**
|
||||||
- npm **^8.3.0**
|
- npm **^8.19.4**
|
||||||
- Docker **^20.10.8**
|
- Docker **^20.10.8**
|
||||||
- Docker Compose **^1.27.4**
|
- Docker Compose **^1.27.4**
|
||||||
|
|
||||||
@@ -58,35 +58,37 @@ docker-compose pull
|
|||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
You can bring the containers back up with `docker-compose up -d`.
|
- You can bring the containers down with `docker-compose down`
|
||||||
|
- You can bring the containers back up with `docker-compose up -d`.
|
||||||
|
|
||||||
### Operation Notes
|
### Development Environment
|
||||||
|
|
||||||
- There is a memory leak in the version of js-ipfs. The app is currently configured to shut down every 8 hours to flush memory. It relies on a process manager like pm2, Docker, or systemd to restart the app after it shuts down, in order to ensure continuous operation.
|
A development environment will allow you modify the code on-the-fly and contribute to the code base of this repository. Ubuntu v20 is the recommended OS for creating a dev environment. Other operating systems may cause issues.
|
||||||
|
|
||||||
- The PSF network operates as a private network. It does not connect or interact with the wider PSF network, relying instead on gateways to bridge the two networks, when they need to share content. This improves the performance and experience for everyone in the PSF network. To join the network, you'll need to add the [swarm.key](./swarm.key) file to the IPFS data folder.
|
```bash
|
||||||
|
git clone https://github.com/Permissionless-Software-Foundation/ipfs-service-provider
|
||||||
|
cd ipfs-service-provider
|
||||||
|
./install-mongo-sh
|
||||||
|
npm install
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
- [Instructions on setting up IPFS private networks.](https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md#private-networks)
|
## File Structure
|
||||||
- For external installations, the swarm.key file will typically go in `~/.ipfs/swarm.key`
|
|
||||||
- For production Docker containers, the key would go in `ipfs-service-provider/production/data/go-ipfs/data/swarm.key`
|
|
||||||
|
|
||||||
## Structure
|
The file layout of this repository follows the file layout of [Clean Architecture](https://christroutner.github.io/trouts-blog/blog/clean-architecture). Understaning the principles laid out this article will help developers navigate the code base.
|
||||||
|
|
||||||
The file layout of this repository differs from the koa-api-boilerplate. Instead, it follows the file layout of [Clean Architecture](troutsblog.com/blog/clean-architecture).
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
- `npm start` Start server on live mode
|
- `npm start` Start server on live mode
|
||||||
- `npm run docs` Generate API documentation
|
- `npm run docs` Generate API documentation
|
||||||
- `npm test` Run mocha tests
|
- `npm test` Run mocha tests
|
||||||
- `docker-compose build` Build a 'production' Docker container
|
|
||||||
- `docker-compose up` Run the docker container
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
API documentation is written inline and generated by [apidoc](http://apidocjs.com/).
|
API documentation is written inline and generated by [apidoc](http://apidocjs.com/). Docs can be generated with this command:
|
||||||
|
- `npm run docs`
|
||||||
|
|
||||||
Visit `http://localhost:5000/docs/` to view docs
|
Visit `http://localhost:5020/` to view docs
|
||||||
|
|
||||||
There is additional developer documentation in the [dev-docs directory](./dev-docs).
|
There is additional developer documentation in the [dev-docs directory](./dev-docs).
|
||||||
|
|
||||||
|
|||||||
+21
-17
@@ -8,23 +8,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// npm libraries
|
// npm libraries
|
||||||
const Koa = require('koa')
|
import Koa from 'koa'
|
||||||
const bodyParser = require('koa-bodyparser')
|
|
||||||
const convert = require('koa-convert')
|
import bodyParser from 'koa-bodyparser'
|
||||||
const logger = require('koa-logger')
|
import convert from 'koa-convert'
|
||||||
const mongoose = require('mongoose')
|
import logger from 'koa-logger'
|
||||||
const session = require('koa-generic-session')
|
import mongoose from 'mongoose'
|
||||||
const passport = require('koa-passport')
|
import session from 'koa-generic-session'
|
||||||
const mount = require('koa-mount')
|
import passport from 'koa-passport'
|
||||||
const serve = require('koa-static')
|
import mount from 'koa-mount'
|
||||||
const cors = require('kcors')
|
import serve from 'koa-static'
|
||||||
|
import cors from 'kcors'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const config = require('../config') // this first.
|
import config from '../config/index.js' // this first.
|
||||||
const AdminLib = require('../src/adapters/admin')
|
|
||||||
const errorMiddleware = require('../src/controllers/rest-api/middleware/error')
|
import AdminLib from '../src/adapters/admin.js'
|
||||||
const { wlogger } = require('../src/adapters/wlogger')
|
import errorMiddleware from '../src/controllers/rest-api/middleware/error.js'
|
||||||
const Controllers = require('../src/controllers')
|
import wlogger from '../src/adapters/wlogger.js'
|
||||||
|
import Controllers from '../src/controllers/index.js'
|
||||||
|
import { applyPassportMods } from '../config/passport.js'
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
constructor () {
|
constructor () {
|
||||||
@@ -70,7 +73,8 @@ class Server {
|
|||||||
app.use(mount('/logs', serve(`${process.cwd()}/config/logs`)))
|
app.use(mount('/logs', serve(`${process.cwd()}/config/logs`)))
|
||||||
|
|
||||||
// User Authentication
|
// User Authentication
|
||||||
require('../config/passport')
|
// require('../config/passport')
|
||||||
|
applyPassportMods(passport)
|
||||||
app.use(passport.initialize())
|
app.use(passport.initialize())
|
||||||
app.use(passport.session())
|
app.use(passport.session())
|
||||||
|
|
||||||
@@ -137,4 +141,4 @@ class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Server
|
export default Server
|
||||||
|
|||||||
Vendored
+27
-5
@@ -1,12 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
This file is used to store unsecure, application-specific data common to all
|
This file is used to store unsecure, application-specific data common to all
|
||||||
environments.
|
environments.
|
||||||
|
|
||||||
|
Additional Environent Variables:
|
||||||
|
- CONNECT_PREF: should have a value of 'cr' (default), or 'direct'. This is
|
||||||
|
used by helia-coord to select a connection preference between peers. Servers
|
||||||
|
with an ip4 or ip6 address should use 'direct'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint no-unneeded-ternary:0 */
|
/* eslint no-unneeded-ternary:0 */
|
||||||
|
|
||||||
|
// Hack to get __dirname back.
|
||||||
|
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
|
||||||
|
import * as url from 'url'
|
||||||
|
|
||||||
// Get the version from the package.json file.
|
// Get the version from the package.json file.
|
||||||
const pkgInfo = require('../../package.json')
|
import { readFileSync } from 'fs'
|
||||||
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||||
|
const pkgInfo = JSON.parse(readFileSync(`${__dirname.toString()}/../../package.json`))
|
||||||
|
|
||||||
const version = pkgInfo.version
|
const version = pkgInfo.version
|
||||||
|
|
||||||
const ipfsCoordName = process.env.COORD_NAME
|
const ipfsCoordName = process.env.COORD_NAME
|
||||||
@@ -15,9 +27,9 @@ const ipfsCoordName = process.env.COORD_NAME
|
|||||||
|
|
||||||
console.log('GET_JWT_AT_STARTUP: ', process.env.GET_JWT_AT_STARTUP)
|
console.log('GET_JWT_AT_STARTUP: ', process.env.GET_JWT_AT_STARTUP)
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
// Configure TCP port.
|
// Configure TCP port.
|
||||||
port: process.env.PORT || 5001,
|
port: process.env.PORT || 5020,
|
||||||
|
|
||||||
// Password for HTML UI that displays logs.
|
// Password for HTML UI that displays logs.
|
||||||
logPass: 'test',
|
logPass: 'test',
|
||||||
@@ -49,6 +61,7 @@ module.exports = {
|
|||||||
: 'demo',
|
: 'demo',
|
||||||
|
|
||||||
// IPFS settings.
|
// IPFS settings.
|
||||||
|
useIpfs: process.env.DISABLE_IPFS ? false : true, // Disable IPFS flag
|
||||||
isCircuitRelay: process.env.ENABLE_CIRCUIT_RELAY ? true : false,
|
isCircuitRelay: process.env.ENABLE_CIRCUIT_RELAY ? true : false,
|
||||||
// SSL domain used for websocket connection via browsers.
|
// SSL domain used for websocket connection via browsers.
|
||||||
crDomain: process.env.CR_DOMAIN ? process.env.CR_DOMAIN : '',
|
crDomain: process.env.CR_DOMAIN ? process.env.CR_DOMAIN : '',
|
||||||
@@ -85,11 +98,20 @@ module.exports = {
|
|||||||
debugLevel: process.env.DEBUG_LEVEL ? parseInt(process.env.DEBUG_LEVEL) : 2,
|
debugLevel: process.env.DEBUG_LEVEL ? parseInt(process.env.DEBUG_LEVEL) : 2,
|
||||||
|
|
||||||
// Settings for production, using external go-ipfs node.
|
// Settings for production, using external go-ipfs node.
|
||||||
isProduction: process.env.SVC_ENV === 'production' ? true : false,
|
isProduction: process.env.SVC_ENV === 'prod' ? true : false,
|
||||||
ipfsHost: process.env.IPFS_HOST ? process.env.IPFS_HOST : 'localhost',
|
ipfsHost: process.env.IPFS_HOST ? process.env.IPFS_HOST : 'localhost',
|
||||||
ipfsApiPort: process.env.IPFS_API_PORT
|
ipfsApiPort: process.env.IPFS_API_PORT
|
||||||
? parseInt(process.env.IPFS_API_PORT)
|
? parseInt(process.env.IPFS_API_PORT)
|
||||||
: 5001,
|
: 5001,
|
||||||
|
|
||||||
chatPubSubChan: 'psf-ipfs-chat-001'
|
chatPubSubChan: 'psf-ipfs-chat-001',
|
||||||
|
|
||||||
|
// This can add specific Circuit Relay v2 servers to connect to.
|
||||||
|
bootstrapRelays: [
|
||||||
|
// v2 Circuit Relay (Token Tiger)
|
||||||
|
// '/ip4/137.184.93.145/tcp/8001/p2p/12D3KooWGMEKkdJfyZbwdH9EafZbRTtMn7FnhWPrE4MhRty2763g',
|
||||||
|
|
||||||
|
// v2 Circuit Relay server (FullStack.cash)
|
||||||
|
// '/ip4/78.46.129.7/tcp/4001/p2p/12D3KooWFQ11GQ5NubsJGhYZ4X3wrAGimLevxfm6HPExCrMYhpSL'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
specified.
|
specified.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
session: 'secret-boilerplate-token',
|
session: 'secret-boilerplate-token',
|
||||||
token: 'secret-jwt-token',
|
token: 'secret-jwt-token',
|
||||||
database: 'mongodb://localhost:27017/bch-service-dev',
|
database: 'mongodb://localhost:27017/bch-service-dev',
|
||||||
|
|||||||
Vendored
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
so as not to conflict with the default host port of 27017 for MongoDB.
|
so as not to conflict with the default host port of 27017 for MongoDB.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
session: 'secret-boilerplate-token',
|
session: 'secret-boilerplate-token',
|
||||||
token: 'secret-jwt-token',
|
token: 'secret-jwt-token',
|
||||||
database: process.env.DBURL
|
database: process.env.DBURL
|
||||||
|
|||||||
Vendored
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
This is the environment run by the test suite.
|
This is the environment run by the test suite.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
session: 'secret-boilerplate-token',
|
session: 'secret-boilerplate-token',
|
||||||
token: 'secret-jwt-token',
|
token: 'secret-jwt-token',
|
||||||
database: 'mongodb://localhost:27017/bch-service-test',
|
database: 'mongodb://localhost:27017/bch-service-test',
|
||||||
|
|||||||
+14
-3
@@ -1,6 +1,17 @@
|
|||||||
const common = require('./env/common')
|
import common from './env/common.js'
|
||||||
|
|
||||||
|
import development from './env/development.js'
|
||||||
|
import production from './env/production.js'
|
||||||
|
import test from './env/test.js'
|
||||||
|
|
||||||
const env = process.env.SVC_ENV || 'development'
|
const env = process.env.SVC_ENV || 'development'
|
||||||
const config = require(`./env/${env}`)
|
console.log(`Loading config for this environment: ${env}`)
|
||||||
|
|
||||||
module.exports = Object.assign({}, common, config)
|
let config = development
|
||||||
|
if (env === 'test') {
|
||||||
|
config = test
|
||||||
|
} else if (env === 'prod') {
|
||||||
|
config = production
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Object.assign({}, common, config)
|
||||||
|
|||||||
+32
-29
@@ -1,30 +1,6 @@
|
|||||||
const passport = require('koa-passport')
|
// import passport from 'koa-passport';
|
||||||
const User = require('../src/adapters/localdb/models/users')
|
import User from '../src/adapters/localdb/models/users.js'
|
||||||
const Strategy = require('passport-local')
|
import Strategy from 'passport-local'
|
||||||
|
|
||||||
passport.serializeUser((user, done) => {
|
|
||||||
done(null, user.id)
|
|
||||||
})
|
|
||||||
|
|
||||||
passport.deserializeUser(async (id, done) => {
|
|
||||||
try {
|
|
||||||
const user = await User.findById(id, '-password')
|
|
||||||
done(null, user)
|
|
||||||
} catch (err) {
|
|
||||||
done(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
passport.use(
|
|
||||||
'local',
|
|
||||||
new Strategy(
|
|
||||||
{
|
|
||||||
usernameField: 'email',
|
|
||||||
passwordField: 'password'
|
|
||||||
},
|
|
||||||
passportCallback
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
async function passportCallback (email, password, done) {
|
async function passportCallback (email, password, done) {
|
||||||
try {
|
try {
|
||||||
@@ -49,5 +25,32 @@ async function passportCallback (email, password, done) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For testing
|
function applyPassportMods (passport) {
|
||||||
module.exports = { passport, passportCallback }
|
passport.serializeUser((user, done) => {
|
||||||
|
done(null, user.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
passport.deserializeUser(async (id, done) => {
|
||||||
|
try {
|
||||||
|
const user = await User.findById(id, '-password')
|
||||||
|
done(null, user)
|
||||||
|
} catch (err) {
|
||||||
|
done(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
passport.use(
|
||||||
|
'local',
|
||||||
|
new Strategy(
|
||||||
|
{
|
||||||
|
usernameField: 'email',
|
||||||
|
passwordField: 'password'
|
||||||
|
},
|
||||||
|
passportCallback
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export { applyPassportMods, passportCallback }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const Server = require('./bin/server.js')
|
import Server from './bin/server.js'
|
||||||
const server = new Server()
|
const server = new Server()
|
||||||
|
|
||||||
server.startServer()
|
server.startServer()
|
||||||
|
|||||||
Generated
+13793
-20686
File diff suppressed because it is too large
Load Diff
+25
-16
@@ -1,20 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "ipfs-bch-wallet-service",
|
"name": "ipfs-bch-wallet-service",
|
||||||
"version": "2.0.0",
|
"version": "3.0.0",
|
||||||
"description": "IPFS and REST service providing blockchain access needed by a wallet. ",
|
"description": "IPFS and REST service providing blockchain access needed by a wallet. ",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index.js",
|
"start": "node index.js",
|
||||||
"test": "npm run test:all",
|
"test": "npm run test:all",
|
||||||
"test:all": "export SVC_ENV=test && nyc --reporter=text mocha --exit --timeout 15000 --recursive test/unit test/e2e/automated/",
|
"test:all": "export SVC_ENV=test && c8 --reporter=text mocha --exit --timeout 15000 --recursive test/unit test/e2e/automated/",
|
||||||
"test:unit": "export SVC_ENV=test && mocha --exit --timeout 15000 --recursive test/unit/",
|
"test:unit": "export SVC_ENV=test && mocha --exit --timeout 15000 --recursive test/unit/",
|
||||||
"test:e2e:auto": "export SVC_ENV=test && mocha --exit --timeout 30000 test/e2e/automated/",
|
"test:e2e:auto": "export SVC_ENV=test && mocha --exit --timeout 30000 test/e2e/automated/",
|
||||||
"test:integration": "export SVC_ENV=test && mocha --timeout 30000 --recursive test/integration/",
|
"test:integration": "export SVC_ENV=test && mocha --timeout 30000 --recursive test/integration/",
|
||||||
"test:temp": "export SVC_ENV=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/",
|
"test:temp": "export SVC_ENV=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/",
|
||||||
"lint": "standard --env mocha --fix",
|
"lint": "standard --env mocha --fix",
|
||||||
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
||||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
"coverage": "c8 report --reporter=text-lcov | coveralls",
|
||||||
"coverage:report": "export SVC_ENV=test && nyc --reporter=html mocha --exit --timeout 15000 --recursive test/unit/ test/e2e/automated/"
|
"coverage:report": "export SVC_ENV=test && c8 --reporter=html mocha --exit --timeout 15000 --recursive test/unit/ test/e2e/automated/"
|
||||||
},
|
},
|
||||||
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -24,13 +25,25 @@
|
|||||||
},
|
},
|
||||||
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-service",
|
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-service",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@chainsafe/libp2p-gossipsub": "11.0.1",
|
||||||
|
"@chainsafe/libp2p-noise": "14.1.0",
|
||||||
|
"@chainsafe/libp2p-yamux": "6.0.1",
|
||||||
|
"@helia/unixfs": "3.0.1",
|
||||||
|
"@libp2p/bootstrap": "10.0.7",
|
||||||
|
"@libp2p/circuit-relay-v2": "1.0.13",
|
||||||
|
"@libp2p/identify": "1.0.6",
|
||||||
|
"@libp2p/keychain": "4.0.7",
|
||||||
|
"@libp2p/logger": "4.0.5",
|
||||||
|
"@libp2p/tcp": "9.0.7",
|
||||||
|
"@libp2p/webrtc": "4.0.17",
|
||||||
"@psf/bch-js": "6.7.3",
|
"@psf/bch-js": "6.7.3",
|
||||||
"axios": "0.27.2",
|
"axios": "0.27.2",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
|
"blockstore-fs": "1.1.8",
|
||||||
|
"datastore-fs": "9.1.6",
|
||||||
"glob": "7.1.6",
|
"glob": "7.1.6",
|
||||||
"ipfs": "0.62.3",
|
"helia": "2.1.0",
|
||||||
"ipfs-coord": "8.0.8",
|
"helia-coord": "1.5.5",
|
||||||
"ipfs-http-client": "55.0.0",
|
|
||||||
"jsonrpc-lite": "2.2.0",
|
"jsonrpc-lite": "2.2.0",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "8.5.1",
|
||||||
"jwt-bch-lib": "1.3.0",
|
"jwt-bch-lib": "1.3.0",
|
||||||
@@ -45,32 +58,28 @@
|
|||||||
"koa-router": "10.0.0",
|
"koa-router": "10.0.0",
|
||||||
"koa-static": "5.0.0",
|
"koa-static": "5.0.0",
|
||||||
"koa2-ratelimit": "0.9.1",
|
"koa2-ratelimit": "0.9.1",
|
||||||
|
"libp2p": "1.2.1",
|
||||||
"line-reader": "0.4.0",
|
"line-reader": "0.4.0",
|
||||||
|
"minimal-slp-wallet": "5.11.1",
|
||||||
"mongoose": "5.13.14",
|
"mongoose": "5.13.14",
|
||||||
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
|
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
|
||||||
"nodemailer": "6.7.5",
|
"nodemailer": "6.7.5",
|
||||||
"passport-local": "1.0.0",
|
"passport-local": "1.0.0",
|
||||||
"public-ip": "4.0.4",
|
"public-ip": "6.0.1",
|
||||||
"winston": "3.3.3",
|
"winston": "3.3.3",
|
||||||
"winston-daily-rotate-file": "4.5.0"
|
"winston-daily-rotate-file": "4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"apidoc": "0.51.1",
|
"apidoc": "0.51.1",
|
||||||
|
"c8": "7.12.0",
|
||||||
"chai": "4.3.0",
|
"chai": "4.3.0",
|
||||||
"coveralls": "3.1.0",
|
"coveralls": "3.1.0",
|
||||||
"eslint": "7.19.0",
|
|
||||||
"eslint-config-prettier": "7.2.0",
|
|
||||||
"eslint-config-standard": "16.0.2",
|
|
||||||
"eslint-plugin-node": "11.1.0",
|
|
||||||
"eslint-plugin-prettier": "3.3.1",
|
|
||||||
"eslint-plugin-standard": "4.0.0",
|
|
||||||
"husky": "4.3.8",
|
"husky": "4.3.8",
|
||||||
"lodash.clonedeep": "4.5.0",
|
"lodash.clonedeep": "4.5.0",
|
||||||
"mocha": "10.0.0",
|
"mocha": "10.0.0",
|
||||||
"nyc": "15.1.0",
|
|
||||||
"semantic-release": "19.0.3",
|
"semantic-release": "19.0.3",
|
||||||
"sinon": "9.2.4",
|
"sinon": "9.2.4",
|
||||||
"standard": "16.0.3",
|
"standard": "17.0.0",
|
||||||
"uuid": "8.3.2"
|
"uuid": "8.3.2"
|
||||||
},
|
},
|
||||||
"release": {
|
"release": {
|
||||||
|
|||||||
@@ -10,9 +10,12 @@ RUN apt-get update
|
|||||||
RUN apt-get install -y sudo git curl nano gnupg wget
|
RUN apt-get install -y sudo git curl nano gnupg wget
|
||||||
|
|
||||||
#Install Node and NPM
|
#Install Node and NPM
|
||||||
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
|
RUN sudo apt-get install -y ca-certificates curl gnupg
|
||||||
RUN bash nodesource_setup.sh
|
RUN sudo mkdir -p /etc/apt/keyrings
|
||||||
RUN apt-get install -y nodejs build-essential
|
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||||
|
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_16.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
|
||||||
|
RUN sudo apt-get update
|
||||||
|
RUN sudo apt-get install -y nodejs build-essential
|
||||||
|
|
||||||
#Create the user 'safeuser' and add them to the sudo group.
|
#Create the user 'safeuser' and add them to the sudo group.
|
||||||
RUN useradd -ms /bin/bash safeuser
|
RUN useradd -ms /bin/bash safeuser
|
||||||
@@ -36,7 +39,7 @@ RUN npm install -g npm
|
|||||||
|
|
||||||
# Update to the latest version of npm.
|
# Update to the latest version of npm.
|
||||||
#RUN npm install -g npm@7.23.0
|
#RUN npm install -g npm@7.23.0
|
||||||
RUN npm install -g npm
|
#RUN npm install -g npm
|
||||||
|
|
||||||
# npm mirror to prevent direct dependency on npm.
|
# npm mirror to prevent direct dependency on npm.
|
||||||
RUN npm set registry http://94.130.170.209:4873/
|
RUN npm set registry http://94.130.170.209:4873/
|
||||||
|
|||||||
@@ -14,36 +14,9 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
ipfs-bch-wallet:
|
ipfs-bch-wallet:
|
||||||
image: christroutner/trickle-ipfs:v1.0.1
|
build: .
|
||||||
#build:
|
#image: christroutner/ipfs-service-provider:v5.0.1
|
||||||
# context: ./
|
container_name: ipfs-service
|
||||||
# dockerfile: Dockerfile
|
|
||||||
container_name: ipfs-bch-wallet
|
|
||||||
environment:
|
|
||||||
IPFS_DAEMON_ARGUMENTS: '--enable-pubsub-experiment --migrate=true --agent-version-suffix=docker --routing=dhtclient'
|
|
||||||
UPLOAD_KBPS: '100'
|
|
||||||
DOWNLOAD_KBPS: '100'
|
|
||||||
logging:
|
|
||||||
driver: 'json-file'
|
|
||||||
options:
|
|
||||||
max-size: '10m'
|
|
||||||
max-file: '10'
|
|
||||||
mem_limit: 2000mb
|
|
||||||
ports:
|
|
||||||
- 4001:4001
|
|
||||||
- 4003:4003
|
|
||||||
- 172.17.0.1:5001:5001
|
|
||||||
- 172.17.0.1:8080:8080
|
|
||||||
command: [
|
|
||||||
'./start-ipfs.sh'
|
|
||||||
]
|
|
||||||
volumes:
|
|
||||||
- ../data/go-ipfs/data:/root/.ipfs
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
bch-wallet-service:
|
|
||||||
build: ./
|
|
||||||
container_name: bch-wallet-service
|
|
||||||
logging:
|
logging:
|
||||||
driver: 'json-file'
|
driver: 'json-file'
|
||||||
options:
|
options:
|
||||||
@@ -52,9 +25,10 @@ services:
|
|||||||
mem_limit: 1000mb
|
mem_limit: 1000mb
|
||||||
links:
|
links:
|
||||||
- mongo-bch-service
|
- mongo-bch-service
|
||||||
- ipfs-bch-wallet
|
|
||||||
ports:
|
ports:
|
||||||
- '5010:5010' # <host port>:<container port>
|
- '5010:5010' # <host port>:<container port>
|
||||||
|
- '4001:4001'
|
||||||
|
- '4003:4003'
|
||||||
volumes:
|
volumes:
|
||||||
- ../data/ipfsdata:/home/safeuser/ipfs-bch-wallet-service/.ipfsdata
|
- ../data/ipfsdata:/home/safeuser/ipfs-bch-wallet-service/.ipfsdata
|
||||||
- ./start-production.sh:/home/safeuser/ipfs-bch-wallet-service/start-production.sh
|
- ./start-production.sh:/home/safeuser/ipfs-bch-wallet-service/start-production.sh
|
||||||
|
|||||||
@@ -38,10 +38,14 @@ export DBURL=mongodb://172.17.0.1:5555/ipfs-service-prod
|
|||||||
export PORT=5010
|
export PORT=5010
|
||||||
|
|
||||||
# Production settings using external go-ipfs node.
|
# Production settings using external go-ipfs node.
|
||||||
export SVC_ENV=production
|
export SVC_ENV=prod
|
||||||
export IPFS_HOST=172.17.0.1
|
export IPFS_HOST=172.17.0.1
|
||||||
export IPFS_API_PORT=5001
|
export IPFS_API_PORT=5001
|
||||||
export IPFS_TCP_PORT=4001
|
export IPFS_TCP_PORT=4001
|
||||||
export IPFS_WS_PORT=4003
|
export IPFS_WS_PORT=4003
|
||||||
|
|
||||||
|
# Set the debug level for helia-coord. 0-3.
|
||||||
|
# 0 = no debug logs. 3 = maximum debug logs.
|
||||||
|
export DEBUG_LEVEL=0
|
||||||
|
|
||||||
npm start
|
npm start
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export COORD_NAME=ipfs-service-provider-generic
|
|||||||
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
|
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
|
||||||
|
|
||||||
# 0 = less verbose. 3 = most verbose
|
# 0 = less verbose. 3 = most verbose
|
||||||
export DEBUG_LEVEL=2
|
export DEBUG_LEVEL=0
|
||||||
|
|
||||||
# Production settings that use external IPFS node.
|
# Production settings that use external IPFS node.
|
||||||
# https://github.com/christroutner/docker-ipfs
|
# https://github.com/christroutner/docker-ipfs
|
||||||
|
|||||||
+18
-8
@@ -13,16 +13,24 @@
|
|||||||
in the Adapter directory.
|
in the Adapter directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
// Global npm libraries
|
||||||
const axios = require('axios').default
|
import axios from 'axios'
|
||||||
const mongoose = require('mongoose')
|
import mongoose from 'mongoose'
|
||||||
const User = require('../adapters/localdb/models/users')
|
|
||||||
const config = require('../../config')
|
// Local libraries
|
||||||
const JsonFiles = require('../adapters/json-files')
|
import User from '../adapters/localdb/models/users.js'
|
||||||
|
import config from '../../config/index.js'
|
||||||
|
import JsonFiles from '../adapters/json-files.js'
|
||||||
|
|
||||||
|
// Hack to get __dirname back.
|
||||||
|
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
|
||||||
|
import * as url from 'url'
|
||||||
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||||
|
|
||||||
const jsonFiles = new JsonFiles()
|
const jsonFiles = new JsonFiles()
|
||||||
|
|
||||||
const JSON_FILE = `system-user-${config.env}.json`
|
const JSON_FILE = `system-user-${config.env}.json`
|
||||||
const JSON_PATH = `${__dirname.toString()}/../../config/${JSON_FILE}`
|
const JSON_PATH = `${__dirname.toString()}../../config/${JSON_FILE}`
|
||||||
|
|
||||||
const LOCALHOST = `http://localhost:${config.port}`
|
const LOCALHOST = `http://localhost:${config.port}`
|
||||||
const context = {}
|
const context = {}
|
||||||
@@ -82,6 +90,8 @@ class Admin {
|
|||||||
// applications like the Task Manager and the test scripts can access.
|
// applications like the Task Manager and the test scripts can access.
|
||||||
|
|
||||||
await jsonFiles.writeJSON(context, JSON_PATH)
|
await jsonFiles.writeJSON(context, JSON_PATH)
|
||||||
|
// console.log('context: ', context)
|
||||||
|
// console.log('JSON_PATH: ', JSON_PATH)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -169,4 +179,4 @@ class Admin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Admin
|
export default Admin
|
||||||
|
|||||||
@@ -3,13 +3,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable no-useless-escape */
|
/* eslint-disable no-useless-escape */
|
||||||
|
import config from '../../config/index.js'
|
||||||
|
import NodeMailer from '../adapters/nodemailer.js'
|
||||||
|
import wlogger from '../adapters/wlogger.js'
|
||||||
|
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||||
|
|
||||||
const config = require('../../config')
|
|
||||||
|
|
||||||
const NodeMailer = require('../adapters/nodemailer')
|
|
||||||
const nodemailer = new NodeMailer()
|
const nodemailer = new NodeMailer()
|
||||||
const { wlogger } = require('../adapters/wlogger')
|
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
@@ -60,4 +59,4 @@ class ContactLib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = ContactLib
|
export default ContactLib
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
for this file.
|
for this file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const JwtLib = require('jwt-bch-lib')
|
import JwtLib from 'jwt-bch-lib'
|
||||||
const BCHJS = require('@psf/bch-js')
|
|
||||||
|
import BCHJS from '@psf/bch-js'
|
||||||
|
|
||||||
class FullStackJWT {
|
class FullStackJWT {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -98,4 +99,4 @@ class FullStackJWT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = FullStackJWT
|
export default FullStackJWT
|
||||||
|
|||||||
+19
-12
@@ -5,19 +5,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public NPM libraries
|
// Public NPM libraries
|
||||||
const BCHJS = require('@psf/bch-js')
|
import BCHJS from '@psf/bch-js'
|
||||||
|
|
||||||
// Load individual adapter libraries.
|
// Load individual adapter libraries.
|
||||||
const IPFSAdapter = require('./ipfs')
|
import IPFSAdapter from './ipfs/index.js'
|
||||||
const LocalDB = require('./localdb')
|
|
||||||
const LogsAPI = require('./logapi')
|
|
||||||
const Passport = require('./passport')
|
|
||||||
const Nodemailer = require('./nodemailer')
|
|
||||||
// const { wlogger } = require('./wlogger')
|
|
||||||
const JSONFiles = require('./json-files')
|
|
||||||
const FullStackJWT = require('./fullstack-jwt')
|
|
||||||
|
|
||||||
const config = require('../../config')
|
import LocalDB from './localdb/index.js'
|
||||||
|
import LogsAPI from './logapi.js'
|
||||||
|
import Passport from './passport.js'
|
||||||
|
import Nodemailer from './nodemailer.js'
|
||||||
|
|
||||||
|
// const { wlogger } = require('./wlogger')
|
||||||
|
import JSONFiles from './json-files.js'
|
||||||
|
|
||||||
|
import FullStackJWT from './fullstack-jwt.js'
|
||||||
|
import config from '../../config/index.js'
|
||||||
|
|
||||||
class Adapters {
|
class Adapters {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -53,7 +55,12 @@ class Adapters {
|
|||||||
// Start the IPFS node.
|
// Start the IPFS node.
|
||||||
// Do not start these adapters if this is an e2e test.
|
// Do not start these adapters if this is an e2e test.
|
||||||
if (this.config.env !== 'test') {
|
if (this.config.env !== 'test') {
|
||||||
await this.ipfs.start({ bchjs: this.bchjs })
|
if (this.config.useIpfs) {
|
||||||
|
await this.ipfs.start()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// These lines are here to ensure code coverage hits 100%.
|
||||||
|
console.log('Not starting IPFS node since this is an e2e test.')
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Async Adapters have been started.')
|
console.log('Async Adapters have been started.')
|
||||||
@@ -66,4 +73,4 @@ class Adapters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Adapters
|
export default Adapters
|
||||||
|
|||||||
+139
-4
@@ -3,9 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const IpfsAdapter = require('./ipfs')
|
import IpfsAdapter from './ipfs.js'
|
||||||
const IpfsCoordAdapter = require('./ipfs-coord')
|
|
||||||
const config = require('../../../config')
|
import IpfsCoordAdapter from './ipfs-coord.js'
|
||||||
|
import config from '../../../config/index.js'
|
||||||
|
|
||||||
class IPFS {
|
class IPFS {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -66,6 +67,140 @@ class IPFS {
|
|||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the status of this IPFS node.
|
||||||
|
// Create an object with different metrics about this IPFS node, then return
|
||||||
|
// the object.
|
||||||
|
getStatus () {
|
||||||
|
try {
|
||||||
|
const statusObj = {
|
||||||
|
ipfsId: this.ipfsCoordAdapter.ipfsCoord.thisNode.ipfsId,
|
||||||
|
multiAddrs: this.ipfsCoordAdapter.ipfsCoord.thisNode.ipfsMultiaddrs,
|
||||||
|
bchAddr: this.ipfsCoordAdapter.ipfsCoord.thisNode.bchAddr,
|
||||||
|
slpAddr: this.ipfsCoordAdapter.ipfsCoord.thisNode.slpAddr,
|
||||||
|
pubKey: this.ipfsCoordAdapter.ipfsCoord.thisNode.pubKey,
|
||||||
|
peers: this.ipfsCoordAdapter.ipfsCoord.thisNode.peerList.length,
|
||||||
|
relays: this.ipfsCoordAdapter.ipfsCoord.thisNode.relayData.length
|
||||||
|
}
|
||||||
|
|
||||||
|
return statusObj
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in ipfs-coord.js/getStatus()')
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get details on the other peers this node is connected to.
|
||||||
|
async getPeers (showAll) {
|
||||||
|
try {
|
||||||
|
const peerData = this.ipfsCoordAdapter.ipfsCoord.thisNode.peerData
|
||||||
|
// console.log(`peerData: ${JSON.stringify(peerData, null, 2)}`)
|
||||||
|
|
||||||
|
let ipfsPeers =
|
||||||
|
await this.ipfsCoordAdapter.ipfsCoord.adapters.ipfs.getPeers()
|
||||||
|
// console.log('ipfsPeers: ', ipfsPeers)
|
||||||
|
|
||||||
|
ipfsPeers = this._removeDuplicatePeers(ipfsPeers)
|
||||||
|
// console.log('filtered ipfsPeers: ', ipfsPeers)
|
||||||
|
|
||||||
|
const peerDataOut = []
|
||||||
|
|
||||||
|
// Loop through each IPFS peer and hydrate it with data from the peerData.
|
||||||
|
for (let i = 0; i < ipfsPeers.length; i++) {
|
||||||
|
const thisPeer = {
|
||||||
|
peer: ipfsPeers[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!showAll) {
|
||||||
|
// // Delete properties that don't contain good info.
|
||||||
|
// delete thisPeer.muxer
|
||||||
|
// delete thisPeer.latency
|
||||||
|
// delete thisPeer.streams
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Get the ipfs-coord peer data for this peer.
|
||||||
|
let thisPeerData = peerData.filter((x) =>
|
||||||
|
x.from.includes(thisPeer.peer)
|
||||||
|
)
|
||||||
|
thisPeerData = thisPeerData[0]
|
||||||
|
// console.log('thisPeerData: ', thisPeerData)
|
||||||
|
|
||||||
|
// Skip if peerData for this IPFS peer could not be found.
|
||||||
|
// if (!thisPeerData) continue
|
||||||
|
|
||||||
|
try {
|
||||||
|
// console.log('thisPeerData: ', thisPeerData)
|
||||||
|
|
||||||
|
// Add data to the IPFS peer data.
|
||||||
|
thisPeer.name = thisPeerData.data.jsonLd.name
|
||||||
|
thisPeer.protocol = thisPeerData.data.jsonLd.protocol
|
||||||
|
thisPeer.version = thisPeerData.data.jsonLd.version
|
||||||
|
thisPeer.connectionAddr = thisPeerData.data.connectionAddr
|
||||||
|
|
||||||
|
if (showAll) {
|
||||||
|
// Add all the peer data.
|
||||||
|
thisPeer.peerData = thisPeerData
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(
|
||||||
|
`warning: ${thisPeer.peer}: ${err.message}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
peerDataOut.push(thisPeer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return peerDataOut
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in getPeers(): ', err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expects an array of peers and returns an array of peers with duplicates
|
||||||
|
// removed.
|
||||||
|
// This function is used by getPeers()
|
||||||
|
_removeDuplicatePeers (arr) {
|
||||||
|
// https://stackoverflow.com/questions/2218999/how-to-remove-all-duplicates-from-an-array-of-objects
|
||||||
|
return arr.filter((v, i, a) => a.findIndex((t) => t === v) === i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get data about the known Circuit Relays. Hydrate with data from peers list.
|
||||||
|
getRelays () {
|
||||||
|
try {
|
||||||
|
const relayData = this.ipfsCoordAdapter.ipfsCoord.thisNode.relayData
|
||||||
|
const peerData = this.ipfsCoordAdapter.ipfsCoord.thisNode.peerData
|
||||||
|
// console.log(`relayData: ${JSON.stringify(relayData, null, 2)}`)
|
||||||
|
// console.log(`peerData: ${JSON.stringify(peerData, null, 2)}`)
|
||||||
|
|
||||||
|
for (let i = 0; i < relayData.length; i++) {
|
||||||
|
const thisRelay = relayData[i]
|
||||||
|
|
||||||
|
// Find the peer that corresponds to this relay.
|
||||||
|
const thisPeer = peerData.filter((x) =>
|
||||||
|
x.from.includes(thisRelay.ipfsId)
|
||||||
|
)
|
||||||
|
// console.log('thisPeer: ', thisPeer)
|
||||||
|
|
||||||
|
// If the peer couldn't be found, skip.
|
||||||
|
if (!thisPeer.length) {
|
||||||
|
thisRelay.name = ''
|
||||||
|
thisRelay.description = ''
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
thisRelay.name = thisPeer[0].data.jsonLd.name
|
||||||
|
thisRelay.description = thisPeer[0].data.jsonLd.description
|
||||||
|
}
|
||||||
|
|
||||||
|
const v1Relays = this.config.v1Relays
|
||||||
|
|
||||||
|
return { v2Relays: relayData, v1Relays }
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in getRelays(): ', err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = IPFS
|
export default IPFS
|
||||||
|
|||||||
@@ -5,12 +5,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Global npm libraries
|
// Global npm libraries
|
||||||
const IpfsCoord = require('ipfs-coord')
|
// import IpfsCoord from 'ipfs-coord-esm'
|
||||||
// const BCHJS = require('@psf/bch-js')
|
import IpfsCoord from 'helia-coord'
|
||||||
const publicIp = require('public-ip')
|
|
||||||
|
// import BCHJS from '@psf/bch-js';
|
||||||
|
import SlpWallet from 'minimal-slp-wallet'
|
||||||
|
import { publicIpv4 } from 'public-ip'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const config = require('../../../config')
|
import config from '../../../config/index.js'
|
||||||
|
|
||||||
// const JSONRPC = require('../../controllers/json-rpc/')
|
// const JSONRPC = require('../../controllers/json-rpc/')
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
@@ -34,9 +38,10 @@ class IpfsCoordAdapter {
|
|||||||
// Encapsulate dependencies
|
// Encapsulate dependencies
|
||||||
this.IpfsCoord = IpfsCoord
|
this.IpfsCoord = IpfsCoord
|
||||||
this.ipfsCoord = {}
|
this.ipfsCoord = {}
|
||||||
// this.rpc = new JSONRPC()
|
// this.bchjs = new BCHJS()
|
||||||
|
this.wallet = new SlpWallet()
|
||||||
this.config = config
|
this.config = config
|
||||||
this.publicIp = publicIp
|
this.publicIp = publicIpv4
|
||||||
|
|
||||||
// Properties of this class instance.
|
// Properties of this class instance.
|
||||||
this.isReady = false
|
this.isReady = false
|
||||||
@@ -47,10 +52,13 @@ class IpfsCoordAdapter {
|
|||||||
async start (localConfig = {}) {
|
async start (localConfig = {}) {
|
||||||
const circuitRelayInfo = {}
|
const circuitRelayInfo = {}
|
||||||
|
|
||||||
|
// Wait for the BCH wallet to create the wallet.
|
||||||
|
await this.wallet.walletInfoPromise
|
||||||
|
|
||||||
// If configured as a Circuit Relay, get the public IP addresses for this node.
|
// If configured as a Circuit Relay, get the public IP addresses for this node.
|
||||||
if (this.config.isCircuitRelay) {
|
if (this.config.isCircuitRelay) {
|
||||||
try {
|
try {
|
||||||
const ip4 = await this.publicIp.v4()
|
const ip4 = await this.publicIp()
|
||||||
// const ip6 = await publicIp.v6()
|
// const ip6 = await publicIp.v6()
|
||||||
|
|
||||||
circuitRelayInfo.ip4 = ip4
|
circuitRelayInfo.ip4 = ip4
|
||||||
@@ -63,24 +71,29 @@ class IpfsCoordAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nullLog = () => {}
|
||||||
|
|
||||||
const ipfsCoordOptions = {
|
const ipfsCoordOptions = {
|
||||||
ipfs: this.ipfs,
|
ipfs: this.ipfs,
|
||||||
type: 'node.js',
|
type: 'node.js',
|
||||||
// type: 'browser',
|
// type: 'browser',
|
||||||
bchjs: this.bchjs,
|
wallet: this.wallet,
|
||||||
privateLog: console.log, // Default to console.log
|
// privateLog: console.log, // Default to console.log
|
||||||
|
privateLog: nullLog,
|
||||||
isCircuitRelay: this.config.isCircuitRelay,
|
isCircuitRelay: this.config.isCircuitRelay,
|
||||||
circuitRelayInfo,
|
circuitRelayInfo,
|
||||||
apiInfo: this.config.apiInfo,
|
apiInfo: this.config.apiInfo,
|
||||||
announceJsonLd: this.config.announceJsonLd,
|
announceJsonLd: this.config.announceJsonLd,
|
||||||
mnemonic: this.config.mnemonic,
|
mnemonic: this.config.mnemonic,
|
||||||
debugLevel: this.config.debugLevel
|
debugLevel: this.config.debugLevel,
|
||||||
|
v1Relays: this.config.v1Relays,
|
||||||
|
tcpPort: this.config.ipfsTcpPort
|
||||||
}
|
}
|
||||||
|
|
||||||
// Production env uses external go-ipfs node.
|
// Production env uses external go-ipfs node.
|
||||||
if (this.config.isProduction) {
|
// if (this.config.isProduction) {
|
||||||
ipfsCoordOptions.nodeType = 'external'
|
// ipfsCoordOptions.nodeType = 'external'
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.ipfsCoord = new this.IpfsCoord(ipfsCoordOptions)
|
this.ipfsCoord = new this.IpfsCoord(ipfsCoordOptions)
|
||||||
|
|
||||||
@@ -107,12 +120,15 @@ class IpfsCoordAdapter {
|
|||||||
|
|
||||||
// Subscribe to the chat pubsub channel
|
// Subscribe to the chat pubsub channel
|
||||||
async subscribeToChat () {
|
async subscribeToChat () {
|
||||||
|
// TODO: Allow user to replace nullog with their own log handler at startup.
|
||||||
|
const nullLog = () => {}
|
||||||
|
|
||||||
await this.ipfsCoord.adapters.pubsub.subscribeToPubsubChannel(
|
await this.ipfsCoord.adapters.pubsub.subscribeToPubsubChannel(
|
||||||
this.config.chatPubSubChan,
|
this.config.chatPubSubChan,
|
||||||
console.log,
|
nullLog,
|
||||||
this.ipfsCoord.thisNode
|
this.ipfsCoord.thisNode
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = IpfsCoordAdapter
|
export default IpfsCoordAdapter
|
||||||
|
|||||||
+235
-82
@@ -9,94 +9,95 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Global npm libraries
|
// Global npm libraries
|
||||||
// const IPFS = require('ipfs')
|
import { createHelia } from 'helia'
|
||||||
// const IPFS = require('@chris.troutner/ipfs')
|
import fs from 'fs'
|
||||||
const IPFSembedded = require('ipfs')
|
import { FsBlockstore } from 'blockstore-fs'
|
||||||
const IPFSexternal = require('ipfs-http-client')
|
import { FsDatastore } from 'datastore-fs'
|
||||||
const fs = require('fs')
|
import { createLibp2p } from 'libp2p'
|
||||||
const http = require('http')
|
import { tcp } from '@libp2p/tcp'
|
||||||
|
import { noise } from '@chainsafe/libp2p-noise'
|
||||||
|
import { yamux } from '@chainsafe/libp2p-yamux'
|
||||||
|
// import { bootstrap } from '@libp2p/bootstrap'
|
||||||
|
// import { identifyService } from 'libp2p/identify'
|
||||||
|
import { identify } from '@libp2p/identify'
|
||||||
|
// import { circuitRelayServer, circuitRelayTransport } from 'libp2p/circuit-relay'
|
||||||
|
import { circuitRelayServer, circuitRelayTransport } from '@libp2p/circuit-relay-v2'
|
||||||
|
import { gossipsub } from '@chainsafe/libp2p-gossipsub'
|
||||||
|
import { webSockets } from '@libp2p/websockets'
|
||||||
|
import { publicIpv4 } from 'public-ip'
|
||||||
|
import { multiaddr } from '@multiformats/multiaddr'
|
||||||
|
import { webRTC } from '@libp2p/webrtc'
|
||||||
|
import { keychain } from '@libp2p/keychain'
|
||||||
|
import { defaultLogger } from '@libp2p/logger'
|
||||||
|
import { unixfs } from '@helia/unixfs'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const config = require('../../../config')
|
import config from '../../../config/index.js'
|
||||||
|
import JsonFiles from '../json-files.js'
|
||||||
|
|
||||||
const IPFS_DIR = './.ipfsdata/ipfs'
|
// Hack to get __dirname back.
|
||||||
|
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
|
||||||
|
import * as url from 'url'
|
||||||
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||||
|
// console.log('__dirname: ', __dirname)
|
||||||
|
|
||||||
|
const ROOT_DIR = `${__dirname}../../../`
|
||||||
|
const IPFS_DIR = `${__dirname}../../../.ipfsdata/ipfs`
|
||||||
|
|
||||||
class IpfsAdapter {
|
class IpfsAdapter {
|
||||||
constructor (localConfig) {
|
constructor (localConfig) {
|
||||||
// Encapsulate dependencies
|
// Encapsulate dependencies
|
||||||
this.config = config
|
this.config = config
|
||||||
|
this.fs = fs
|
||||||
// Choose the IPFS constructor based on the config settings.
|
this.createLibp2p = createLibp2p
|
||||||
this.IPFS = IPFSembedded // default
|
this.publicIp = publicIpv4
|
||||||
if (this.config.isProduction) {
|
this.multiaddr = multiaddr
|
||||||
this.IPFS = IPFSexternal
|
this.jsonFiles = new JsonFiles()
|
||||||
}
|
this.keychain = keychain
|
||||||
|
this.createHelia = createHelia
|
||||||
|
|
||||||
// Properties of this class instance.
|
// Properties of this class instance.
|
||||||
this.isReady = false
|
this.isReady = false
|
||||||
|
|
||||||
this.fs = fs
|
// Bind 'this' object to all subfunctions
|
||||||
|
this.start = this.start.bind(this)
|
||||||
|
this.createNode = this.createNode.bind(this)
|
||||||
|
this.stop = this.stop.bind(this)
|
||||||
|
this.ensureBlocksDir = this.ensureBlocksDir.bind(this)
|
||||||
|
this.getSeed = this.getSeed.bind(this)
|
||||||
|
this.getKeychain = this.getKeychain.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start an IPFS node.
|
// Start an IPFS node.
|
||||||
async start () {
|
async start () {
|
||||||
try {
|
try {
|
||||||
// Ipfs Options
|
// Ensure the directory structure exists that is needed by the IPFS node to store data.
|
||||||
const ipfsOptionsEmbedded = {
|
this.ensureBlocksDir()
|
||||||
repo: IPFS_DIR,
|
|
||||||
start: true,
|
|
||||||
config: {
|
|
||||||
relay: {
|
|
||||||
enabled: true, // enable circuit relay dialer and listener
|
|
||||||
hop: {
|
|
||||||
enabled: config.isCircuitRelay // enable circuit relay HOP (make this node a relay)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
pubsub: true, // enable pubsub
|
|
||||||
Swarm: {
|
|
||||||
ConnMgr: {
|
|
||||||
HighWater: 30,
|
|
||||||
LowWater: 10
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addresses: {
|
|
||||||
Swarm: [
|
|
||||||
`/ip4/0.0.0.0/tcp/${this.config.ipfsTcpPort}`,
|
|
||||||
`/ip4/0.0.0.0/tcp/${this.config.ipfsWsPort}/ws`
|
|
||||||
]
|
|
||||||
},
|
|
||||||
Datastore: {
|
|
||||||
StorageMax: '2GB',
|
|
||||||
StorageGCWatermark: 50,
|
|
||||||
GCPeriod: '15m'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ipfsOptionsExternal = {
|
// Create an IPFS node
|
||||||
host: this.config.ipfsHost,
|
const ipfs = await this.createNode()
|
||||||
port: this.config.ipfsApiPort,
|
// console.log('ipfs: ', ipfs)
|
||||||
agent: http.Agent({ keepAlive: true, maxSockets: 2000 })
|
|
||||||
}
|
|
||||||
|
|
||||||
let ipfsOptions = ipfsOptionsEmbedded
|
this.id = ipfs.libp2p.peerId.toString()
|
||||||
if (this.config.isProduction) {
|
console.log('IPFS ID: ', this.id)
|
||||||
ipfsOptions = ipfsOptionsExternal
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new IPFS node.
|
// Attempt to guess our ip4 IP address.
|
||||||
this.ipfs = await this.IPFS.create(ipfsOptions)
|
const ip4 = await this.publicIp()
|
||||||
|
let detectedMultiaddr = `/ip4/${ip4}/tcp/${this.config.ipfsTcpPort}/p2p/${this.id}`
|
||||||
|
detectedMultiaddr = this.multiaddr(detectedMultiaddr)
|
||||||
|
|
||||||
// Set the 'server' profile so the node does not scan private networks.
|
// Get the multiaddrs for the node.
|
||||||
await this.ipfs.config.profiles.apply('server')
|
const multiaddrs = ipfs.libp2p.getMultiaddrs()
|
||||||
|
multiaddrs.push(detectedMultiaddr)
|
||||||
|
console.log('Multiaddrs: ', multiaddrs)
|
||||||
|
|
||||||
// Debugging: Display IPFS config settings.
|
this.multiaddrs = multiaddrs
|
||||||
// const configSettings = await this.ipfs.config.getAll()
|
|
||||||
// console.log(`configSettings: ${JSON.stringify(configSettings, null, 2)}`)
|
|
||||||
|
|
||||||
// Signal that this adapter is ready.
|
// Signal that this adapter is ready.
|
||||||
this.isReady = true
|
this.isReady = true
|
||||||
|
|
||||||
|
this.ipfs = ipfs
|
||||||
|
|
||||||
return this.ipfs
|
return this.ipfs
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error in ipfs.js/start()')
|
console.error('Error in ipfs.js/start()')
|
||||||
@@ -110,31 +111,183 @@ class IpfsAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getKeychain (datastore) {
|
||||||
|
const keychainInit = {
|
||||||
|
pass: await this.getSeed()
|
||||||
|
}
|
||||||
|
|
||||||
|
const chain = this.keychain(keychainInit)({
|
||||||
|
datastore,
|
||||||
|
logger: defaultLogger()
|
||||||
|
})
|
||||||
|
|
||||||
|
return chain
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function creates an IPFS node using Helia.
|
||||||
|
// It returns the node as an object.
|
||||||
|
async createNode () {
|
||||||
|
try {
|
||||||
|
// Create block and data stores.
|
||||||
|
const blockstore = new FsBlockstore(`${IPFS_DIR}/blockstore`)
|
||||||
|
const datastore = new FsDatastore(`${IPFS_DIR}/datastore`)
|
||||||
|
|
||||||
|
// const keychainInit = {
|
||||||
|
// pass: await this.getSeed()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Create an identity
|
||||||
|
let peerId
|
||||||
|
// console.log('this.keychain: ', this.keychain)
|
||||||
|
// const chain = this.keychain(keychainInit)({
|
||||||
|
// datastore,
|
||||||
|
// logger: defaultLogger()
|
||||||
|
// })
|
||||||
|
const chain = await this.getKeychain(datastore)
|
||||||
|
try {
|
||||||
|
peerId = await chain.exportPeerId('myKey')
|
||||||
|
} catch (err) {
|
||||||
|
await chain.createKey('myKey', 'Ed25519', 4096)
|
||||||
|
peerId = await chain.exportPeerId('myKey')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure services
|
||||||
|
const services = {
|
||||||
|
identify: identify(),
|
||||||
|
pubsub: gossipsub({ allowPublishToZeroPeers: true })
|
||||||
|
}
|
||||||
|
if (this.config.isCircuitRelay) {
|
||||||
|
console.log('Helia (IPFS) node IS configured as Circuit Relay')
|
||||||
|
services.relay = circuitRelayServer({ // makes the node function as a relay server
|
||||||
|
hopTimeout: 30 * 1000, // incoming relay requests must be resolved within this time limit
|
||||||
|
advertise: true,
|
||||||
|
reservations: {
|
||||||
|
maxReservations: 15, // how many peers are allowed to reserve relay slots on this server
|
||||||
|
reservationClearInterval: 300 * 1000, // how often to reclaim stale reservations
|
||||||
|
applyDefaultLimit: true, // whether to apply default data/duration limits to each relayed connection
|
||||||
|
defaultDurationLimit: 2 * 60 * 1000, // the default maximum amount of time a relayed connection can be open for
|
||||||
|
defaultDataLimit: BigInt(2 << 7), // the default maximum number of bytes that can be transferred over a relayed connection
|
||||||
|
maxInboundHopStreams: 32, // how many inbound HOP streams are allow simultaneously
|
||||||
|
maxOutboundHopStreams: 64 // how many outbound HOP streams are allow simultaneously
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('Helia (IPFS) node IS NOT configured as Circuit Relay')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure transports
|
||||||
|
let transports
|
||||||
|
if (process.env.CONNECT_PREF === 'direct') {
|
||||||
|
transports = [
|
||||||
|
tcp(),
|
||||||
|
webSockets(),
|
||||||
|
webRTC()
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
transports = [
|
||||||
|
tcp(),
|
||||||
|
webSockets(),
|
||||||
|
circuitRelayTransport({
|
||||||
|
discoverRelays: 3,
|
||||||
|
reservationConcurrency: 3
|
||||||
|
}),
|
||||||
|
webRTC()
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// libp2p is the networking layer that underpins Helia
|
||||||
|
const libp2p = await this.createLibp2p({
|
||||||
|
peerId,
|
||||||
|
datastore,
|
||||||
|
addresses: {
|
||||||
|
listen: [
|
||||||
|
'/ip4/127.0.0.1/tcp/0',
|
||||||
|
`/ip4/0.0.0.0/tcp/${this.config.ipfsTcpPort}`,
|
||||||
|
`/ip4/0.0.0.0/tcp/${this.config.ipfsWsPort}/ws`,
|
||||||
|
'/webrtc'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
transports,
|
||||||
|
connectionEncryption: [
|
||||||
|
noise()
|
||||||
|
],
|
||||||
|
streamMuxers: [
|
||||||
|
yamux()
|
||||||
|
],
|
||||||
|
services
|
||||||
|
})
|
||||||
|
|
||||||
|
// create a Helia node
|
||||||
|
const helia = await this.createHelia({
|
||||||
|
blockstore,
|
||||||
|
datastore,
|
||||||
|
libp2p
|
||||||
|
})
|
||||||
|
|
||||||
|
// Attach IPFS file system.
|
||||||
|
const fs = unixfs(helia)
|
||||||
|
helia.fs = fs
|
||||||
|
|
||||||
|
return helia
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error creating Helia node: ', err)
|
||||||
|
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async stop () {
|
async stop () {
|
||||||
await this.ipfs.stop()
|
await this.ipfs.stop()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the '/blocks' directory that is used to store IPFS data.
|
// Ensure that the directories exist to store blocks from the IPFS network.
|
||||||
// Dev Note: It's assumed this node is not pinning any data and that
|
// This function is called at startup, before the IPFS node is started.
|
||||||
// everything in this directory is transient. This folder will regularly
|
ensureBlocksDir () {
|
||||||
// fill up and prevent IPFS from starting.
|
try {
|
||||||
// rmBlocksDir () {
|
!this.fs.existsSync(`${ROOT_DIR}.ipfsdata`) && this.fs.mkdirSync(`${ROOT_DIR}.ipfsdata`)
|
||||||
// try {
|
|
||||||
// const dir = `${IPFS_DIR}/blocks`
|
!this.fs.existsSync(`${IPFS_DIR}`) && this.fs.mkdirSync(`${IPFS_DIR}`)
|
||||||
// console.log(`Deleting ${dir} directory...`)
|
|
||||||
//
|
!this.fs.existsSync(`${IPFS_DIR}/blockstore`) && this.fs.mkdirSync(`${IPFS_DIR}/blockstore`)
|
||||||
// this.fs.rmdirSync(dir, { recursive: true })
|
|
||||||
//
|
!this.fs.existsSync(`${IPFS_DIR}/datastore`) && this.fs.mkdirSync(`${IPFS_DIR}/datastore`)
|
||||||
// console.log(`${dir} directory is deleted!`)
|
|
||||||
//
|
return true
|
||||||
// return true // Signal successful execution.
|
} catch (err) {
|
||||||
// } catch (err) {
|
console.error('Error in adapters/ipfs.js/ensureBlocksDir(): ', err)
|
||||||
// console.log('Error in rmBlocksDir()')
|
throw err
|
||||||
// throw err
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
// This function opens the seed used to generate the key for this IPFS peer.
|
||||||
|
// The seed is stored in a JSON file. If it doesn't exist, a new one is created.
|
||||||
|
async getSeed () {
|
||||||
|
try {
|
||||||
|
let seed
|
||||||
|
|
||||||
|
const filename = `${IPFS_DIR}/seed.json`
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try to read the JSON file containing the seed.
|
||||||
|
seed = await this.jsonFiles.readJSON(filename)
|
||||||
|
} catch (err) {
|
||||||
|
const seedNum = Math.floor(Math.random() * 1000000000000000000000)
|
||||||
|
seed = seedNum.toString()
|
||||||
|
|
||||||
|
// Save the newly generated seed
|
||||||
|
await this.jsonFiles.writeJSON(seed, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log('getSeed() seed: ', seed)
|
||||||
|
|
||||||
|
return seed
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in adapters/ipfs/ipfs.js/getSeed()')
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = IpfsAdapter
|
export default IpfsAdapter
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
A utility file for reading and writing JSON files.
|
A utility file for reading and writing JSON files.
|
||||||
*/
|
*/
|
||||||
'use strict'
|
|
||||||
const fs = require('fs')
|
import fs from 'fs'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
@@ -57,7 +57,8 @@ class JsonFiles {
|
|||||||
console.log(`err: ${JSON.stringify(err, null, 2)}`)
|
console.log(`err: ${JSON.stringify(err, null, 2)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw err
|
// throw err
|
||||||
|
return reject(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
const obj = JSON.parse(data)
|
const obj = JSON.parse(data)
|
||||||
@@ -72,4 +73,4 @@ class JsonFiles {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = JsonFiles
|
export default JsonFiles
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Load Mongoose models.
|
// Load Mongoose models.
|
||||||
const Users = require('./models/users')
|
import Users from './models/users.js'
|
||||||
|
|
||||||
class LocalDB {
|
class LocalDB {
|
||||||
constructor () {
|
constructor () {
|
||||||
@@ -12,4 +12,4 @@ class LocalDB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = LocalDB
|
export default LocalDB
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
const mongoose = require('mongoose')
|
// Global npm libraries
|
||||||
const bcrypt = require('bcryptjs')
|
import mongoose from 'mongoose'
|
||||||
const config = require('../../../../config')
|
import bcrypt from 'bcryptjs'
|
||||||
const jwt = require('jsonwebtoken')
|
import jwt from 'jsonwebtoken'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import config from '../../../../config/index.js'
|
||||||
|
|
||||||
const User = new mongoose.Schema({
|
const User = new mongoose.Schema({
|
||||||
type: { type: String, default: 'user' },
|
type: { type: String, default: 'user' },
|
||||||
@@ -51,4 +54,4 @@ User.methods.generateToken = function generateToken () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// export default mongoose.model('user', User)
|
// export default mongoose.model('user', User)
|
||||||
module.exports = mongoose.model('user', User)
|
export default mongoose.model('user', User)
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
const lineReader = require('line-reader')
|
import lineReader from 'line-reader'
|
||||||
const fs = require('fs')
|
import fs from 'fs'
|
||||||
|
|
||||||
const config = require('../../config')
|
import config from '../../config/index.js'
|
||||||
|
|
||||||
|
// Hack to get __dirname back.
|
||||||
|
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
|
||||||
|
import * as url from 'url'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||||
|
|
||||||
class LogsApi {
|
class LogsApi {
|
||||||
constructor () {
|
constructor () {
|
||||||
@@ -169,4 +174,4 @@ class LogsApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = LogsApi
|
export default LogsApi
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
const nodemailer = require('nodemailer')
|
import nodemailer from 'nodemailer'
|
||||||
|
|
||||||
const config = require('../../config')
|
import config from '../../config/index.js'
|
||||||
|
import wlogger from './wlogger.js'
|
||||||
const { wlogger } = require('./wlogger')
|
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
@@ -150,4 +149,4 @@ class NodeMailer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = NodeMailer
|
export default NodeMailer
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
koa-passport is an authorization library used for different authentication schemes.
|
koa-passport is an authorization library used for different authentication schemes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const passport = require('koa-passport')
|
import passport from 'koa-passport'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
class Passport {
|
class Passport {
|
||||||
@@ -32,4 +32,4 @@ class Passport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Passport
|
export default Passport
|
||||||
|
|||||||
+12
-4
@@ -6,10 +6,17 @@
|
|||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const winston = require('winston')
|
// Global npm libraries
|
||||||
require('winston-daily-rotate-file')
|
import winston from 'winston'
|
||||||
|
import 'winston-daily-rotate-file'
|
||||||
|
|
||||||
const config = require('../../config')
|
// Local libraries
|
||||||
|
import config from '../../config/index.js'
|
||||||
|
|
||||||
|
// Hack to get __dirname back.
|
||||||
|
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
|
||||||
|
import * as url from 'url'
|
||||||
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||||
|
|
||||||
class Wlogger {
|
class Wlogger {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -69,4 +76,5 @@ logger.outputToConsole()
|
|||||||
|
|
||||||
const wlogger = logger.wlogger
|
const wlogger = logger.wlogger
|
||||||
|
|
||||||
module.exports = { wlogger, Wlogger }
|
export { wlogger as default, Wlogger }
|
||||||
|
// export default wlogger
|
||||||
|
|||||||
+17
-16
@@ -6,23 +6,21 @@
|
|||||||
|
|
||||||
// Public npm libraries.
|
// Public npm libraries.
|
||||||
|
|
||||||
// Load the Clean Architecture Adapters library
|
// Local libraries
|
||||||
const Adapters = require('../adapters')
|
import Adapters from '../adapters/index.js'
|
||||||
|
import JSONRPC from './json-rpc/index.js'
|
||||||
// Load the JSON RPC Controller.
|
import UseCases from '../use-cases/index.js'
|
||||||
const JSONRPC = require('./json-rpc')
|
import RESTControllers from './rest-api/index.js'
|
||||||
|
import TimerControllers from './timer-controllers.js'
|
||||||
// Load the Clean Architecture Use Case libraries.
|
import config from '../../config/index.js'
|
||||||
const UseCases = require('../use-cases')
|
|
||||||
// const useCases = new UseCases({ adapters })
|
|
||||||
|
|
||||||
// Load the REST API Controllers.
|
|
||||||
const RESTControllers = require('./rest-api')
|
|
||||||
|
|
||||||
class Controllers {
|
class Controllers {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
|
// Encapsulate dependencies
|
||||||
this.adapters = new Adapters()
|
this.adapters = new Adapters()
|
||||||
this.useCases = new UseCases({ adapters: this.adapters })
|
this.useCases = new UseCases({ adapters: this.adapters })
|
||||||
|
this.timerControllers = new TimerControllers({ adapters: this.adapters, useCases: this.useCases })
|
||||||
|
this.config = config
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spin up any adapter libraries that have async startup needs.
|
// Spin up any adapter libraries that have async startup needs.
|
||||||
@@ -52,12 +50,15 @@ class Controllers {
|
|||||||
// Wait for any startup processes to complete for the Adapters libraries.
|
// Wait for any startup processes to complete for the Adapters libraries.
|
||||||
// await this.adapters.start()
|
// await this.adapters.start()
|
||||||
|
|
||||||
// Attach the REST controllers to the Koa app.
|
if (this.config.useIpfs) {
|
||||||
// this.attachRESTControllers(app)
|
// Attach JSON RPC controllers
|
||||||
|
|
||||||
this.attachRPCControllers()
|
this.attachRPCControllers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attach and start the timer controllers
|
||||||
|
this.timerControllers.startTimers()
|
||||||
|
}
|
||||||
|
|
||||||
// Add the JSON RPC router to the ipfs-coord adapter.
|
// Add the JSON RPC router to the ipfs-coord adapter.
|
||||||
attachRPCControllers () {
|
attachRPCControllers () {
|
||||||
const jsonRpcController = new JSONRPC({
|
const jsonRpcController = new JSONRPC({
|
||||||
@@ -72,4 +73,4 @@ class Controllers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Controllers
|
export default Controllers
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const jsonrpc = require('jsonrpc-lite')
|
import jsonrpc from 'jsonrpc-lite'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const config = require('../../../../config')
|
import config from '../../../../config/index.js'
|
||||||
|
|
||||||
class AboutRPC {
|
class AboutRPC {
|
||||||
constructor (localConfig) {
|
constructor (localConfig) {
|
||||||
@@ -48,4 +48,4 @@ class AboutRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = AboutRPC
|
export default AboutRPC
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const jsonrpc = require('jsonrpc-lite')
|
import jsonrpc from 'jsonrpc-lite'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
// const AuthLib = require('../../lib/auth')
|
// const AuthLib = require('../../lib/auth')
|
||||||
// const UserLib = require('../../../use-cases/user')
|
// const UserLib = require('../../../use-cases/user')
|
||||||
const { wlogger } = require('../../../adapters/wlogger')
|
import wlogger from '../../../adapters/wlogger.js'
|
||||||
const RateLimit = require('../rate-limit')
|
|
||||||
|
import RateLimit from '../rate-limit.js'
|
||||||
|
|
||||||
class AuthRPC {
|
class AuthRPC {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -173,4 +174,4 @@ class AuthRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = AuthRPC
|
export default AuthRPC
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const jsonrpc = require('jsonrpc-lite')
|
import jsonrpc from 'jsonrpc-lite'
|
||||||
|
|
||||||
// Local support libraries
|
// Local support libraries
|
||||||
const { wlogger } = require('../../adapters/wlogger')
|
import wlogger from '../../adapters/wlogger.js'
|
||||||
const UserController = require('./users')
|
import UserController from './users/index.js'
|
||||||
const AuthController = require('./auth')
|
import AuthController from './auth/index.js'
|
||||||
const AboutController = require('./about')
|
import AboutController from './about/index.js'
|
||||||
const BCHController = require('./bch')
|
import BCHController from './bch/index.js'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
@@ -202,4 +202,4 @@ class JSONRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = JSONRPC
|
export default JSONRPC
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
/* eslint no-useless-catch: 0 */
|
/* eslint no-useless-catch: 0 */
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const RateLimitLib = require('koa2-ratelimit').RateLimit
|
import { RateLimit as RateLimitLib } from 'koa2-ratelimit'
|
||||||
|
|
||||||
class RateLimit {
|
class RateLimit {
|
||||||
constructor (options) {
|
constructor (options) {
|
||||||
@@ -80,4 +80,4 @@ class RateLimit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RateLimit
|
export default RateLimit
|
||||||
|
|||||||
@@ -3,12 +3,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const jsonrpc = require('jsonrpc-lite')
|
import jsonrpc from 'jsonrpc-lite'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
// const UserLib = require('../../../use-cases/user')
|
// const UserLib = require('../../../use-cases/user')
|
||||||
const Validators = require('../validators')
|
import Validators from '../validators.js'
|
||||||
const RateLimit = require('../rate-limit')
|
|
||||||
|
import RateLimit from '../rate-limit.js'
|
||||||
|
|
||||||
class UserRPC {
|
class UserRPC {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -533,4 +534,4 @@ class UserRPC {
|
|||||||
// TODO create deleteUser()
|
// TODO create deleteUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UserRPC
|
export default UserRPC
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
/* eslint no-useless-catch: 0 */
|
/* eslint no-useless-catch: 0 */
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const jwt = require('jsonwebtoken')
|
import jwt from 'jsonwebtoken'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const config = require('../../../config')
|
import config from '../../../config/index.js'
|
||||||
|
|
||||||
// const UserModel = require('../../adapters/localdb/models/users')
|
// const UserModel = require('../../adapters/localdb/models/users')
|
||||||
|
|
||||||
class Validators {
|
class Validators {
|
||||||
@@ -93,4 +94,4 @@ class Validators {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Validators
|
export default Validators
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const Passport = require('../../../adapters/passport')
|
import Passport from '../../../adapters/passport.js'
|
||||||
const passport = new Passport()
|
const passport = new Passport()
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
@@ -96,4 +96,4 @@ class AuthRESTController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = AuthRESTController
|
export default AuthRESTController
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries.
|
// Public npm libraries.
|
||||||
const Router = require('koa-router')
|
import Router from 'koa-router'
|
||||||
|
|
||||||
// Local libraries.
|
// Local libraries.
|
||||||
const AuthRESTController = require('./controller')
|
import AuthRESTController from './controller.js'
|
||||||
|
|
||||||
class AuthRouter {
|
class AuthRouter {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -48,4 +48,4 @@ class AuthRouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = AuthRouter
|
export default AuthRouter
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable no-useless-escape */
|
/* eslint-disable no-useless-escape */
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
import ContactLib from '../../../adapters/contact.js'
|
||||||
|
|
||||||
const ContactLib = require('../../../adapters/contact')
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||||
const contactLib = new ContactLib()
|
const contactLib = new ContactLib()
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
@@ -74,4 +74,4 @@ class ContactController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = ContactController
|
export default ContactController
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries.
|
// Public npm libraries.
|
||||||
const Router = require('koa-router')
|
import Router from 'koa-router'
|
||||||
|
|
||||||
// Local libraries.
|
// Local libraries.
|
||||||
const ContactRESTControllerLib = require('./controller')
|
import ContactRESTControllerLib from './controller.js'
|
||||||
|
|
||||||
class ContactRouter {
|
class ContactRouter {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -53,4 +53,4 @@ class ContactRouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ContactRouter
|
export default ContactRouter
|
||||||
|
|||||||
@@ -6,12 +6,13 @@
|
|||||||
|
|
||||||
// Public npm libraries.
|
// Public npm libraries.
|
||||||
|
|
||||||
// Load the REST API Controllers.
|
// Local libraries
|
||||||
const AuthRESTController = require('./auth')
|
import AuthRESTController from './auth/index.js'
|
||||||
const UserRouter = require('./users')
|
import UserRouter from './users/index.js'
|
||||||
const ContactRESTController = require('./contact')
|
import ContactRESTController from './contact/index.js'
|
||||||
const LogsRESTController = require('./logs')
|
import LogsRESTController from './logs/index.js'
|
||||||
const BCHRESTController = require('./bch')
|
import IpfsRESTController from './ipfs/index.js'
|
||||||
|
import BCHRESTController from './bch/index.js'
|
||||||
|
|
||||||
class RESTControllers {
|
class RESTControllers {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -54,10 +55,14 @@ class RESTControllers {
|
|||||||
const logsRESTController = new LogsRESTController(dependencies)
|
const logsRESTController = new LogsRESTController(dependencies)
|
||||||
logsRESTController.attach(app)
|
logsRESTController.attach(app)
|
||||||
|
|
||||||
|
// Attach the REST API Controllers associated with the /ipfs route
|
||||||
|
const ipfsRESTController = new IpfsRESTController(dependencies)
|
||||||
|
ipfsRESTController.attach(app)
|
||||||
|
|
||||||
// Attach the REST API Controllers associated with the /fulcrum route
|
// Attach the REST API Controllers associated with the /fulcrum route
|
||||||
const bchRESTController = new BCHRESTController(dependencies)
|
const bchRESTController = new BCHRESTController(dependencies)
|
||||||
bchRESTController.attach(app)
|
bchRESTController.attach(app)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RESTControllers
|
export default RESTControllers
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
REST API Controller library for the /ipfs route
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Global npm libraries
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import wlogger from '../../../adapters/wlogger.js'
|
||||||
|
|
||||||
|
class IpfsRESTControllerLib {
|
||||||
|
constructor (localConfig = {}) {
|
||||||
|
// Dependency Injection.
|
||||||
|
this.adapters = localConfig.adapters
|
||||||
|
if (!this.adapters) {
|
||||||
|
throw new Error(
|
||||||
|
'Instance of Adapters library required when instantiating /ipfs REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
this.useCases = localConfig.useCases
|
||||||
|
if (!this.useCases) {
|
||||||
|
throw new Error(
|
||||||
|
'Instance of Use Cases library required when instantiating /ipfs REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encapsulate dependencies
|
||||||
|
// this.UserModel = this.adapters.localdb.Users
|
||||||
|
// this.userUseCases = this.useCases.user
|
||||||
|
|
||||||
|
// Bind 'this' object to all subfunctions
|
||||||
|
this.getStatus = this.getStatus.bind(this)
|
||||||
|
this.getPeers = this.getPeers.bind(this)
|
||||||
|
this.getRelays = this.getRelays.bind(this)
|
||||||
|
this.handleError = this.handleError.bind(this)
|
||||||
|
this.connect = this.connect.bind(this)
|
||||||
|
this.getThisNode = this.getThisNode.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {get} /ipfs Get status on IPFS infrastructure
|
||||||
|
* @apiPermission public
|
||||||
|
* @apiName GetIpfsStatus
|
||||||
|
* @apiGroup REST BCH
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
* curl -H "Content-Type: application/json" -X GET localhost:5001/ipfs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getStatus (ctx) {
|
||||||
|
try {
|
||||||
|
const status = await this.adapters.ipfs.getStatus()
|
||||||
|
|
||||||
|
ctx.body = { status }
|
||||||
|
} catch (err) {
|
||||||
|
wlogger.error('Error in ipfs/controller.js/getStatus(): ')
|
||||||
|
// ctx.throw(422, err.message)
|
||||||
|
this.handleError(ctx, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return information on IPFS peers this node is connected to.
|
||||||
|
async getPeers (ctx) {
|
||||||
|
try {
|
||||||
|
const showAll = ctx.request.body.showAll
|
||||||
|
|
||||||
|
const peers = await this.adapters.ipfs.getPeers(showAll)
|
||||||
|
|
||||||
|
ctx.body = { peers }
|
||||||
|
} catch (err) {
|
||||||
|
wlogger.error('Error in ipfs/controller.js/getPeers(): ')
|
||||||
|
// ctx.throw(422, err.message)
|
||||||
|
this.handleError(ctx, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get data about the known Circuit Relays. Hydrate with data from peers list.
|
||||||
|
async getRelays (ctx) {
|
||||||
|
try {
|
||||||
|
const relays = await this.adapters.ipfs.getRelays()
|
||||||
|
|
||||||
|
ctx.body = { relays }
|
||||||
|
} catch (err) {
|
||||||
|
wlogger.error('Error in ipfs/controller.js/getRelays(): ')
|
||||||
|
// ctx.throw(422, err.message)
|
||||||
|
this.handleError(ctx, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect (ctx) {
|
||||||
|
try {
|
||||||
|
const multiaddr = ctx.request.body.multiaddr
|
||||||
|
const getDetails = ctx.request.body.getDetails
|
||||||
|
|
||||||
|
// console.log('this.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs: ', this.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs)
|
||||||
|
const result = await this.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs.connectToPeer({ multiaddr, getDetails })
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
ctx.body = result
|
||||||
|
} catch (err) {
|
||||||
|
wlogger.error('Error in ipfs/controller.js/connect():', err)
|
||||||
|
// ctx.throw(422, err.message)
|
||||||
|
this.handleError(ctx, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {get} /ipfs/node Get a copy of the thisNode object from helia-coord
|
||||||
|
* @apiPermission public
|
||||||
|
* @apiName GetThisNode
|
||||||
|
* @apiGroup REST BCH
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
* curl -H "Content-Type: application/json" -X GET localhost:5001/ipfs/node
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getThisNode (ctx) {
|
||||||
|
try {
|
||||||
|
const thisNode = this.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.thisNode
|
||||||
|
|
||||||
|
ctx.body = { thisNode }
|
||||||
|
} catch (err) {
|
||||||
|
wlogger.error('Error in ipfs/controller.js/getThisNode(): ')
|
||||||
|
// ctx.throw(422, err.message)
|
||||||
|
this.handleError(ctx, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DRY error handler
|
||||||
|
handleError (ctx, err) {
|
||||||
|
// If an HTTP status is specified by the buisiness logic, use that.
|
||||||
|
if (err.status) {
|
||||||
|
if (err.message) {
|
||||||
|
ctx.throw(err.status, err.message)
|
||||||
|
} else {
|
||||||
|
ctx.throw(err.status)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// By default use a 422 error if the HTTP status is not specified.
|
||||||
|
ctx.throw(422, err.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// module.exports = IpfsRESTControllerLib
|
||||||
|
export default IpfsRESTControllerLib
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
REST API library for the /ipfs route.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries.
|
||||||
|
import Router from 'koa-router'
|
||||||
|
|
||||||
|
// Local libraries.
|
||||||
|
import IPFSRESTControllerLib from './controller.js'
|
||||||
|
import Validators from '../middleware/validators.js'
|
||||||
|
|
||||||
|
// let _this
|
||||||
|
|
||||||
|
class IpfsRouter {
|
||||||
|
constructor (localConfig = {}) {
|
||||||
|
// Dependency Injection.
|
||||||
|
this.adapters = localConfig.adapters
|
||||||
|
if (!this.adapters) {
|
||||||
|
throw new Error(
|
||||||
|
'Instance of Adapters library required when instantiating IPFS REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
this.useCases = localConfig.useCases
|
||||||
|
if (!this.useCases) {
|
||||||
|
throw new Error(
|
||||||
|
'Instance of Use Cases library required when instantiating IPFS REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const dependencies = {
|
||||||
|
adapters: this.adapters,
|
||||||
|
useCases: this.useCases
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encapsulate dependencies.
|
||||||
|
this.ipfsRESTController = new IPFSRESTControllerLib(dependencies)
|
||||||
|
this.validators = new Validators()
|
||||||
|
|
||||||
|
// Instantiate the router and set the base route.
|
||||||
|
const baseUrl = '/ipfs'
|
||||||
|
this.router = new Router({ prefix: baseUrl })
|
||||||
|
|
||||||
|
// _this = this
|
||||||
|
}
|
||||||
|
|
||||||
|
attach (app) {
|
||||||
|
if (!app) {
|
||||||
|
throw new Error(
|
||||||
|
'Must pass app object when attaching REST API controllers.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the routes and attach the controller.
|
||||||
|
this.router.get('/', this.ipfsRESTController.getStatus)
|
||||||
|
this.router.post('/peers', this.ipfsRESTController.getPeers)
|
||||||
|
this.router.post('/relays', this.ipfsRESTController.getRelays)
|
||||||
|
this.router.post('/connect', this.ipfsRESTController.connect)
|
||||||
|
this.router.get('/node', this.ipfsRESTController.getThisNode)
|
||||||
|
|
||||||
|
// Attach the Controller routes to the Koa app.
|
||||||
|
app.use(this.router.routes())
|
||||||
|
app.use(this.router.allowedMethods())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// module.exports = BchRouter
|
||||||
|
export default IpfsRouter
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const LogsApiLib = require('../../../adapters/logapi')
|
import LogsApiLib from '../../../adapters/logapi.js'
|
||||||
const logsApiLib = new LogsApiLib()
|
const logsApiLib = new LogsApiLib()
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
@@ -62,4 +62,4 @@ class LogsApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = LogsApi
|
export default LogsApi
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries.
|
// Public npm libraries.
|
||||||
const Router = require('koa-router')
|
import Router from 'koa-router'
|
||||||
|
|
||||||
// Local libraries.
|
// Local libraries.
|
||||||
const LogsRESTControllerLib = require('./controller')
|
import LogsRESTControllerLib from './controller.js'
|
||||||
|
|
||||||
class LogsRouter {
|
class LogsRouter {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -52,4 +52,4 @@ class LogsRouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = LogsRouter
|
export default LogsRouter
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = function errorMiddleware () {
|
export default function errorMiddleware () {
|
||||||
return async (ctx, next) => {
|
return async (ctx, next) => {
|
||||||
try {
|
try {
|
||||||
await next()
|
await next()
|
||||||
@@ -8,4 +8,4 @@ module.exports = function errorMiddleware () {
|
|||||||
ctx.app.emit('error', err, ctx)
|
ctx.app.emit('error', err, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
REST API validator middleware.
|
REST API validator middleware.
|
||||||
|
|
||||||
|
These are a series of functions that ensure the user making a REST API
|
||||||
|
matches a user in the database (or not). In can do fine-grain user control
|
||||||
|
such as telling the difference between an admin, a normal user, and an
|
||||||
|
anonymous user.
|
||||||
|
|
||||||
|
This middleware is used to gatekeep access to different REST API resources.
|
||||||
|
|
||||||
|
CT 9/17/22:
|
||||||
|
This library was lightly refactored to make it work with the new unit tests.
|
||||||
|
This not and the commented code below can be deleted once it is verified that
|
||||||
|
this refactor did not result in any breaking changes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const User = require('../../../adapters/localdb/models/users')
|
import User from '../../../adapters/localdb/models/users.js'
|
||||||
const config = require('../../../../config')
|
|
||||||
const jwt = require('jsonwebtoken')
|
import config from '../../../../config/index.js'
|
||||||
const { wlogger } = require('../../../adapters/wlogger')
|
import jwt from 'jsonwebtoken'
|
||||||
|
import wlogger from '../../../adapters/wlogger.js'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
@@ -20,12 +33,10 @@ class Validators {
|
|||||||
|
|
||||||
async ensureUser (ctx, next) {
|
async ensureUser (ctx, next) {
|
||||||
try {
|
try {
|
||||||
// console.log(`getToken: ${typeof (getToken)}`)
|
|
||||||
const token = _this.getToken(ctx)
|
const token = _this.getToken(ctx)
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// console.log(`Err: Token not provided.`)
|
throw new Error('Token could not be retrieved from header')
|
||||||
ctx.throw(401)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let decoded = null
|
let decoded = null
|
||||||
@@ -34,20 +45,23 @@ class Validators {
|
|||||||
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
||||||
decoded = _this.jwt.verify(token, config.token)
|
decoded = _this.jwt.verify(token, config.token)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// console.log(`Err: Token could not be decoded: ${err}`)
|
throw new Error('Could not verify JWT')
|
||||||
ctx.throw(401)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
||||||
|
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
// console.log(`Err: Could not find user.`)
|
// console.log('Err: Could not find user.')
|
||||||
ctx.throw(401)
|
throw new Error('Could not find user')
|
||||||
}
|
}
|
||||||
|
|
||||||
// return next()
|
// return next()
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ctx.throw(401)
|
// console.log('Ensure user error: ', error)
|
||||||
|
// console.log('ctx: ', ctx)
|
||||||
|
ctx.status = 401
|
||||||
|
ctx.throw(401, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +74,8 @@ class Validators {
|
|||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// console.log(`Err: Token not provided.`)
|
// console.log(`Err: Token not provided.`)
|
||||||
ctx.throw(401)
|
// ctx.throw(401)
|
||||||
|
throw new Error('Token could not be retrieved from header')
|
||||||
}
|
}
|
||||||
|
|
||||||
let decoded = null
|
let decoded = null
|
||||||
@@ -70,22 +85,26 @@ class Validators {
|
|||||||
decoded = _this.jwt.verify(token, config.token)
|
decoded = _this.jwt.verify(token, config.token)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// console.log(`Err: Token could not be decoded: ${err}`)
|
// console.log(`Err: Token could not be decoded: ${err}`)
|
||||||
ctx.throw(401)
|
// ctx.throw(401)
|
||||||
|
throw new Error('Could not verify JWT')
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
// console.log(`Err: Could not find user.`)
|
// console.log(`Err: Could not find user.`)
|
||||||
ctx.throw(401)
|
// ctx.throw(401)
|
||||||
|
throw new Error('Could not find user')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.state.user.type !== 'admin') {
|
if (ctx.state.user.type !== 'admin') {
|
||||||
ctx.throw(401, 'not admin')
|
// ctx.throw(401, 'not admin')
|
||||||
|
throw new Error('User is not an admin')
|
||||||
}
|
}
|
||||||
|
|
||||||
// return next()
|
// return next()
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
ctx.status = 401
|
||||||
ctx.throw(401, error.message)
|
ctx.throw(401, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,7 +120,8 @@ class Validators {
|
|||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// console.log(`Err: Token not provided.`)
|
// console.log(`Err: Token not provided.`)
|
||||||
ctx.throw(401)
|
// ctx.throw(401)
|
||||||
|
throw new Error('Token could not be retrieved from header')
|
||||||
}
|
}
|
||||||
|
|
||||||
// The user ID targeted in this API call.
|
// The user ID targeted in this API call.
|
||||||
@@ -114,14 +134,16 @@ class Validators {
|
|||||||
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
||||||
decoded = _this.jwt.verify(token, config.token)
|
decoded = _this.jwt.verify(token, config.token)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// console.log(`Err: Token could not be decoded: ${err}`)
|
console.log(`Err: Token could not be decoded: ${err}`)
|
||||||
ctx.throw(401)
|
// ctx.throw(401)
|
||||||
|
throw new Error('Could not verify JWT')
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
// console.log(`Err: Could not find user.`)
|
// console.log(`Err: Could not find user.`)
|
||||||
ctx.throw(401)
|
// ctx.throw(401)
|
||||||
|
throw new Error('Could not find user')
|
||||||
}
|
}
|
||||||
// console.log('ctx.state.user: ', ctx.state.user)
|
// console.log('ctx.state.user: ', ctx.state.user)
|
||||||
|
|
||||||
@@ -135,7 +157,8 @@ class Validators {
|
|||||||
|
|
||||||
// If they don't match, then the calling user better be an admin.
|
// If they don't match, then the calling user better be an admin.
|
||||||
if (ctx.state.user.type !== 'admin') {
|
if (ctx.state.user.type !== 'admin') {
|
||||||
ctx.throw(401, 'not admin')
|
// ctx.throw(401, 'not admin')
|
||||||
|
throw new Error('User is not an admin')
|
||||||
} else {
|
} else {
|
||||||
wlogger.verbose("It's ok. The user is an admin.")
|
wlogger.verbose("It's ok. The user is an admin.")
|
||||||
}
|
}
|
||||||
@@ -144,6 +167,8 @@ class Validators {
|
|||||||
// return next()
|
// return next()
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// console.log('Error in ensureTargetUserOrAdmin(): ', error)
|
||||||
|
ctx.status = 401
|
||||||
ctx.throw(401, error.message)
|
ctx.throw(401, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,4 +191,4 @@ class Validators {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Validators
|
export default Validators
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
REST API Controller library for the /user route
|
REST API Controller library for the /user route
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { wlogger } = require('../../../adapters/wlogger')
|
import wlogger from '../../../adapters/wlogger.js'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ class UserRESTControllerLib {
|
|||||||
* @apiGroup REST Users
|
* @apiGroup REST Users
|
||||||
*
|
*
|
||||||
* @apiExample Example usage:
|
* @apiExample Example usage:
|
||||||
* curl -H "Content-Type: application/json" -X POST -d '{ "user": { "email": "email@format.com", "name": "my name", "password": "secretpasas" } }' localhost:5001/users
|
* curl -H "Content-Type: application/json" -X POST -d '{ "user": { "email": "email@format.com", "name": "my name", "password": "secretpasas" } }' localhost:5010/users
|
||||||
*
|
*
|
||||||
* @apiParam {Object} user User object (required)
|
* @apiParam {Object} user User object (required)
|
||||||
* @apiParam {String} user.email Email
|
* @apiParam {String} user.email Email
|
||||||
@@ -124,7 +124,7 @@ class UserRESTControllerLib {
|
|||||||
|
|
||||||
ctx.body = { users }
|
ctx.body = { users }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
wlogger.error('Error in users/controller.js/getUsers(): '.err)
|
wlogger.error('Error in users/controller.js/getUsers(): ', err)
|
||||||
ctx.throw(422, err.message)
|
ctx.throw(422, err.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ class UserRESTControllerLib {
|
|||||||
* @apiGroup REST Users
|
* @apiGroup REST Users
|
||||||
*
|
*
|
||||||
* @apiExample Example usage:
|
* @apiExample Example usage:
|
||||||
* curl -H "Content-Type: application/json" -X GET localhost:5000/users/56bd1da600a526986cf65c80
|
* curl -H "Content-Type: application/json" -X GET localhost:5010/users/56bd1da600a526986cf65c80
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} users User object
|
* @apiSuccess {Object} users User object
|
||||||
* @apiSuccess {ObjectId} users._id User id
|
* @apiSuccess {ObjectId} users._id User id
|
||||||
@@ -281,4 +281,4 @@ class UserRESTControllerLib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UserRESTControllerLib
|
export default UserRESTControllerLib
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries.
|
// Public npm libraries.
|
||||||
const Router = require('koa-router')
|
import Router from 'koa-router'
|
||||||
|
|
||||||
// Local libraries.
|
// Local libraries.
|
||||||
const UserRESTControllerLib = require('./controller')
|
import UserRESTControllerLib from './controller.js'
|
||||||
const Validators = require('../middleware/validators')
|
|
||||||
|
import Validators from '../middleware/validators.js'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
@@ -85,4 +86,4 @@ class UserRouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UserRouter
|
export default UserRouter
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
This Controller library is concerned with timer-based functions that are
|
||||||
|
kicked off periodicially.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import config from '../../config/index.js'
|
||||||
|
|
||||||
|
class TimerControllers {
|
||||||
|
constructor (localConfig = {}) {
|
||||||
|
// Dependency Injection.
|
||||||
|
this.adapters = localConfig.adapters
|
||||||
|
if (!this.adapters) {
|
||||||
|
throw new Error(
|
||||||
|
'Instance of Adapters library required when instantiating Timer Controller libraries.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
this.useCases = localConfig.useCases
|
||||||
|
if (!this.useCases) {
|
||||||
|
throw new Error(
|
||||||
|
'Instance of Use Cases library required when instantiating Timer Controller libraries.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debugLevel = localConfig.debugLevel
|
||||||
|
|
||||||
|
// Encapsulate dependencies
|
||||||
|
this.config = config
|
||||||
|
|
||||||
|
// Bind 'this' object to all subfunctions.
|
||||||
|
this.exampleTimerFunc = this.exampleTimerFunc.bind(this)
|
||||||
|
|
||||||
|
// this.startTimers()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start all the time-based controllers.
|
||||||
|
startTimers () {
|
||||||
|
// Any new timer control functions can be added here. They will be started
|
||||||
|
// when the server starts.
|
||||||
|
this.optimizeWalletHandle = setInterval(this.exampleTimerFunc, 60000 * 10)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTimers () {
|
||||||
|
clearInterval(this.optimizeWalletHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace this example function with your own timer handler.
|
||||||
|
exampleTimerFunc (negativeTest) {
|
||||||
|
try {
|
||||||
|
console.log('Example timer controller executed.')
|
||||||
|
|
||||||
|
if (negativeTest) throw new Error('test error')
|
||||||
|
|
||||||
|
return true
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in exampleTimerFunc(): ', err)
|
||||||
|
|
||||||
|
// Note: Do not throw an error. This is a top-level function.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TimerControllers
|
||||||
@@ -21,4 +21,4 @@ class User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = User
|
export default User
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const UserUseCases = require('./user')
|
import UserUseCases from './user.js'
|
||||||
const BCHUseCases = require('./bch')
|
import BCHUseCases from './bch/index.js'
|
||||||
|
|
||||||
class UseCases {
|
class UseCases {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -24,16 +24,10 @@ class UseCases {
|
|||||||
|
|
||||||
// Run any startup Use Cases at the start of the app.
|
// Run any startup Use Cases at the start of the app.
|
||||||
async start () {
|
async start () {
|
||||||
// try {
|
|
||||||
console.log('Async Use Cases have been started.')
|
console.log('Async Use Cases have been started.')
|
||||||
|
|
||||||
return true
|
return true
|
||||||
// } catch (err) {
|
|
||||||
// console.error('Error in use-cases/index.js/start()')
|
|
||||||
// // console.log(err)
|
|
||||||
// throw err
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UseCases
|
export default UseCases
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
functions are called by the /user REST API endpoints.
|
functions are called by the /user REST API endpoints.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const UserEntity = require('../entities/user')
|
import UserEntity from '../entities/user.js'
|
||||||
const { wlogger } = require('../adapters/wlogger')
|
|
||||||
|
import wlogger from '../adapters/wlogger.js'
|
||||||
|
|
||||||
class UserLib {
|
class UserLib {
|
||||||
constructor (localConfig = {}) {
|
constructor (localConfig = {}) {
|
||||||
@@ -181,4 +182,4 @@ class UserLib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UserLib
|
export default UserLib
|
||||||
|
|||||||
@@ -5,15 +5,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const axios = require('axios').default
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
// const sinon = require('sinon')
|
// const sinon = require('sinon')
|
||||||
|
|
||||||
// Local support libraries
|
// Local support libraries
|
||||||
const config = require('../../../config')
|
import config from '../../../config/index.js'
|
||||||
const Server = require('../../../bin/server')
|
|
||||||
const testUtils = require('../../utils/test-utils')
|
import Server from '../../../bin/server.js'
|
||||||
const AdminLib = require('../../../src/adapters/admin')
|
import testUtils from '../../utils/test-utils.js'
|
||||||
|
import AdminLib from '../../../src/adapters/admin.js'
|
||||||
const adminLib = new AdminLib()
|
const adminLib = new AdminLib()
|
||||||
|
|
||||||
// const request = supertest.agent(app.listen())
|
// const request = supertest.agent(app.listen())
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
const testUtils = require('../../utils/test-utils')
|
import testUtils from '../../utils/test-utils.js'
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const config = require('../../../config')
|
import config from '../../../config/index.js'
|
||||||
const axios = require('axios').default
|
import axios from 'axios'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
import util from 'util'
|
||||||
|
|
||||||
const util = require('util')
|
import UserController from '../../../src/controllers/rest-api/users/controller.js'
|
||||||
|
import Adapters from '../../../src/adapters/index.js'
|
||||||
|
import UseCases from '../../../src/use-cases/index.js'
|
||||||
util.inspect.defaultOptions = { depth: 1 }
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
const LOCALHOST = `http://localhost:${config.port}`
|
const LOCALHOST = `http://localhost:${config.port}`
|
||||||
|
|
||||||
const context = {}
|
const context = {}
|
||||||
|
|
||||||
const UserController = require('../../../src/controllers/rest-api/users/controller')
|
|
||||||
const Adapters = require('../../../src/adapters')
|
|
||||||
const adapters = new Adapters()
|
const adapters = new Adapters()
|
||||||
const UseCases = require('../../../src/use-cases/')
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ describe('Users', () => {
|
|||||||
|
|
||||||
// Get the JWT used to log in as the admin 'system' user.
|
// Get the JWT used to log in as the admin 'system' user.
|
||||||
const adminJWT = await testUtils.getAdminJWT()
|
const adminJWT = await testUtils.getAdminJWT()
|
||||||
// console.log(`adminJWT: ${admi nJWT}`)
|
console.log(`adminJWT: ${adminJWT}`)
|
||||||
context.adminJWT = adminJWT
|
context.adminJWT = adminJWT
|
||||||
|
|
||||||
// const admin = await testUtils.loginAdminUser()
|
// const admin = await testUtils.loginAdminUser()
|
||||||
@@ -71,9 +70,6 @@ describe('Users', () => {
|
|||||||
|
|
||||||
await axios(options)
|
await axios(options)
|
||||||
|
|
||||||
/* console.log(
|
|
||||||
`result stringified: ${JSON.stringify(result.data, null, 2)}`
|
|
||||||
) */
|
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert(err.response.status === 422, 'Error code 422 expected.')
|
assert(err.response.status === 422, 'Error code 422 expected.')
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
const config = require('../../../config')
|
import config from '../../../config/index.js'
|
||||||
const axios = require('axios').default
|
import axios from 'axios'
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
import { context as mockContext } from '../../unit/mocks/ctx-mock.js'
|
||||||
|
import ContactController from '../../../src/controllers/rest-api/contact/controller.js'
|
||||||
|
|
||||||
// Mock data
|
// Mock data
|
||||||
// const mockData = require('./mocks/contact-mocks')
|
// const mockData = require('./mocks/contact-mocks')
|
||||||
|
|
||||||
const LOCALHOST = `http://localhost:${config.port}`
|
const LOCALHOST = `http://localhost:${config.port}`
|
||||||
|
|
||||||
const mockContext = require('../../unit/mocks/ctx-mock').context
|
|
||||||
const ContactController = require('../../../src/controllers/rest-api/contact/controller')
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
const config = require('../../../config')
|
import config from '../../../config/index.js'
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
|
import axios from 'axios'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
import util from 'util'
|
||||||
|
|
||||||
const axios = require('axios').default
|
import LogsController from '../../../src/controllers/rest-api/logs/controller.js'
|
||||||
const sinon = require('sinon')
|
import { context as mockContext } from '../../unit/mocks/ctx-mock.js'
|
||||||
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = { depth: 1 }
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
const LOCALHOST = `http://localhost:${config.port}`
|
const LOCALHOST = `http://localhost:${config.port}`
|
||||||
|
|
||||||
const LogsController = require('../../../src/controllers/rest-api/logs/controller')
|
|
||||||
const mockContext = require('../../unit/mocks/ctx-mock').context
|
|
||||||
|
|
||||||
let sandbox
|
let sandbox
|
||||||
let uut
|
let uut
|
||||||
describe('LogsApi', () => {
|
describe('LogsApi', () => {
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
const assert = require('chai').assert
|
/*
|
||||||
const testUtils = require('../../utils/test-utils')
|
import { assert } from 'chai';
|
||||||
|
import testUtils from '../../utils/test-utils.js';
|
||||||
const Validators = require('../../../src/controllers/rest-api/middleware/validators')
|
import Validators from '../../../src/controllers/rest-api/middleware/validators.js';
|
||||||
|
import sinon from 'sinon';
|
||||||
const sinon = require('sinon')
|
import { context as mockContext } from '../../unit/mocks/ctx-mock.js';
|
||||||
const mockContext = require('../../unit/mocks/ctx-mock').context
|
import util from 'util';
|
||||||
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = { depth: 1 }
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
const context = {}
|
const context = {}
|
||||||
@@ -303,3 +301,4 @@ describe('Validators', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
|
import Admin from '../../../src/adapters/admin.js'
|
||||||
const Admin = require('../../../src/adapters/admin')
|
import sinon from 'sinon'
|
||||||
|
import util from 'util'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = { depth: 1 }
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Global npm libraries
|
// Global npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const Adapters = require('../../../src/adapters')
|
import Adapters from '../../../src/adapters/index.js'
|
||||||
|
|
||||||
describe('#adapters', () => {
|
describe('#adapters', () => {
|
||||||
let uut, sandbox
|
let uut, sandbox
|
||||||
@@ -26,6 +27,8 @@ describe('#adapters', () => {
|
|||||||
it('should start the async adapters', async () => {
|
it('should start the async adapters', async () => {
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
uut.config.getJwtAtStartup = true
|
uut.config.getJwtAtStartup = true
|
||||||
|
uut.config.useIpfs = true
|
||||||
|
uut.config.env = 'not-a-test'
|
||||||
sandbox.stub(uut.fullStackJwt, 'getJWT').resolves()
|
sandbox.stub(uut.fullStackJwt, 'getJWT').resolves()
|
||||||
sandbox.stub(uut.fullStackJwt, 'instanceBchjs').resolves()
|
sandbox.stub(uut.fullStackJwt, 'instanceBchjs').resolves()
|
||||||
sandbox.stub(uut.ipfs, 'start').resolves()
|
sandbox.stub(uut.ipfs, 'start').resolves()
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
import ContactLib from '../../../src/adapters/contact.js'
|
||||||
const ContactLib = require('../../../src/adapters/contact')
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const FullStackJWT = require('../../../src/adapters/fullstack-jwt')
|
import sinon from 'sinon'
|
||||||
|
import FullStackJWT from '../../../src/adapters/fullstack-jwt.js'
|
||||||
|
|
||||||
describe('#FullStackJWT', () => {
|
describe('#FullStackJWT', () => {
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -2,20 +2,20 @@
|
|||||||
Unit tests for the IPFS Adapter.
|
Unit tests for the IPFS Adapter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const IPFSCoordAdapter = require('../../../src/adapters/ipfs/ipfs-coord')
|
import sinon from 'sinon'
|
||||||
const IPFSMock = require('../mocks/ipfs-mock')
|
import IPFSCoordAdapter from '../../../src/adapters/ipfs/ipfs-coord.js'
|
||||||
const IPFSCoordMock = require('../mocks/ipfs-coord-mock')
|
import create from '../mocks/ipfs-mock.js'
|
||||||
const config = require('../../../config')
|
import IPFSCoordMock from '../mocks/ipfs-coord-mock.js'
|
||||||
|
import config from '../../../config/index.js'
|
||||||
|
|
||||||
describe('#IPFS', () => {
|
describe('#IPFS', () => {
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const ipfs = IPFSMock.create()
|
const ipfs = create()
|
||||||
const bchjs = {}
|
const bchjs = {}
|
||||||
uut = new IPFSCoordAdapter({ ipfs, bchjs })
|
uut = new IPFSCoordAdapter({ ipfs, bchjs })
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ describe('#IPFS', () => {
|
|||||||
|
|
||||||
it('should throw an error if bchjs instance is not included', () => {
|
it('should throw an error if bchjs instance is not included', () => {
|
||||||
try {
|
try {
|
||||||
const ipfs = IPFSMock.create()
|
const ipfs = create()
|
||||||
uut = new IPFSCoordAdapter({ ipfs })
|
uut = new IPFSCoordAdapter({ ipfs })
|
||||||
|
|
||||||
assert.fail('Unexpected code path')
|
assert.fail('Unexpected code path')
|
||||||
@@ -67,7 +67,7 @@ describe('#IPFS', () => {
|
|||||||
it('should get the public IP address if this node is a Circuit Relay', async () => {
|
it('should get the public IP address if this node is a Circuit Relay', async () => {
|
||||||
// Mock dependencies.
|
// Mock dependencies.
|
||||||
uut.IpfsCoord = IPFSCoordMock
|
uut.IpfsCoord = IPFSCoordMock
|
||||||
sandbox.stub(uut.publicIp, 'v4').returns('123')
|
sandbox.stub(uut, 'publicIp').resolves('123')
|
||||||
|
|
||||||
// Force Circuit Relay
|
// Force Circuit Relay
|
||||||
uut.config.isCircuitRelay = true
|
uut.config.isCircuitRelay = true
|
||||||
@@ -77,6 +77,21 @@ describe('#IPFS', () => {
|
|||||||
|
|
||||||
assert.equal(result, true)
|
assert.equal(result, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should exit quietly if this node is a Circuit Relay and there is an issue getting the IP address', async () => {
|
||||||
|
// Mock dependencies.
|
||||||
|
uut.IpfsCoord = IPFSCoordMock
|
||||||
|
sandbox.stub(uut, 'publicIp').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
// Force Circuit Relay
|
||||||
|
uut.config.isCircuitRelay = true
|
||||||
|
|
||||||
|
const result = await uut.start()
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
|
||||||
it('should return a promise that resolves into an instance of IPFS in production mode', async () => {
|
it('should return a promise that resolves into an instance of IPFS in production mode', async () => {
|
||||||
uut.config.isProduction = true
|
uut.config.isProduction = true
|
||||||
// Mock dependencies.
|
// Mock dependencies.
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
Unit tests for the index.js file for the IPFS and ipfs-coord libraries.
|
Unit tests for the index.js file for the IPFS and ipfs-coord libraries.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
import BCHJS from '@psf/bch-js'
|
||||||
const BCHJS = require('@psf/bch-js')
|
|
||||||
|
|
||||||
const IPFSLib = require('../../../src/adapters/ipfs')
|
import sinon from 'sinon'
|
||||||
const IPFSMock = require('../mocks/ipfs-mock')
|
import IPFSLib from '../../../src/adapters/ipfs/index.js'
|
||||||
const IPFSCoordMock = require('../mocks/ipfs-coord-mock')
|
// import create from '../mocks/ipfs-mock.js'
|
||||||
|
import IPFSCoordMock from '../mocks/ipfs-coord-mock.js'
|
||||||
|
|
||||||
describe('#IPFS-adapter-index', () => {
|
describe('#IPFS-adapter-index', () => {
|
||||||
let uut
|
let uut
|
||||||
@@ -41,7 +41,9 @@ describe('#IPFS-adapter-index', () => {
|
|||||||
|
|
||||||
it('should return a promise that resolves into an instance of IPFS.', async () => {
|
it('should return a promise that resolves into an instance of IPFS.', async () => {
|
||||||
// Mock dependencies.
|
// Mock dependencies.
|
||||||
uut.ipfsAdapter = new IPFSMock()
|
uut.ipfsAdapter = {
|
||||||
|
start: async () => {}
|
||||||
|
}
|
||||||
uut.IpfsCoordAdapter = IPFSCoordMock
|
uut.IpfsCoordAdapter = IPFSCoordMock
|
||||||
|
|
||||||
const result = await uut.start({ bchjs: {} })
|
const result = await uut.start({ bchjs: {} })
|
||||||
@@ -81,4 +83,155 @@ describe('#IPFS-adapter-index', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#getStatus', () => {
|
||||||
|
it('should return an object with node metrics', () => {
|
||||||
|
// Force uut to have the needed properties
|
||||||
|
uut.ipfsCoordAdapter = {
|
||||||
|
ipfsCoord: {
|
||||||
|
thisNode: {
|
||||||
|
ipfsId: 'fake-id',
|
||||||
|
ipfsMultiaddrs: [],
|
||||||
|
bchAddr: 'fake-bch-addr',
|
||||||
|
slpAddr: 'fake-slp-addr',
|
||||||
|
pubKey: 'fake-pubkey',
|
||||||
|
peerList: [],
|
||||||
|
relayData: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = uut.getStatus()
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.property(result, 'ipfsId')
|
||||||
|
assert.property(result, 'multiAddrs')
|
||||||
|
assert.property(result, 'bchAddr')
|
||||||
|
assert.property(result, 'slpAddr')
|
||||||
|
assert.property(result, 'pubKey')
|
||||||
|
assert.property(result, 'peers')
|
||||||
|
assert.property(result, 'relays')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should catch, report, and throw errors', () => {
|
||||||
|
try {
|
||||||
|
uut.getStatus()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log('err.message: ', err.message)
|
||||||
|
assert.include(err.message, 'Cannot read properties')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#_removeDuplicatePeers', () => {
|
||||||
|
it('should return the same array when there are no duplicates', () => {
|
||||||
|
const inArray = [
|
||||||
|
'12D3KooWPpBXhhAeoCZCGuQ3KR4xwHzzvtP57f6zLmo8P7ZFBJFE',
|
||||||
|
'12D3KooWRBhwfeP2Y9CDkFRBAZ1pmxUadH36TKuk3KtKm5XXP8mA',
|
||||||
|
'12D3KooWGsgHWyDLKuV4ZSfRJfsxQJj77rxx3i8Px3qXKHsLN7a2',
|
||||||
|
'12D3KooWJyc54njjeZGbLew4D8u1ghrmZTTPyh3QpBF7dxtd3zGY',
|
||||||
|
'12D3KooWDtj9cfj1SKuLbDNKvKRKSsGN8qivq9M8CYpLPDpcD5pu'
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = uut._removeDuplicatePeers(inArray)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result.length, inArray.length)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should remove duplicates from an array', () => {
|
||||||
|
const inArray = [
|
||||||
|
'12D3KooWPpBXhhAeoCZCGuQ3KR4xwHzzvtP57f6zLmo8P7ZFBJFE',
|
||||||
|
'12D3KooWRBhwfeP2Y9CDkFRBAZ1pmxUadH36TKuk3KtKm5XXP8mA',
|
||||||
|
'12D3KooWGsgHWyDLKuV4ZSfRJfsxQJj77rxx3i8Px3qXKHsLN7a2',
|
||||||
|
'12D3KooWJyc54njjeZGbLew4D8u1ghrmZTTPyh3QpBF7dxtd3zGY',
|
||||||
|
'12D3KooWDtj9cfj1SKuLbDNKvKRKSsGN8qivq9M8CYpLPDpcD5pu',
|
||||||
|
'12D3KooWPpBXhhAeoCZCGuQ3KR4xwHzzvtP57f6zLmo8P7ZFBJFE',
|
||||||
|
'12D3KooWRBhwfeP2Y9CDkFRBAZ1pmxUadH36TKuk3KtKm5XXP8mA'
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = uut._removeDuplicatePeers(inArray)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result.length, inArray.length - 2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#getPeers', () => {
|
||||||
|
it('should return an array of current JSON data about each peer when showAll is true', async () => {
|
||||||
|
// Mock dependencies
|
||||||
|
uut.ipfsCoordAdapter.ipfsCoord = {
|
||||||
|
thisNode: {
|
||||||
|
peerData: [{ from: 'a', data: { jsonLd: { name: 'a', protocol: 'test', version: '1' } } }, { from: 'b' }]
|
||||||
|
},
|
||||||
|
adapters: {
|
||||||
|
ipfs: {
|
||||||
|
getPeers: async () => ['a', 'b']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await uut.getPeers(true)
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should catch, report, and throw errors', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
uut.ipfsCoordAdapter.ipfsCoord = {
|
||||||
|
thisNode: {},
|
||||||
|
adapters: {
|
||||||
|
ipfs: {
|
||||||
|
getPeers: async () => { throw new Error('test error') }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.getPeers()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log('err.message: ', err.message)
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#getRelays', () => {
|
||||||
|
it('should return known relays', () => {
|
||||||
|
uut.ipfsCoordAdapter.ipfsCoord = {
|
||||||
|
thisNode: {
|
||||||
|
peerData: [{ from: 'a', data: { jsonLd: { name: 'a', description: 'test' } } }, { from: 'b' }],
|
||||||
|
relayData: [{ ipfsId: 'c' }, { ipfsId: 'a' }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = uut.getRelays()
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.isArray(result.v2Relays)
|
||||||
|
assert.equal(result.v2Relays.length, 2)
|
||||||
|
assert.property(result.v2Relays[0], 'name')
|
||||||
|
assert.property(result.v2Relays[0], 'description')
|
||||||
|
assert.property(result.v2Relays[1], 'name')
|
||||||
|
assert.property(result.v2Relays[1], 'description')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should catch, report, and throw errors', () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
uut.ipfsCoordAdapter.ipfsCoord = { thisNode: {} }
|
||||||
|
|
||||||
|
uut.getRelays()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log('err.message: ', err.message)
|
||||||
|
assert.include(err.message, 'Cannot read')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,20 +2,29 @@
|
|||||||
Unit tests for the IPFS Adapter.
|
Unit tests for the IPFS Adapter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
// Global npm libraries
|
||||||
const sinon = require('sinon')
|
import { assert } from 'chai'
|
||||||
const IPFSLib = require('../../../src/adapters/ipfs/ipfs')
|
import sinon from 'sinon'
|
||||||
const IPFSMock = require('../mocks/ipfs-mock')
|
import cloneDeep from 'lodash.clonedeep'
|
||||||
const config = require('../../../config')
|
import { peerIdFromString } from '@libp2p/peer-id'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import IPFSLib from '../../../src/adapters/ipfs/ipfs.js'
|
||||||
|
// import create from '../mocks/ipfs-mock.js'
|
||||||
|
import config from '../../../config/index.js'
|
||||||
|
import createHeliaLib from '../mocks/helia-mock.js'
|
||||||
|
|
||||||
// config.isProduction = true;
|
// config.isProduction = true;
|
||||||
describe('#IPFS-adapter', () => {
|
describe('#IPFS-adapter', () => {
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
let ipfs
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
uut = new IPFSLib()
|
uut = new IPFSLib()
|
||||||
|
|
||||||
|
ipfs = cloneDeep(createHeliaLib)
|
||||||
|
|
||||||
sandbox = sinon.createSandbox()
|
sandbox = sinon.createSandbox()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -44,35 +53,28 @@ describe('#IPFS-adapter', () => {
|
|||||||
describe('#start', () => {
|
describe('#start', () => {
|
||||||
it('should return a promise that resolves into an instance of IPFS.', async () => {
|
it('should return a promise that resolves into an instance of IPFS.', async () => {
|
||||||
// Mock dependencies.
|
// Mock dependencies.
|
||||||
uut.IPFS = IPFSMock
|
sandbox.stub(uut, 'createNode').resolves(ipfs)
|
||||||
|
sandbox.stub(uut, 'publicIp').resolves('192.168.2.4')
|
||||||
|
sandbox.stub(uut, 'multiaddr').returns('/ip4/fake-multiaddr')
|
||||||
|
|
||||||
const result = await uut.start()
|
const result = await uut.start()
|
||||||
// console.log('result: ', result)
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
// Assert properties of the instance are set.
|
||||||
assert.equal(uut.isReady, true)
|
assert.equal(uut.isReady, true)
|
||||||
|
assert.property(uut, 'multiaddrs')
|
||||||
|
assert.property(uut, 'id')
|
||||||
|
|
||||||
assert.property(result, 'config')
|
// Output should be an instance of IPFS
|
||||||
})
|
assert.property(result, 'libp2p')
|
||||||
|
|
||||||
it('should return a promise that resolves into an instance of IPFS in production mode.', async () => {
|
|
||||||
// Mock dependencies.
|
|
||||||
uut.IPFS = IPFSMock
|
|
||||||
uut.config.isProduction = true
|
|
||||||
const result = await uut.start()
|
|
||||||
// console.log('result: ', result)
|
|
||||||
|
|
||||||
assert.equal(uut.isReady, true)
|
|
||||||
|
|
||||||
assert.property(result, 'config')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should catch and throw an error', async () => {
|
it('should catch and throw an error', async () => {
|
||||||
try {
|
try {
|
||||||
// Force an error
|
// Force an error
|
||||||
sandbox.stub(uut.IPFS, 'create').rejects(new Error('test error'))
|
sandbox.stub(uut, 'createNode').rejects(new Error('test error'))
|
||||||
|
|
||||||
await uut.start()
|
await uut.start()
|
||||||
|
|
||||||
assert.fail('Unexpected code path.')
|
assert.fail('Unexpected code path.')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// console.log(err)
|
// console.log(err)
|
||||||
@@ -95,24 +97,146 @@ describe('#IPFS-adapter', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// describe('#rmBlocksDir', () => {
|
describe('#ensureBlocksDir', () => {
|
||||||
// it('should delete the /blocks directory', () => {
|
it('should create directory if it does not exist', () => {
|
||||||
// const result = uut.rmBlocksDir()
|
// Force desired code path
|
||||||
//
|
sandbox.stub(uut.fs, 'existsSync').returns(false)
|
||||||
// assert.equal(result, true)
|
sandbox.stub(uut.fs, 'mkdirSync').returns(true)
|
||||||
// })
|
|
||||||
//
|
const result = uut.ensureBlocksDir()
|
||||||
// it('should catch and throw an error', () => {
|
|
||||||
// try {
|
assert.equal(result, true)
|
||||||
// // Force an error
|
})
|
||||||
// sandbox.stub(uut.fs, 'rmdirSync').throws(new Error('test error'))
|
|
||||||
//
|
it('should report and throw errors', () => {
|
||||||
// uut.rmBlocksDir()
|
// Force an error
|
||||||
//
|
sandbox.stub(uut.fs, 'existsSync').throws(new Error('test error'))
|
||||||
// assert.fail('Unexpected code path')
|
|
||||||
// } catch (err) {
|
try {
|
||||||
// assert.equal(err.message, 'test error')
|
uut.ensureBlocksDir()
|
||||||
// }
|
|
||||||
// })
|
assert.fail('Unexpected code path')
|
||||||
// })
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#createNode', () => {
|
||||||
|
it('should report and throw errors', async () => {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut, 'createLibp2p').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await uut.createNode()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should create an IPFS node from Helia', async () => {
|
||||||
|
uut.config.isCircuitRelay = false
|
||||||
|
const result = await uut.createNode()
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
// Assert the returned IPFS node has expected properties
|
||||||
|
assert.property(result, 'libp2p')
|
||||||
|
assert.property(result, 'blockstore')
|
||||||
|
|
||||||
|
// Stop the IPFS node
|
||||||
|
await result.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should create a Circuit Relay if configured', async () => {
|
||||||
|
uut.config.isCircuitRelay = true
|
||||||
|
const result = await uut.createNode()
|
||||||
|
|
||||||
|
// Assert the returned IPFS node has expected properties
|
||||||
|
assert.property(result, 'libp2p')
|
||||||
|
assert.property(result, 'blockstore')
|
||||||
|
|
||||||
|
// Stop the IPFS node
|
||||||
|
await result.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should create a new private key on first run', async () => {
|
||||||
|
uut.config.isCircuitRelay = false
|
||||||
|
|
||||||
|
// Mock dependencies and force desired code path.
|
||||||
|
let beenCalled = false
|
||||||
|
sandbox.stub(uut, 'getKeychain').resolves({
|
||||||
|
exportPeerId: async () => {
|
||||||
|
if (!beenCalled) {
|
||||||
|
beenCalled = true
|
||||||
|
throw new Error('test error')
|
||||||
|
}
|
||||||
|
return peerIdFromString('12D3KooWSXF1PnEfiA8bCG8SJduCvzdwHtvhVPK4WC6zzDoto2XP')
|
||||||
|
},
|
||||||
|
createKey: async () => {}
|
||||||
|
})
|
||||||
|
sandbox.stub(uut, 'createLibp2p').resolves()
|
||||||
|
sandbox.stub(uut, 'createHelia').resolves({})
|
||||||
|
|
||||||
|
const result = await uut.createNode()
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.property(result, 'fs')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not use circuit relay when CONNECT_PREF is set to direct', async () => {
|
||||||
|
process.env.CONNECT_PREF = 'direct'
|
||||||
|
|
||||||
|
uut.config.isCircuitRelay = false
|
||||||
|
const result = await uut.createNode()
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
delete process.env.CONNECT_PREF
|
||||||
|
|
||||||
|
// Assert the returned IPFS node has expected properties
|
||||||
|
assert.property(result, 'libp2p')
|
||||||
|
assert.property(result, 'blockstore')
|
||||||
|
|
||||||
|
// Stop the IPFS node
|
||||||
|
await result.stop()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#getSeed', () => {
|
||||||
|
it('should read the seed from the JSON file', async () => {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut.jsonFiles, 'readJSON').resolves('12345678')
|
||||||
|
|
||||||
|
const result = await uut.getSeed()
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.isString(result)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should generate a new seed if the JSON file is not found', async () => {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut.jsonFiles, 'readJSON').rejects(new Error('test error'))
|
||||||
|
sandbox.stub(uut.jsonFiles, 'writeJSON').resolves()
|
||||||
|
|
||||||
|
const result = await uut.getSeed()
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.isString(result)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should catch, report, and throw errors', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.jsonFiles, 'readJSON').rejects(new Error('test error'))
|
||||||
|
sandbox.stub(uut.jsonFiles, 'writeJSON').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.getSeed()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const fs = require('fs')
|
import fs from 'fs'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
import util from 'util'
|
||||||
|
|
||||||
const util = require('util')
|
import JsonFiles from '../../../src/adapters/json-files.js'
|
||||||
|
|
||||||
|
// Hack to get __dirname back.
|
||||||
|
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
|
||||||
|
import * as url from 'url'
|
||||||
util.inspect.defaultOptions = { depth: 1 }
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||||
const JsonFiles = require('../../../src/adapters/json-files')
|
|
||||||
|
|
||||||
const JSON_FILE = 'test-json-file.json'
|
const JSON_FILE = 'test-json-file.json'
|
||||||
const JSON_PATH = `${__dirname.toString()}/${JSON_FILE}`
|
const JSON_PATH = `${__dirname.toString()}/${JSON_FILE}`
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
import util from 'util'
|
||||||
|
|
||||||
const sinon = require('sinon')
|
import LogsApiLib from '../../../src/adapters/logapi.js'
|
||||||
|
import mockData from '../mocks/log-api-mock.js'
|
||||||
|
|
||||||
const util = require('util')
|
// Hack to get __dirname back.
|
||||||
|
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
|
||||||
|
import * as url from 'url'
|
||||||
util.inspect.defaultOptions = { depth: 1 }
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||||
const LogsApiLib = require('../../../src/adapters/logapi')
|
|
||||||
const mockData = require('../mocks/log-api-mock')
|
|
||||||
|
|
||||||
const context = {}
|
const context = {}
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const NodeMailer = require('../../../src/adapters/nodemailer')
|
import sinon from 'sinon'
|
||||||
|
import NodeMailer from '../../../src/adapters/nodemailer.js'
|
||||||
|
|
||||||
let sandbox
|
let sandbox
|
||||||
let uut
|
let uut
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const PassportLib = require('../../../src/adapters/passport')
|
import PassportLib from '../../../src/adapters/passport.js'
|
||||||
|
import sinon from 'sinon'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -2,16 +2,17 @@
|
|||||||
Unit tests for the users Mongoose model.
|
Unit tests for the users Mongoose model.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
const mongoose = require('mongoose')
|
import sinon from 'sinon'
|
||||||
|
import mongoose from 'mongoose'
|
||||||
|
|
||||||
|
import User from '../../../src/adapters/localdb/models/users.js'
|
||||||
|
import config from '../../../config/index.js'
|
||||||
|
|
||||||
// Set the environment variable to signal this is a test.
|
// Set the environment variable to signal this is a test.
|
||||||
process.env.SVC_ENV = 'test'
|
process.env.SVC_ENV = 'test'
|
||||||
|
|
||||||
const User = require('../../../src/adapters/localdb/models/users')
|
|
||||||
const config = require('../../../config')
|
|
||||||
|
|
||||||
describe('#User-Adapter', () => {
|
describe('#User-Adapter', () => {
|
||||||
// let uut
|
// let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const { Wlogger } = require('../../../src/adapters/wlogger')
|
import { Wlogger } from '../../../src/adapters/wlogger.js'
|
||||||
|
import sinon from 'sinon'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import sinon from 'sinon'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const Controllers = require('../../../src/controllers')
|
import Controllers from '../../../src/controllers/index.js'
|
||||||
|
const assert = require('chai').assert
|
||||||
|
|
||||||
describe('#Controllers', () => {
|
describe('#Controllers', () => {
|
||||||
let uut
|
let uut
|
||||||
@@ -33,6 +33,9 @@ describe('#Controllers', () => {
|
|||||||
attachRPCRouter: () => {}
|
attachRPCRouter: () => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mock the timer controllers
|
||||||
|
sandbox.stub(uut.timerControllers, 'startTimers').returns()
|
||||||
|
|
||||||
const app = {
|
const app = {
|
||||||
use: () => {}
|
use: () => {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,18 +5,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const jsonrpc = require('jsonrpc-lite')
|
import jsonrpc from 'jsonrpc-lite'
|
||||||
const sinon = require('sinon')
|
|
||||||
const assert = require('chai').assert
|
import sinon from 'sinon'
|
||||||
const { v4: uid } = require('uuid')
|
import { assert } from 'chai'
|
||||||
|
import { v4 as uid } from 'uuid'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import Validators from '../../../../src/controllers/json-rpc/validators.js'
|
||||||
|
|
||||||
|
import adapters from '../../mocks/adapters/index.js'
|
||||||
|
|
||||||
// Set the environment variable to signal this is a test.
|
// Set the environment variable to signal this is a test.
|
||||||
process.env.SVC_ENV = 'test'
|
process.env.SVC_ENV = 'test'
|
||||||
|
|
||||||
// Local libraries
|
|
||||||
const Validators = require('../../../../src/controllers/json-rpc/validators')
|
|
||||||
const adapters = require('../../mocks/adapters')
|
|
||||||
|
|
||||||
describe('#validators', () => {
|
describe('#validators', () => {
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -5,15 +5,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
const assert = require('chai').assert
|
|
||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import RateLimit from '../../../../src/controllers/json-rpc/rate-limit.js'
|
||||||
|
|
||||||
// Set the environment variable to signal this is a test.
|
// Set the environment variable to signal this is a test.
|
||||||
process.env.SVC_ENV = 'test'
|
process.env.SVC_ENV = 'test'
|
||||||
|
|
||||||
// Local libraries
|
|
||||||
const RateLimit = require('../../../../src/controllers/json-rpc/rate-limit')
|
|
||||||
|
|
||||||
describe('#rate-limit', () => {
|
describe('#rate-limit', () => {
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
const assert = require('chai').assert
|
|
||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const AboutRPC = require('../../../../src/controllers/json-rpc/about')
|
import AboutRPC from '../../../../src/controllers/json-rpc/about/index.js'
|
||||||
|
|
||||||
describe('#AboutRPC', () => {
|
describe('#AboutRPC', () => {
|
||||||
let uut
|
let uut
|
||||||
|
|||||||
@@ -3,20 +3,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const jsonrpc = require('jsonrpc-lite')
|
import jsonrpc from 'jsonrpc-lite'
|
||||||
const sinon = require('sinon')
|
|
||||||
const assert = require('chai').assert
|
import sinon from 'sinon'
|
||||||
const { v4: uid } = require('uuid')
|
import { assert } from 'chai'
|
||||||
|
import { v4 as uid } from 'uuid'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import AuthRPC from '../../../../src/controllers/json-rpc/auth/index.js'
|
||||||
|
|
||||||
|
import RateLimit from '../../../../src/controllers/json-rpc/rate-limit.js'
|
||||||
|
import adapters from '../../mocks/adapters/index.js'
|
||||||
|
import UseCasesMock from '../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
// Set the environment variable to signal this is a test.
|
// Set the environment variable to signal this is a test.
|
||||||
process.env.SVC_ENV = 'test'
|
process.env.SVC_ENV = 'test'
|
||||||
|
|
||||||
// Local libraries
|
|
||||||
const AuthRPC = require('../../../../src/controllers/json-rpc/auth')
|
|
||||||
const RateLimit = require('../../../../src/controllers/json-rpc/rate-limit')
|
|
||||||
const adapters = require('../../mocks/adapters')
|
|
||||||
const UseCasesMock = require('../../mocks/use-cases')
|
|
||||||
|
|
||||||
describe('#AuthRPC', () => {
|
describe('#AuthRPC', () => {
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -3,19 +3,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const jsonrpc = require('jsonrpc-lite')
|
|
||||||
const sinon = require('sinon')
|
import jsonrpc from 'jsonrpc-lite'
|
||||||
const { v4: uid } = require('uuid')
|
import sinon from 'sinon'
|
||||||
|
import { v4 as uid } from 'uuid'
|
||||||
|
|
||||||
|
// Local libraries.
|
||||||
|
import JSONRPC from '../../../../src/controllers/json-rpc/index.js'
|
||||||
|
|
||||||
|
import adapters from '../../mocks/adapters/index.js'
|
||||||
|
import UseCasesMock from '../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
// Set the environment variable to signal this is a test.
|
// Set the environment variable to signal this is a test.
|
||||||
process.env.SVC_ENV = 'test'
|
process.env.SVC_ENV = 'test'
|
||||||
|
|
||||||
// Local libraries.
|
|
||||||
const JSONRPC = require('../../../../src/controllers/json-rpc')
|
|
||||||
const adapters = require('../../mocks/adapters')
|
|
||||||
const UseCasesMock = require('../../mocks/use-cases')
|
|
||||||
|
|
||||||
describe('#JSON RPC', () => {
|
describe('#JSON RPC', () => {
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -3,19 +3,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const jsonrpc = require('jsonrpc-lite')
|
import jsonrpc from 'jsonrpc-lite'
|
||||||
const sinon = require('sinon')
|
|
||||||
const assert = require('chai').assert
|
import sinon from 'sinon'
|
||||||
const { v4: uid } = require('uuid')
|
import { assert } from 'chai'
|
||||||
|
import { v4 as uid } from 'uuid'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import UserRPC from '../../../../src/controllers/json-rpc/users/index.js'
|
||||||
|
|
||||||
|
import adapters from '../../mocks/adapters/index.js'
|
||||||
|
import UseCasesMock from '../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
// Set the environment variable to signal this is a test.
|
// Set the environment variable to signal this is a test.
|
||||||
process.env.SVC_ENV = 'test'
|
process.env.SVC_ENV = 'test'
|
||||||
|
|
||||||
// Local libraries
|
|
||||||
const UserRPC = require('../../../../src/controllers/json-rpc/users')
|
|
||||||
const adapters = require('../../mocks/adapters')
|
|
||||||
const UseCasesMock = require('../../mocks/use-cases')
|
|
||||||
|
|
||||||
describe('#UserRPC', () => {
|
describe('#UserRPC', () => {
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|||||||
@@ -3,21 +3,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local support libraries
|
// Local support libraries
|
||||||
const adapters = require('../../../mocks/adapters')
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
const UseCasesMock = require('../../../mocks/use-cases')
|
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
// const app = require('../../../mocks/app-mock')
|
// const app = require('../../../mocks/app-mock')
|
||||||
|
|
||||||
const AuthRESTController = require('../../../../../src/controllers/rest-api/auth/controller')
|
import AuthRESTController from '../../../../../src/controllers/rest-api/auth/controller.js'
|
||||||
|
|
||||||
|
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
|
||||||
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
let ctx
|
let ctx
|
||||||
|
|
||||||
const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
|
||||||
|
|
||||||
describe('#Auth-REST-Router', () => {
|
describe('#Auth-REST-Router', () => {
|
||||||
// const testUser = {}
|
// const testUser = {}
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local support libraries
|
// Local support libraries
|
||||||
const adapters = require('../../../mocks/adapters')
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
const UseCasesMock = require('../../../mocks/use-cases')
|
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
// const app = require('../../../mocks/app-mock')
|
// const app = require('../../../mocks/app-mock')
|
||||||
|
|
||||||
const AuthRouter = require('../../../../../src/controllers/rest-api/auth')
|
import AuthRouter from '../../../../../src/controllers/rest-api/auth/index.js'
|
||||||
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
// let ctx
|
// let ctx
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const ContactController = require('../../../../../src/controllers/rest-api/contact/controller')
|
import sinon from 'sinon'
|
||||||
|
import ContactController from '../../../../../src/controllers/rest-api/contact/controller.js'
|
||||||
|
|
||||||
|
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
let ctx
|
let ctx
|
||||||
|
|
||||||
const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
|
||||||
|
|
||||||
describe('Contact', () => {
|
describe('Contact', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,15 +3,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local support libraries
|
// Local support libraries
|
||||||
const adapters = require('../../../mocks/adapters')
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
const UseCasesMock = require('../../../mocks/use-cases')
|
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
// const app = require('../../../mocks/app-mock')
|
// const app = require('../../../mocks/app-mock')
|
||||||
|
|
||||||
const ContactRouter = require('../../../../../src/controllers/rest-api/contact')
|
import ContactRouter from '../../../../../src/controllers/rest-api/contact/index.js'
|
||||||
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
// let ctx
|
// let ctx
|
||||||
|
|||||||
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the REST API handler for the /ipfs endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import IpfsApiController from '../../../../../src/controllers/rest-api/ipfs/controller.js'
|
||||||
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
|
import { context as mockContext } from '../../../mocks/ctx-mock.js'
|
||||||
|
let uut
|
||||||
|
let sandbox
|
||||||
|
let ctx
|
||||||
|
|
||||||
|
describe('#IPFS REST API', () => {
|
||||||
|
before(async () => {
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const useCases = new UseCasesMock()
|
||||||
|
|
||||||
|
uut = new IpfsApiController({ adapters, useCases })
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
ctx = mockContext()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('#constructor', () => {
|
||||||
|
it('should throw an error if adapters are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new IpfsApiController()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Adapters library required when instantiating /ipfs REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error if useCases are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new IpfsApiController({ adapters })
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Use Cases library required when instantiating /ipfs REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#GET /status', () => {
|
||||||
|
it('should return 422 status on biz logic error', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.adapters.ipfs, 'getStatus').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.getStatus(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 422)
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return 200 status on success', async () => {
|
||||||
|
// Mock dependencies
|
||||||
|
sandbox.stub(uut.adapters.ipfs, 'getStatus').resolves({ a: 'b' })
|
||||||
|
|
||||||
|
await uut.getStatus(ctx)
|
||||||
|
// console.log('ctx.body: ', ctx.body)
|
||||||
|
|
||||||
|
assert.property(ctx.body, 'status')
|
||||||
|
assert.equal(ctx.body.status.a, 'b')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#POST /peers', () => {
|
||||||
|
it('should return 422 status on biz logic error', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.adapters.ipfs, 'getPeers').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
ctx.request.body = {
|
||||||
|
showAll: true
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.getPeers(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 422)
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return 200 status on success', async () => {
|
||||||
|
// Mock dependencies
|
||||||
|
sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves({ a: 'b' })
|
||||||
|
|
||||||
|
ctx.request.body = {
|
||||||
|
showAll: true
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.getPeers(ctx)
|
||||||
|
// console.log('ctx.body: ', ctx.body)
|
||||||
|
|
||||||
|
assert.property(ctx.body, 'peers')
|
||||||
|
assert.equal(ctx.body.peers.a, 'b')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#POST /relays', () => {
|
||||||
|
it('should return 422 status on biz logic error', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.adapters.ipfs, 'getRelays').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.getRelays(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 422)
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return 200 status on success', async () => {
|
||||||
|
// Mock dependencies
|
||||||
|
sandbox.stub(uut.adapters.ipfs, 'getRelays').resolves({ a: 'b' })
|
||||||
|
|
||||||
|
await uut.getRelays(ctx)
|
||||||
|
// console.log('ctx.body: ', ctx.body)
|
||||||
|
|
||||||
|
assert.property(ctx.body, 'relays')
|
||||||
|
assert.equal(ctx.body.relays.a, 'b')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#POST /connect', () => {
|
||||||
|
it('should return 422 status on biz logic error', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs, 'connectToPeer').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
ctx.request.body = {
|
||||||
|
multiaddr: '/ip4/161.35.99.207/tcp/4001/p2p/12D3KooWDtj9cfj1SKuLbDNKvKRKSsGN8qivq9M8CYpLPDpcD5pu'
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.connect(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 422)
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return 200 status on success', async () => {
|
||||||
|
// Mock dependencies
|
||||||
|
sandbox.stub(uut.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs, 'connectToPeer').resolves({ success: true })
|
||||||
|
|
||||||
|
ctx.request.body = {
|
||||||
|
multiaddr: '/ip4/161.35.99.207/tcp/4001/p2p/12D3KooWDtj9cfj1SKuLbDNKvKRKSsGN8qivq9M8CYpLPDpcD5pu'
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.connect(ctx)
|
||||||
|
// console.log('ctx.body: ', ctx.body)
|
||||||
|
|
||||||
|
assert.property(ctx.body, 'success')
|
||||||
|
assert.equal(ctx.body.success, true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#handleError', () => {
|
||||||
|
it('should still throw error if there is no message', () => {
|
||||||
|
try {
|
||||||
|
const err = {
|
||||||
|
status: 404
|
||||||
|
}
|
||||||
|
|
||||||
|
uut.handleError(ctx, err)
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Not Found')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error with message', () => {
|
||||||
|
try {
|
||||||
|
const err = {
|
||||||
|
status: 422,
|
||||||
|
message: 'test error'
|
||||||
|
}
|
||||||
|
|
||||||
|
uut.handleError(ctx, err)
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#getThisNode', () => {
|
||||||
|
it('should return 422 status on biz logic error', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
// sandbox.stub(uut.adapters.ipfs.ipfsCoordAdapter.ipfsCoord, 'thisNode').rejects(new Error('test error'))
|
||||||
|
uut.adapters.ipfs.ipfsCoordAdapter = {}
|
||||||
|
|
||||||
|
ctx.request.body = {}
|
||||||
|
|
||||||
|
await uut.getThisNode(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log('err: ', err)
|
||||||
|
assert.equal(err.status, 422)
|
||||||
|
assert.include(err.message, 'Cannot read')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return 200 status on success', async () => {
|
||||||
|
// Mock dependencies
|
||||||
|
// sandbox.stub(uut.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs, 'connectToPeer').resolves({ success: true })
|
||||||
|
|
||||||
|
uut.adapters.ipfs.ipfsCoordAdapter = {
|
||||||
|
ipfsCoord: {
|
||||||
|
thisNode: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.request.body = {}
|
||||||
|
|
||||||
|
await uut.getThisNode(ctx)
|
||||||
|
|
||||||
|
assert.property(ctx.body, 'thisNode')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the REST API handler for the /ipfs endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
// Local support libraries
|
||||||
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
import IpfsRouter from '../../../../../src/controllers/rest-api/ipfs/index.js'
|
||||||
|
// const app = require('../../../mocks/app-mock')
|
||||||
|
|
||||||
|
let uut
|
||||||
|
let sandbox
|
||||||
|
// let ctx
|
||||||
|
|
||||||
|
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
||||||
|
|
||||||
|
describe('#IPFS-REST-Router', () => {
|
||||||
|
// const testUser = {}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const useCases = new UseCasesMock()
|
||||||
|
uut = new IpfsRouter({ adapters, useCases })
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
// ctx = mockContext()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('#constructor', () => {
|
||||||
|
it('should throw an error if adapters are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new IpfsRouter()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Adapters library required when instantiating IPFS REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error if useCases are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new IpfsRouter({ adapters })
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Use Cases library required when instantiating IPFS REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#attach', () => {
|
||||||
|
it('should throw an error if app is not passed in.', () => {
|
||||||
|
try {
|
||||||
|
uut.attach()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Must pass app object when attaching REST API controllers.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -3,16 +3,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const LogsApiController = require('../../../../../src/controllers/rest-api/logs/controller')
|
import sinon from 'sinon'
|
||||||
|
import LogsApiController from '../../../../../src/controllers/rest-api/logs/controller.js'
|
||||||
|
|
||||||
|
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
let ctx
|
let ctx
|
||||||
|
|
||||||
const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
|
||||||
|
|
||||||
describe('Logapi', () => {
|
describe('Logapi', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,15 +3,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local support libraries
|
// Local support libraries
|
||||||
const adapters = require('../../../mocks/adapters')
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
const UseCasesMock = require('../../../mocks/use-cases')
|
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
// const app = require('../../../mocks/app-mock')
|
// const app = require('../../../mocks/app-mock')
|
||||||
|
|
||||||
const LogsRouter = require('../../../../../src/controllers/rest-api/logs')
|
import LogsRouter from '../../../../../src/controllers/rest-api/logs/index.js'
|
||||||
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
// let ctx
|
// let ctx
|
||||||
|
|||||||
@@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the REST API middleware that validates users.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import Validators from '../../../../../src/controllers/rest-api/middleware/validators.js'
|
||||||
|
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
|
||||||
|
|
||||||
|
describe('#Validators', () => {
|
||||||
|
let uut
|
||||||
|
let ctx
|
||||||
|
let sandbox
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new Validators()
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
ctx = mockContext()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('#getToken', () => {
|
||||||
|
it('should return null if no header is provided', () => {
|
||||||
|
const result = uut.getToken(ctx)
|
||||||
|
|
||||||
|
assert.equal(result, null)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return null if header is not in two parts', () => {
|
||||||
|
ctx.request.header.authorization = 'Bearer'
|
||||||
|
|
||||||
|
const result = uut.getToken(ctx)
|
||||||
|
|
||||||
|
assert.equal(result, null)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return null if first part of header does not container the word bearer', () => {
|
||||||
|
ctx.request.header.authorization = 'some thing'
|
||||||
|
|
||||||
|
const result = uut.getToken(ctx)
|
||||||
|
|
||||||
|
assert.equal(result, null)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return the JWT token from the header', () => {
|
||||||
|
const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYzMjNiNTUwNzgxYWYzNTc4YzI0ZmU5YiIsImlhdCI6MTY2MzQ0NDczNCwiZXhwIjoxNjYzNTMxMTM0fQ.BY5sOfXc4z5axS98CdTfyqnO9y2wijOlwnv52rcvxHA'
|
||||||
|
ctx.request.header.authorization = `Bearer ${jwt}`
|
||||||
|
|
||||||
|
const result = uut.getToken(ctx)
|
||||||
|
|
||||||
|
assert.equal(result, jwt)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#ensureUser', () => {
|
||||||
|
it('should throw error if token is not provided', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns()
|
||||||
|
|
||||||
|
await uut.ensureUser(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if token can not be verified', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').throws(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.ensureUser(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if user can not be found in database', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves(false)
|
||||||
|
|
||||||
|
await uut.ensureUser(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true if the user is verified', async () => {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves({ user: 'alice' })
|
||||||
|
|
||||||
|
const result = await uut.ensureUser(ctx)
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#ensureUser', () => {
|
||||||
|
it('should throw error if token is not provided', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns()
|
||||||
|
|
||||||
|
await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if token can not be verified', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').throws(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if user can not be found in database', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves(false)
|
||||||
|
|
||||||
|
await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if user is not an admin', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves({ type: 'user' })
|
||||||
|
|
||||||
|
await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true if the user is an admin', async () => {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves({ type: 'admin' })
|
||||||
|
|
||||||
|
const result = await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#ensureTargetUserOrAdmin', () => {
|
||||||
|
it('should throw error if token is not provided', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns()
|
||||||
|
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if token can not be verified', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').throws(new Error('test error'))
|
||||||
|
|
||||||
|
ctx.params = {
|
||||||
|
id: '456'
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if user can not be found in database', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves(false)
|
||||||
|
|
||||||
|
ctx.params = {
|
||||||
|
id: '456'
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if user is not an admin', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves({ type: 'user' })
|
||||||
|
|
||||||
|
ctx.params = {
|
||||||
|
id: '456'
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error is user is not admin or target user', async () => {
|
||||||
|
try {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves({ type: 'user', _id: '123' })
|
||||||
|
|
||||||
|
ctx.params = {
|
||||||
|
id: '456'
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(ctx.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true if the user is an admin', async () => {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves({ type: 'admin', _id: '123' })
|
||||||
|
|
||||||
|
ctx.params = {
|
||||||
|
id: '456'
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true if the user is the target user', async () => {
|
||||||
|
// Mock dependencies and force desired code path
|
||||||
|
sandbox.stub(uut, 'getToken').returns('fake-jwt')
|
||||||
|
sandbox.stub(uut.jwt, 'verify').returns({})
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves({ type: 'user', _id: '123' })
|
||||||
|
|
||||||
|
ctx.params = {
|
||||||
|
id: '123'
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -3,14 +3,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const RESTControllers = require('../../../../src/controllers/rest-api/')
|
import RESTControllers from '../../../../src/controllers/rest-api/index.js'
|
||||||
|
|
||||||
// const mockContext = require('../../../unit/mocks/ctx-mock').context
|
// const mockContext = require('../../../unit/mocks/ctx-mock').context
|
||||||
const adapters = require('../../mocks/adapters')
|
import adapters from '../../mocks/adapters/index.js'
|
||||||
const UseCasesMock = require('../../mocks/use-cases')
|
|
||||||
|
import UseCasesMock from '../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
describe('#RESTControllers', () => {
|
describe('#RESTControllers', () => {
|
||||||
let uut
|
let uut
|
||||||
|
|||||||
@@ -3,20 +3,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local support libraries
|
// Local support libraries
|
||||||
const adapters = require('../../../mocks/adapters')
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
const UseCasesMock = require('../../../mocks/use-cases')
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
import UserController from '../../../../../src/controllers/rest-api/users/controller.js'
|
||||||
|
|
||||||
const UserController = require('../../../../../src/controllers/rest-api/users/controller')
|
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
let ctx
|
let ctx
|
||||||
|
|
||||||
const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
|
||||||
|
|
||||||
describe('#Users-REST-Controller', () => {
|
describe('#Users-REST-Controller', () => {
|
||||||
// const testUser = {}
|
// const testUser = {}
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local support libraries
|
// Local support libraries
|
||||||
const adapters = require('../../../mocks/adapters')
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
const UseCasesMock = require('../../../mocks/use-cases')
|
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
// const app = require('../../../mocks/app-mock')
|
// const app = require('../../../mocks/app-mock')
|
||||||
|
|
||||||
const UserRouter = require('../../../../../src/controllers/rest-api/users')
|
import UserRouter from '../../../../../src/controllers/rest-api/users/index.js'
|
||||||
|
|
||||||
let uut
|
let uut
|
||||||
let sandbox
|
let sandbox
|
||||||
// let ctx
|
// let ctx
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the timer-controller.js Controller library
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import TimerControllers from '../../../src/controllers/timer-controllers.js'
|
||||||
|
import adapters from '../mocks/adapters/index.js'
|
||||||
|
import UseCasesMock from '../mocks/use-cases/index.js'
|
||||||
|
|
||||||
|
describe('#Timer-Controllers', () => {
|
||||||
|
let uut
|
||||||
|
let sandbox
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
|
||||||
|
const useCases = new UseCasesMock()
|
||||||
|
uut = new TimerControllers({ adapters, useCases })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
sandbox.restore()
|
||||||
|
|
||||||
|
uut.stopTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#constructor', () => {
|
||||||
|
it('should throw an error if adapters are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new TimerControllers()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Adapters library required when instantiating Timer Controller libraries.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error if useCases are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new TimerControllers({ adapters })
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Use Cases library required when instantiating Timer Controller libraries.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#startTimers', () => {
|
||||||
|
it('should start the timers', () => {
|
||||||
|
const result = uut.startTimers()
|
||||||
|
|
||||||
|
uut.stopTimers()
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#exampleTimerFunc', () => {
|
||||||
|
it('should kick off the Use Case', async () => {
|
||||||
|
const result = await uut.exampleTimerFunc()
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false on error', async () => {
|
||||||
|
const result = await uut.exampleTimerFunc(true)
|
||||||
|
|
||||||
|
assert.equal(result, false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
Unit tests for the User entity library.
|
Unit tests for the User entity library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const User = require('../../../src/entities/user')
|
import sinon from 'sinon'
|
||||||
|
import User from '../../../src/entities/user.js'
|
||||||
|
|
||||||
let sandbox
|
let sandbox
|
||||||
let uut
|
let uut
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the config directory
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
let currentEnv
|
||||||
|
|
||||||
|
describe('#config', () => {
|
||||||
|
before(() => {
|
||||||
|
// Backup the current environment setting.
|
||||||
|
currentEnv = process.env.SVC_ENV
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
// Restore the environment setting before starting these tests.
|
||||||
|
process.env.SVC_ENV = currentEnv
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should return development environment config by default', async () => {
|
||||||
|
const importedConfig = await import('../../../config/index.js')
|
||||||
|
const config = importedConfig.default
|
||||||
|
// console.log('config: ', config)
|
||||||
|
|
||||||
|
assert.equal(config.env, 'dev')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should return test environment config', async () => {
|
||||||
|
// Hack to dynamically import a library multiple times:
|
||||||
|
// https://github.com/denoland/deno/issues/6946
|
||||||
|
|
||||||
|
process.env.SVC_ENV = 'test'
|
||||||
|
|
||||||
|
const importedConfig2 = await import('../../../config/index.js?foo=bar1')
|
||||||
|
const config = importedConfig2.default
|
||||||
|
// console.log('config: ', config)
|
||||||
|
|
||||||
|
assert.equal(config.env, 'test')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should return test environment config', async () => {
|
||||||
|
process.env.SVC_ENV = 'prod'
|
||||||
|
|
||||||
|
const importedConfig3 = await import('../../../config/index.js?foo=bar2')
|
||||||
|
const config = importedConfig3.default
|
||||||
|
// console.log('config: ', config)
|
||||||
|
|
||||||
|
assert.equal(config.env, 'prod')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -3,13 +3,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
// const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
import passport from 'koa-passport'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const User = require('../../../src/adapters/localdb/models/users')
|
import User from '../../../src/adapters/localdb/models/users.js'
|
||||||
const { passport, passportCallback } = require('../../../config/passport')
|
|
||||||
const adaptersMock = require('../mocks/adapters')
|
import { applyPassportMods, passportCallback } from '../../../config/passport.js'
|
||||||
|
import adaptersMock from '../mocks/adapters/index.js'
|
||||||
|
|
||||||
describe('#passport', () => {
|
describe('#passport', () => {
|
||||||
let sandbox
|
let sandbox
|
||||||
@@ -25,33 +27,6 @@ describe('#passport', () => {
|
|||||||
|
|
||||||
afterEach(() => sandbox.restore())
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
describe('#serializeUser', () => {
|
|
||||||
it('should serialize a user', () => {
|
|
||||||
const user = {
|
|
||||||
id: 'abc123'
|
|
||||||
}
|
|
||||||
const done = () => {}
|
|
||||||
|
|
||||||
passport.serializeUser(user, done)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#deserializeUser', () => {
|
|
||||||
it('should deserialize a user', () => {
|
|
||||||
// Mock Users model.
|
|
||||||
sandbox.stub(User, 'findById').resolves({ id })
|
|
||||||
|
|
||||||
passport.deserializeUser(id, done)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should catch and handle errors', () => {
|
|
||||||
// Force an error
|
|
||||||
sandbox.stub(User, 'findById').rejects(new Error('test error'))
|
|
||||||
|
|
||||||
passport.deserializeUser(id, done)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#passportCallback', () => {
|
describe('#passportCallback', () => {
|
||||||
it('should return if user is found', () => {
|
it('should return if user is found', () => {
|
||||||
// Mock Users model.
|
// Mock Users model.
|
||||||
@@ -74,4 +49,45 @@ describe('#passport', () => {
|
|||||||
passportCallback(id, 'password', done)
|
passportCallback(id, 'password', done)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#applyPassportMods', () => {
|
||||||
|
it('should apply modifications to default passport behavior', () => {
|
||||||
|
const result = applyPassportMods(passport)
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#serializeUser', () => {
|
||||||
|
it('should serialize a user', () => {
|
||||||
|
const user = {
|
||||||
|
id: 'abc123'
|
||||||
|
}
|
||||||
|
const done = () => {}
|
||||||
|
|
||||||
|
applyPassportMods(passport)
|
||||||
|
|
||||||
|
passport.serializeUser(user, done)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#deserializeUser', () => {
|
||||||
|
it('should deserialize a user', () => {
|
||||||
|
// Mock Users model.
|
||||||
|
sandbox.stub(User, 'findById').resolves({ id })
|
||||||
|
|
||||||
|
applyPassportMods(passport)
|
||||||
|
|
||||||
|
passport.deserializeUser(id, done)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should catch and handle errors', () => {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(User, 'findById').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
applyPassportMods(passport)
|
||||||
|
|
||||||
|
passport.deserializeUser(id, done)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import { assert } from 'chai'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const Server = require('../../../bin/server')
|
import Server from '../../../bin/server.js'
|
||||||
|
|
||||||
describe('#server', () => {
|
describe('#server', () => {
|
||||||
let uut, sandbox
|
let uut, sandbox
|
||||||
|
|||||||
@@ -15,18 +15,27 @@ class IpfsAdapter {
|
|||||||
class IpfsCoordAdapter {
|
class IpfsCoordAdapter {
|
||||||
constructor () {
|
constructor () {
|
||||||
this.ipfsCoord = {
|
this.ipfsCoord = {
|
||||||
|
adapters: {
|
||||||
|
ipfs: {
|
||||||
|
connectToPeer: async () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
useCases: {
|
useCases: {
|
||||||
peer: {
|
peer: {
|
||||||
sendPrivateMessage: () => {}
|
sendPrivateMessage: () => {}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
thisNode: {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ipfs = {
|
const ipfs = {
|
||||||
ipfsAdapter: new IpfsAdapter(),
|
ipfsAdapter: new IpfsAdapter(),
|
||||||
ipfsCoordAdapter: new IpfsCoordAdapter()
|
ipfsCoordAdapter: new IpfsCoordAdapter(),
|
||||||
|
getStatus: async () => {},
|
||||||
|
getPeers: async () => {},
|
||||||
|
getRelays: async () => {}
|
||||||
}
|
}
|
||||||
ipfs.ipfs = ipfs.ipfsAdapter.ipfs
|
ipfs.ipfs = ipfs.ipfsAdapter.ipfs
|
||||||
|
|
||||||
@@ -94,4 +103,4 @@ const bchjs = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { ipfs, localdb, bchjs }
|
export default { ipfs, localdb, bchjs };
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ const app = {
|
|||||||
use: () => {}
|
use: () => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = app
|
export default app;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user