diff --git a/src/adapters/localdb/models/users.js b/src/adapters/localdb/models/users.js index b8e0b0f..869e303 100644 --- a/src/adapters/localdb/models/users.js +++ b/src/adapters/localdb/models/users.js @@ -11,60 +11,33 @@ const User = new mongoose.Schema({ email: { type: String, required: true, - unique: true, - validate: { - validator: function (email) { - // eslint-disable-next-line no-useless-escape - return /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email) - }, - message: props => `${props.value} is not a valid Email format!` - } + unique: true } }) // Before saving, convert the password to a hash. -User.pre('save', function preSave (next) { +User.pre('save', async function preSave (next) { const user = this if (!user.isModified('password')) { return next() } - new Promise((resolve, reject) => { - bcrypt.genSalt(10, (err, salt) => { - if (err) { - return reject(err) - } - resolve(salt) - }) - }) - .then(salt => { - bcrypt.hash(user.password, salt, (err, hash) => { - if (err) { - throw new Error(err) - } + const salt = await bcrypt.genSalt(10) + const hash = await bcrypt.hash(user.password, salt) - user.password = hash + user.password = hash - next(null) - }) - }) - .catch(err => next(err)) + next(null) }) // Validate the password by comparing to the saved hash. -User.methods.validatePassword = function validatePassword (password) { +User.methods.validatePassword = async function validatePassword (password) { const user = this - return new Promise((resolve, reject) => { - bcrypt.compare(password, user.password, (err, isMatch) => { - if (err) { - return reject(err) - } + const isMatch = await bcrypt.compare(password, user.password) - resolve(isMatch) - }) - }) + return isMatch } // Generate a JWT token. diff --git a/src/controllers/json-rpc/index.js b/src/controllers/json-rpc/index.js index 73096f8..ef6bddf 100644 --- a/src/controllers/json-rpc/index.js +++ b/src/controllers/json-rpc/index.js @@ -110,25 +110,13 @@ class JSONRPC { // The default JSON RPC response if the incoming command could not be routed. defaultResponse () { - try { - // const errorObj = this.jsonrpc.error( - // 'Can not route', - // new jsonrpc.JsonRpcError('Input does not match routing rules', 422) - // ) - // const errorStr = JSON.stringify(errorObj) - // return errorStr - - const errorObj = { - success: false, - status: 422, - message: 'Input does not match routing rules.' - } - - return errorObj - } catch (err) { - console.error('Error in defaultResponse()') - throw err + const errorObj = { + success: false, + status: 422, + message: 'Input does not match routing rules.' } + + return errorObj } } diff --git a/test/unit/adapters/users.adapter.unit.js b/test/unit/adapters/users.adapter.unit.js new file mode 100644 index 0000000..cc788db --- /dev/null +++ b/test/unit/adapters/users.adapter.unit.js @@ -0,0 +1,82 @@ +/* + Unit tests for the users Mongoose model. +*/ + +const assert = require('chai').assert +const sinon = require('sinon') +const mongoose = require('mongoose') + +// Set the environment variable to signal this is a test. +process.env.SVC_ENV = 'test' + +const User = require('../../../src/adapters/localdb/models/users') +const config = require('../../../config') + +describe('#User-Adapter', () => { + // let uut + let sandbox + let testuser + + before(async () => { + // Connect to the Mongo Database. + console.log(`Connecting to database: ${config.database}`) + mongoose.Promise = global.Promise + mongoose.set('useCreateIndex', true) // Stop deprecation warning. + await mongoose.connect(config.database, { + useUnifiedTopology: true, + useNewUrlParser: true + }) + + testuser = new User({ + email: 'test983@test.com', + name: 'test983', + password: 'password' + }) + }) + + beforeEach(async () => { + sandbox = sinon.createSandbox() + }) + + afterEach(() => sandbox.restore()) + + after(async () => { + await testuser.remove() + + mongoose.connection.close() + }) + + describe('#save', () => { + it('should replace the password with a salt', async () => { + await testuser.save() + // console.log('testuser: ', testuser) + + assert.notEqual(testuser.password, 'password') + }) + }) + + describe('#validatePassword', () => { + it('should return true when password matches', async () => { + const result = await testuser.validatePassword('password') + // console.log('result: ', result) + + assert.equal(result, true) + }) + + it('should return false when password does not match', async () => { + const result = await testuser.validatePassword('wrongpassword') + // console.log('result: ', result) + + assert.equal(result, false) + }) + }) + + describe('#generateToken', () => { + it('should generate a JWT token', () => { + const token = testuser.generateToken() + // console.log('token: ', token) + + assert.include(token, 'eyJ') + }) + }) +}) diff --git a/test/unit/controllers/controllers.unit.js b/test/unit/controllers/controllers.unit.js new file mode 100644 index 0000000..7600abc --- /dev/null +++ b/test/unit/controllers/controllers.unit.js @@ -0,0 +1,37 @@ +/* + Unit tests for controllers index.js file. +*/ + +// Public npm libraries +// const assert = require('chai').assert +const sinon = require('sinon') + +const adapters = require('../../../src/adapters') +const { attachControllers } = require('../../../src/controllers') + +describe('#Controllers', () => { + // let uut + let sandbox + + beforeEach(() => { + sandbox = sinon.createSandbox() + }) + + afterEach(() => sandbox.restore()) + + describe('#attachControllers', () => { + it('should attach the controllers', async () => { + // mock IPFS + sandbox.stub(adapters.ipfs, 'start').resolves({}) + adapters.ipfs.ipfsCoordAdapter = { + attachRPCRouter: () => {} + } + + const app = { + use: () => {} + } + + await attachControllers(app) + }) + }) +}) diff --git a/test/unit/controllers/json-rpc/a10-rpc.unit.js b/test/unit/controllers/json-rpc/a10-rpc.unit.js index 1d6f218..ce63523 100644 --- a/test/unit/controllers/json-rpc/a10-rpc.unit.js +++ b/test/unit/controllers/json-rpc/a10-rpc.unit.js @@ -29,6 +29,34 @@ describe('#JSON RPC', () => { afterEach(() => sandbox.restore()) + describe('#constructor', () => { + it('should throw an error if adapters are not passed in', () => { + try { + uut = new JSONRPC() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Adapters library required when instantiating JSON RPC Controllers.' + ) + } + }) + + it('should throw an error if useCases are not passed in', () => { + try { + uut = new JSONRPC({ adapters }) + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Use Cases library required when instantiating JSON RPC Controllers.' + ) + } + }) + }) + describe('#router', () => { it('should exit quietly if given a random string', async () => { const str = 'random string message' @@ -106,5 +134,50 @@ describe('#JSON RPC', () => { assert.equal(obj.result.method, 'users') assert.equal(obj.id, id) }) + + it('should route to auth handler', async () => { + const id = uid() + const userCall = jsonrpc.request(id, 'auth', { endpoint: 'getAll' }) + const jsonStr = JSON.stringify(userCall, null, 2) + + // Mock the controller. + sandbox.stub(uut.authController, 'authRouter').resolves('true') + + const result = await uut.router(jsonStr, 'peerA') + // console.log(result) + + const obj = JSON.parse(result.retStr) + // console.log('obj: ', obj) + + assert.equal(obj.result.value, 'true') + assert.equal(obj.result.method, 'auth') + assert.equal(obj.id, id) + }) + + it('should route to about handler', async () => { + const id = uid() + const userCall = jsonrpc.request(id, 'about', { endpoint: 'getAll' }) + const jsonStr = JSON.stringify(userCall, null, 2) + + // Mock the controller. + sandbox.stub(uut.aboutController, 'aboutRouter').resolves('true') + + // Force ipfs-coord communication. + uut.ipfsCoord.ipfs = { + orbitdb: { + sendToDb: () => {} + } + } + + const result = await uut.router(jsonStr, 'peerA') + // console.log(result) + + const obj = JSON.parse(result.retStr) + // console.log('obj: ', obj) + + assert.equal(obj.result.value, 'true') + assert.equal(obj.result.method, 'about') + assert.equal(obj.id, id) + }) }) })