UNPKG

meshblu-authenticator-core

Version:

[![Build Status](https://travis-ci.org/octoblu/meshblu-authenticator-core.svg?branch=master)](https://travis-ci.org/octoblu/meshblu-authenticator-core) [![Test Coverage](https://codecov.io/gh/octoblu/meshblu-authenticator-core/branch/master/graph/badge.sv

392 lines (304 loc) 15.4 kB
DeviceAuthenticator = require '../../src/device-authenticator' bcrypt = require 'bcrypt' describe 'DeviceAuthenticator', -> beforeEach -> @meshbluHttp = sign: sinon.stub() devices: sinon.stub() register: sinon.stub() update: sinon.stub() verify: sinon.stub() search: sinon.stub() describe '->buildDeviceUpdate', -> beforeEach -> authenticatorUuid = '1' authenticatorName = 'name' @sut = new DeviceAuthenticator {authenticatorUuid, authenticatorName, @meshbluHttp} describe 'when called with data', -> beforeEach -> @result = @sut.buildDeviceUpdate {deviceUuid: "auuid", owner: "auuid", user_id: '1', hashedSecret: "pretendyoucantreadthis"} it 'should call meshblu.sign', -> expect(@meshbluHttp.sign).to.have.been.calledWith {id: '1', name: 'name', secret: 'pretendyoucantreadthis'} it 'should set the owner', -> expect(@result.owner).to.equal "auuid" describe '->create', -> beforeEach -> authenticatorUuid = 'auth-id' authenticatorName = 'authenticator' @sut = new DeviceAuthenticator {authenticatorUuid, authenticatorName, @meshbluHttp} describe 'calling exists', -> beforeEach -> @sut.exists = sinon.spy() @sut.create {query: {'google.id': '959'}, data: {}, secret: 'secret'} it 'should call exists', -> expect(@sut.exists).to.have.been.calledWith query: {'google.id' : '959'} describe 'when exists yields true', -> beforeEach (done) -> @sut.exists = sinon.stub().yields true @sut.insert = sinon.stub().yields new Error DeviceAuthenticator.ERROR_DEVICE_ALREADY_EXISTS @sut.create {query: {'google.id': '595'}, data: {}, user_id: 'id', secret: 'secret'}, (@error) => done() it 'should have a device already exists error', -> expect(@error.message).to.equal DeviceAuthenticator.ERROR_DEVICE_ALREADY_EXISTS describe 'when exists yields false', -> beforeEach -> @sut.exists = sinon.stub().yields false @sut.insert = sinon.spy() @sut.create {query: {'google.id': '595'}, data: {google:{id: 123}}, user_id: 'id', secret: 'secret'} describe 'when exists yields false and insert yields an error', -> beforeEach (done) -> @sut.exists = sinon.stub().yields false @sut.insert = sinon.stub().yields new Error @sut.create {query: {'google.id': '595'}, data: {}, user_id: 'id', secret: 'secret'}, (@error) => done() it 'should have an error', -> expect(@error).to.exist describe 'when exists yields false and insert yields a device', -> beforeEach (done) -> @meshbluHttp.sign = sinon.stub().returns 'trust-me' @sut.exists = sinon.stub().yields false @sut.insert = sinon.stub().yields null, {uuid: 'wobbly-table'} @sut.hashSecret = sinon.stub().yields null @sut.update = sinon.stub().yields null @sut.create {query: {'google.id': '595'}, data: {}, user_id: 'id', secret: 'secret'}, (@error) => done() it 'should call hashSecret', -> expect(@sut.hashSecret).to.have.been.calledWith secret: 'secret' + 'wobbly-table' describe 'when exists yields false and insert yields a device and hashSecret yields an error', -> beforeEach (done) -> @sut.exists = sinon.stub().yields false @sut.insert = sinon.stub().yields null, {uuid: 'wobbly-table'} @sut.hashSecret = sinon.stub().yields new Error @sut.create {query: {'google.id': '595'}, data: {}, user_id: null, secret: null}, (@error) => done() it 'should have an error', -> expect(@error).to.exist describe 'when exists yields false and insert yields a device and hashSecret yields a secret', -> beforeEach (done) -> @meshbluHttp.sign = sinon.stub().returns 'trust-me' @sut.exists = sinon.stub().yields false @sut.insert = sinon.stub().yields null, {uuid: 'wobbly-table'} @sut.hashSecret = sinon.stub().yields null, '$$$$$$$$$$' @sut.update = sinon.stub().yields null @sut.create {query: {'google.id': '595'}, data: {}, user_id: '1', secret: 'secret'}, (@error, @device) => done() it 'should call update', -> expect(@sut.update).to.have.been.calledWith uuid: 'wobbly-table', data: {owner: 'wobbly-table', 'auth-id': {name : 'authenticator', id: '1', secret: '$$$$$$$$$$', signature: 'trust-me'}} it 'should yield the device', -> expect(@device).to.deep.equal {uuid: 'wobbly-table'} describe '->exists', -> beforeEach -> authenticatorUuid = '1' authenticatorName = 'name' @sut = new DeviceAuthenticator {authenticatorUuid, authenticatorName, @meshbluHttp} describe 'when exists is called', -> beforeEach -> @sut.exists query: {'google.id': '123'} it 'should call findOne with query', -> expect(@meshbluHttp.devices).to.have.been.calledWith 'google.id': '123' describe 'when findOne yields a device', -> beforeEach -> firstDevice = uuid: 'label-maker', '1': {user_id: '123', signature: 'aaron-in-cursive'} secondDevice = uuid: 'label-maker', '1': {user_id: '123', signature: 'aaron-in-sanscrit'} @meshbluHttp.devices.yields null, [firstDevice, secondDevice] describe 'when the devices do not have valid signatures', -> beforeEach (done) -> @meshbluHttp.verify = sinon.stub().returns false @sut.exists query: {'google.id' : '12350'}, (error, @exists) => done error it 'should call meshbluHttp.verify with the find device data', -> expect(@meshbluHttp.verify).to.have.been.calledWith {user_id: '123'}, 'aaron-in-cursive' it 'should have a device', -> expect(@exists).to.be.false describe 'when the devices do have valid signatures', -> beforeEach (done) -> @meshbluHttp.verify = sinon.stub().returns true @sut.exists query: {'google.id' : '12350'}, (error, @exists) => done error it 'should call meshbluHttp.verify with the find device data', -> expect(@meshbluHttp.verify).to.have.been.calledWith {user_id: '123'}, 'aaron-in-cursive' it 'should have a device', -> expect(@exists).to.be.true describe 'when exists yields nothing', -> beforeEach (done) -> @meshbluHttp.devices.yields null, null @sut.exists query: {'google.id' : '12350'}, (error, @exists) => done error it 'should not have an device', -> expect(@exists).to.be.false describe 'when exists yields an empty array', -> beforeEach (done) -> @meshbluHttp.devices.yields null, [] @sut.exists query: {'google.id' : '12350'}, (error, @exists) => done error it 'should not have an device', -> expect(@exists).to.be.false describe 'when exists yields an error', -> beforeEach (done) -> @meshbluHttp.devices.yields new Error @sut.exists query: {'google.id' : '12350'}, (@error, @exists) => done() it 'should have an error', -> expect(@error).to.exist describe '->insert', -> beforeEach -> authenticatorUuid = '1' authenticatorName = 'name' @sut = new DeviceAuthenticator {authenticatorUuid, authenticatorName, @meshbluHttp} describe 'when insert is called', -> beforeEach (done) -> @meshbluHttp.register.yields null, {} @sut.exists = sinon.stub().yields null, false @sut.insert query: {'something':'tall'}, data: {'pen':'sharpie'}, (error, @device) => done error it 'should call exists', -> expect(@sut.exists).to.have.been.calledWith query: {'something': 'tall'} it 'should call meshbluHttp.register', -> expect(@meshbluHttp.register).to.have.been.calledWith {'pen': 'sharpie'} it 'should yield a device', -> expect(@device).to.exist describe 'when insert is called with a different device', -> beforeEach -> @sut.exists = sinon.stub().yields null, false @sut.insert query: {'something':'black'}, data: {'skinny': 'stick'} it 'should call meshbluHttp.insert', -> expect(@meshbluHttp.register).to.have.been.calledWith {'skinny': 'stick'} describe '->hashSecret', -> beforeEach -> @sut = new DeviceAuthenticator {} describe 'when hashSecret is called', -> beforeEach (done) -> @sut.hashSecret secret: null, (@error) => done() it 'should yield an error', -> expect(@error).to.exist describe 'when bcryptn', -> beforeEach (done) -> @sut.hashSecret secret: 'shhh', (@error, @hashedSecret) => done() it 'should yield a bcrypted secret', -> expect(bcrypt.compareSync('shhh', @hashedSecret)).to.be.true describe '->update', -> beforeEach -> authenticatorUuid = '1' authenticatorName = 'name' @sut = new DeviceAuthenticator {authenticatorUuid, authenticatorName, @meshbluHttp} describe 'when update yields an error', -> beforeEach (done) -> @meshbluHttp.update.yields new Error @sut.update data: {}, (@error) => done() it 'should yield an error', -> expect(@error).to.exist describe 'when update is called', -> beforeEach (done) -> @meshbluHttp.update.yields null @sut.update uuid: 'hi!', data: {uuid: 'hi!', some: 'stuff'}, (error) => done error it 'should get called with stuff', -> expect(@meshbluHttp.update).to.have.been.calledWith 'hi!', {some: 'stuff', uuid: 'hi! '} describe '->verifySignature', -> beforeEach -> authenticatorUuid = '1' authenticatorName = 'name' @sut = new DeviceAuthenticator {authenticatorUuid, authenticatorName, @meshbluHttp} describe 'when called', -> beforeEach -> @sut.verifySignature data: {id: 'foo', signature: 'this-is-my-rifle'} it 'should meshblu.verify', -> expect(@meshbluHttp.verify).to.have.been.calledWith {id: 'foo'}, 'this-is-my-rifle' describe 'when called with a different device', -> beforeEach -> @sut.verifySignature data: {id: 'bar', signature: 'this-is-my-gun'} it 'should meshblu.verify', -> expect(@meshbluHttp.verify).to.have.been.calledWith {id: 'bar'}, 'this-is-my-gun' describe '->findVerified', -> beforeEach -> authenticatorUuid = 'auth-id' authenticatorName = 'auth-id' @sut = new DeviceAuthenticator {authenticatorUuid, authenticatorName, @meshbluHttp} describe 'when find yields an error', -> beforeEach (done) -> @meshbluHttp.search.yields new Error @sut.findVerified query: {}, password: 'password', (@error) => done() it 'should yield an error', -> expect(@error).to.exist describe 'when it finds one device with a valid signature and invalid secret', -> beforeEach (done) -> devices = [ uuid: 1, 'auth-id': signature: 2, secret: '######' ] @meshbluHttp.search.yields null, devices @sut.verifySignature = sinon.stub().returns true @sut.verifySecret = sinon.stub().returns false @sut.findVerified query: {something: 'important'}, password: 'password', (error, @device) => done() it 'should call meshblu.search', -> expect(@meshbluHttp.search).to.have.been.calledWith {something : 'important'} it 'should call verifySignature', -> expect(@sut.verifySignature).to.have.been.calledWith data: {signature: 2, secret: '######'} it 'should call verifySecret', -> expect(@sut.verifySecret).to.have.been.calledWith secret: 'password' + 1, hash: '######' it 'should not have a device', -> expect(@device).to.not.exist describe 'when it finds one device with a valid signature and valid secret', -> beforeEach (done) -> devices = [ uuid: 7, 'auth-id': signature: 8, secret: '######' ] @meshbluHttp.search.yields null, devices @sut.verifySignature = sinon.stub().returns true @sut.verifySecret = sinon.stub().returns true @sut.findVerified query: {something: 'less-important'}, password: 'password', (error, @device) => done() it 'should call meshblu.search', -> expect(@meshbluHttp.search).to.have.been.calledWith {something : 'less-important'} it 'should call verifySignature', -> expect(@sut.verifySignature).to.have.been.calledWith data: {signature: 8, secret: '######'} it 'should call verifySecret', -> expect(@sut.verifySecret).to.have.been.calledWith secret: 'password' + 7, hash: '######' it 'should have one device', -> expect(@device).to.deep.equal uuid: 7, 'auth-id': signature: 8, secret: '######' describe 'when it finds one device with a invalid signature', -> beforeEach (done) -> devices = [ uuid: 7, 'auth-id': signature: 8, secret: '######' ] @meshbluHttp.search.yields null, devices @sut.verifySignature = sinon.stub().returns false @sut.verifySecret = sinon.stub().returns false @sut.findVerified query: {something: 'less-important'}, password: 'password' + 7, (error, @device) => done() it 'should call meshblu.search', -> expect(@meshbluHttp.search).to.have.been.calledWith {something : 'less-important'} it 'should call verifySignature', -> expect(@sut.verifySignature).to.have.been.calledWith data: {signature: 8, secret:'######'} it 'should call verifySecret', -> expect(@sut.verifySecret).to.not.have.been.called it 'should have one device', -> expect(@device).to.not.exist describe 'when it finds a different valid device', -> beforeEach (done) -> devices = [ uuid: 4, 'auth-id': signature: 5, secret: '######' ] @meshbluHttp.search.yields null, devices @sut.verifySignature = sinon.stub().returns true @sut.verifySecret = sinon.stub().returns true @sut.findVerified query: {something: 'more-important'}, password: 'password', (error, @device) => done() it 'should call meshblu.search', -> expect(@meshbluHttp.search).to.have.been.calledWith {something : 'more-important'} it 'should call verifySignature', -> expect(@sut.verifySignature).to.have.been.calledWith data: {signature: 5, secret: '######'} it 'should call verifySecret', -> expect(@sut.verifySecret).to.have.been.calledWith secret: 'password' + 4, hash: '######' it 'should have one device', -> expect(@device).to.containSubset uuid: 4, 'auth-id': signature: 5, secret: '######' describe '->verifySecret', -> beforeEach -> @sut = new DeviceAuthenticator '', '' describe 'when called with valid secret', -> beforeEach -> @result = @sut.verifySecret secret: 'secret', hash: bcrypt.hashSync('secret', 8) it 'should return true', -> expect(@result).to.be.true describe 'when called with invalid secret', -> beforeEach -> @result = @sut.verifySecret secret: 'secret', hash: bcrypt.hashSync('not-correct-secret', 8) it 'should return false', -> expect(@result).to.be.false