Refactored JSON RPC validation library

This commit is contained in:
Chris Troutner
2021-07-10 09:57:25 -07:00
parent bf357443aa
commit 2667002b0d
4 changed files with 84 additions and 54 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ class UserRPC {
// Encapsulate dependencies
this.userLib = this.useCases.user
this.jsonrpc = jsonrpc
this.validators = new Validators()
this.validators = new Validators(localConfig)
this.rateLimit = new RateLimit()
}
+12 -4
View File
@@ -8,14 +8,22 @@ const jwt = require('jsonwebtoken')
// Local libraries
const config = require('../../../config')
const UserModel = require('../../adapters/localdb/models/users')
// const UserModel = require('../../adapters/localdb/models/users')
class Validators {
constructor () {
constructor (localConfig = {}) {
// Dependency Injection.
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of Adapters library required when instantiating JSON RPC Validators library.'
)
}
// Encapsulate dependencies
this.config = config
this.UserModel = UserModel
this.jwt = jwt
this.UserModel = this.adapters.localdb.Users
}
// Returns if user passes a valid JWT token that resolves to a valid user.
@@ -63,7 +71,7 @@ class Validators {
if (!user) throw new Error('User not found!')
// If this current user is an admin, then quietly exit.
if (user.type === 'admin') return
if (user.type === 'admin') return true
// Throw an error if the JWT token does not match the targeted user.
if (user._id.toString() !== targetUserId) {
+64 -48
View File
@@ -6,7 +6,6 @@
// 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')
@@ -15,49 +14,34 @@ const { v4: uid } = require('uuid')
process.env.SVC_ENV = 'test'
// Local libraries
const config = require('../../../config')
const Validators = require('../../../src/controllers/json-rpc/validators')
const UserLib = require('../../../src/use-cases/user')
const userLib = new UserLib()
const adapters = require('../mocks/adapters')
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()
uut = new Validators({ adapters })
})
afterEach(() => sandbox.restore())
after(async () => {
// Delete the test user.
testUser = await userLib.getUser({ id: testUser.userData._id })
await userLib.deleteUser(testUser)
describe('#constructor', () => {
it('should throw an error if adapters is not passed in.', () => {
try {
uut = new Validators()
mongoose.connection.close()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating JSON RPC Validators library.'
)
}
})
})
describe('#ensureUser', () => {
@@ -67,18 +51,20 @@ describe('#validators', () => {
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'getAll',
apiToken: testUser.token
apiToken: 'fakeJWTToken'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
sandbox.stub(uut.UserModel, 'findById').resolves(true)
const user = await uut.ensureUser(rpcData)
// console.log('user: ', user)
assert.property(user, 'type')
assert.property(user, '_id')
assert.property(user, 'email')
assert.property(user, 'name')
// For this test, we return a value of 'true' instead of actual user data.
assert.equal(user, true)
})
it('should throw an error if JWT token is not included', async () => {
@@ -129,13 +115,14 @@ describe('#validators', () => {
try {
// Force 'error not found' error
sandbox.stub(uut.UserModel, 'findById').resolves(null)
sandbox.stub(uut.jwt, 'verify').returns(true)
// 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
apiToken: 'fakeJWTToken'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
@@ -157,18 +144,21 @@ describe('#validators', () => {
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: testUser.token,
userId: testUser.userData._id.toString()
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const user = await uut.ensureTargetUserOrAdmin(rpcData)
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
sandbox.stub(uut.UserModel, 'findById').resolves({ _id: 'abc123' })
assert.property(user, 'type')
assert.property(user, '_id')
assert.property(user, 'email')
assert.property(user, 'name')
const user = await uut.ensureTargetUserOrAdmin(rpcData)
// console.log('user: ', user)
// Assert that the mocked data expected is returned.
assert.equal(user._id, 'abc123')
})
it('should throw error if JWT token is not provided', async () => {
@@ -198,7 +188,7 @@ describe('#validators', () => {
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: testUser.token
apiToken: 'fakeJWTToken'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
@@ -223,7 +213,7 @@ describe('#validators', () => {
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: token,
userId: testUser.userData._id.toString()
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
@@ -247,12 +237,15 @@ describe('#validators', () => {
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: testUser.token,
userId: testUser.userData._id.toString()
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
await uut.ensureTargetUserOrAdmin(rpcData)
assert.fail('Unexpected code path')
@@ -262,6 +255,29 @@ describe('#validators', () => {
}
})
// TODO: it should exit quietly if user is an admin.
it('should return true if user is an admin', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const userCall = jsonrpc.request(id, 'users', {
endpoint: 'deleteUser',
apiToken: 'fakeJWTToken',
userId: 'abc123'
})
const jsonStr = JSON.stringify(userCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
// Mock external dependencies.
sandbox.stub(uut.jwt, 'verify').returns(true)
sandbox
.stub(uut.UserModel, 'findById')
.resolves({ _id: 'abc123', type: 'admin' })
const user = await uut.ensureTargetUserOrAdmin(rpcData)
// console.log('user: ', user)
// Assert that the mocked data expected is returned.
assert.equal(user, true)
})
})
})
+7 -1
View File
@@ -11,4 +11,10 @@ const ipfs = {
}
}
module.exports = { ipfs }
const localdb = {
Users: class Users {
static findById () {}
}
}
module.exports = { ipfs, localdb }