mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex.git
synced 2026-09-21 16:52:00 -07:00
feat(JSON RPC): Adding validator middleware
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
REST API validator middleware.
|
||||
*/
|
||||
|
||||
const User = require('../models/users')
|
||||
const config = require('../../config')
|
||||
const getToken = require('../lib/auth')
|
||||
|
||||
@@ -7,12 +7,14 @@ const jsonrpc = require('jsonrpc-lite')
|
||||
|
||||
// Local libraries
|
||||
const UserLib = require('../../lib/users')
|
||||
const Validators = require('../validators')
|
||||
|
||||
class UserRPC {
|
||||
constructor (localConfig) {
|
||||
// Encapsulate dependencies
|
||||
this.userLib = new UserLib()
|
||||
this.jsonrpc = jsonrpc
|
||||
this.validators = new Validators()
|
||||
}
|
||||
|
||||
// Top-level router for this library. All other methods in this class are for
|
||||
@@ -27,7 +29,8 @@ class UserRPC {
|
||||
// Route the call based on the value of the method property.
|
||||
switch (endpoint) {
|
||||
case 'getAll':
|
||||
return await this.getAll()
|
||||
// await this.validators.ensureUser(rpcData)
|
||||
return await this.getAll(rpcData)
|
||||
case 'getUser':
|
||||
return await this.getUser(rpcData)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Validators for the JSON RPC
|
||||
*/
|
||||
/* eslint no-useless-catch: 0 */
|
||||
|
||||
// Public npm libraries
|
||||
const jwt = require('jsonwebtoken')
|
||||
|
||||
// Local libraries
|
||||
const config = require('../../config')
|
||||
const UserModel = require('../models/users')
|
||||
|
||||
class Validators {
|
||||
constructor () {
|
||||
// Encapsulate dependencies
|
||||
this.config = config
|
||||
this.UserModel = UserModel
|
||||
this.jwt = jwt
|
||||
}
|
||||
|
||||
// Returns if user passes a valid JWT token. Otherwise it throws an error.
|
||||
async ensureUser (rpcData) {
|
||||
try {
|
||||
// console.log('rpcData: ', rpcData)
|
||||
|
||||
const apiToken = rpcData.payload.params.apiToken
|
||||
if (!apiToken) throw new Error('apiToken JWT required as a parameter')
|
||||
|
||||
const decoded = this.jwt.verify(apiToken, this.config.token)
|
||||
|
||||
const user = await this.UserModel.findById(decoded.id, '-password')
|
||||
if (!user) throw new Error('User not found!')
|
||||
} catch (err) {
|
||||
// console.error('Error in ensureUser()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Validators
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
Unit tests for the JSON RPC validator middleware.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
const jsonrpc = require('jsonrpc-lite')
|
||||
const mongoose = require('mongoose')
|
||||
const sinon = require('sinon')
|
||||
const assert = require('chai').assert
|
||||
const { v4: uid } = require('uuid')
|
||||
|
||||
// Set the environment variable to signal this is a test.
|
||||
process.env.SVC_ENV = 'test'
|
||||
|
||||
// Local libraries
|
||||
const config = require('../../../config')
|
||||
const Validators = require('../../../src/rpc/validators')
|
||||
const UserLib = require('../../../src/lib/users')
|
||||
const userLib = new UserLib()
|
||||
|
||||
describe('#validators', () => {
|
||||
let testUser
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
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
|
||||
}
|
||||
)
|
||||
|
||||
// Create a test user.
|
||||
testUser = await userLib.createUser({
|
||||
email: 'test544@test.com',
|
||||
name: 'tester544',
|
||||
password: 'password'
|
||||
})
|
||||
// console.log('testUser: ', testUser)
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
uut = new Validators()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
after(async () => {
|
||||
// Delete the test user.
|
||||
testUser = await userLib.getUser({ id: testUser.userData._id })
|
||||
await userLib.deleteUser(testUser)
|
||||
|
||||
mongoose.connection.close()
|
||||
})
|
||||
|
||||
describe('#ensureUser', () => {
|
||||
it('should return quietly for valid JWT token', async () => {
|
||||
// Generate the parsed data that the main router would pass to this
|
||||
// endpoint.
|
||||
const id = uid()
|
||||
const userCall = jsonrpc.request(id, 'users', {
|
||||
endpoint: 'getAll',
|
||||
apiToken: testUser.token
|
||||
})
|
||||
const jsonStr = JSON.stringify(userCall, null, 2)
|
||||
const rpcData = jsonrpc.parse(jsonStr)
|
||||
|
||||
await uut.ensureUser(rpcData)
|
||||
|
||||
assert.isOk('Not throwing an error is a success!')
|
||||
})
|
||||
|
||||
it('should throw an error if JWT token is not included', async () => {
|
||||
try {
|
||||
// Generate the parsed data that the main router would pass to this
|
||||
// endpoint.
|
||||
const id = uid()
|
||||
const userCall = jsonrpc.request(id, 'users', {
|
||||
endpoint: 'getAll'
|
||||
})
|
||||
const jsonStr = JSON.stringify(userCall, null, 2)
|
||||
const rpcData = jsonrpc.parse(jsonStr)
|
||||
|
||||
await uut.ensureUser(rpcData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, 'apiToken JWT required as a parameter')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if JWT token can not be decoded', async () => {
|
||||
try {
|
||||
const token =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYwNmQxYTlkNTgxNTVjMjIzNWFmMTNhMSIsImlhdCI6MTYxNzc2Mjk3M30.6JkM1v0n71Mzsd3qzClzlMKtq6HlD0umoauG23N9FFF'
|
||||
|
||||
// Generate the parsed data that the main router would pass to this
|
||||
// endpoint.
|
||||
const id = uid()
|
||||
const userCall = jsonrpc.request(id, 'users', {
|
||||
endpoint: 'getAll',
|
||||
apiToken: token
|
||||
})
|
||||
const jsonStr = JSON.stringify(userCall, null, 2)
|
||||
const rpcData = jsonrpc.parse(jsonStr)
|
||||
|
||||
await uut.ensureUser(rpcData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, 'invalid signature')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if the user can not be found', async () => {
|
||||
try {
|
||||
// Force 'error not found' error
|
||||
sandbox.stub(uut.UserModel, 'findById').resolves(null)
|
||||
|
||||
// Generate the parsed data that the main router would pass to this
|
||||
// endpoint.
|
||||
const id = uid()
|
||||
const userCall = jsonrpc.request(id, 'users', {
|
||||
endpoint: 'getAll',
|
||||
apiToken: testUser.token
|
||||
})
|
||||
const jsonStr = JSON.stringify(userCall, null, 2)
|
||||
const rpcData = jsonrpc.parse(jsonStr)
|
||||
|
||||
await uut.ensureUser(rpcData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, 'User not found!')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user