UNPKG

endo-core

Version:
336 lines (293 loc) 11.4 kB
{afterEach, beforeEach, describe, it} = global {expect} = require 'chai' sinon = require 'sinon' fs = require 'fs' request = require 'request' Encryption = require 'meshblu-encryption' enableDestroy = require 'server-destroy' shmock = require 'shmock' MockStrategy = require '../mock-strategy' Server = require '../..' describe 'v2 messages', -> beforeEach (done) -> @serviceAuth = new Buffer('peter:i-could-eat').toString 'base64' @privateKey = fs.readFileSync "#{__dirname}/../data/private-key.pem", 'utf8' @HTTP_SIGNATURE_OPTIONS = keyId: 'meshblu-webhook-key' key: @privateKey headers: [ 'date', 'X-MESHBLU-UUID' ] @encryption = Encryption.fromPem @privateKey @publicKey = @encryption.key.exportKey 'public' @meshblu = shmock 0xd00d enableDestroy @meshblu @apiStrategy = new MockStrategy name: 'api' @octobluStrategy = new MockStrategy name: 'octoblu' @messageHandler = onMessage: sinon.stub() @meshblu .get 'publickey' .reply 200, @privateKey @meshblu .get '/v2/whoami' .set 'Authorization', "Basic #{@serviceAuth}" .reply 200, { options: imageUrl: "http://this-is-an-image.exe" } @meshblu .get '/publickey' .reply 200, {@publicKey} serverOptions = logFn: -> port: undefined, disableLogging: true apiStrategy: @apiStrategy octobluStrategy: @octobluStrategy messageHandler: @messageHandler serviceUrl: 'http://octoblu.xxx' deviceType: 'endo-endor' meshbluConfig: hostname: 'localhost' protocol: 'http' port: 0xd00d uuid: 'peter' token: 'i-could-eat' privateKey: @privateKey appOctobluHost: 'http://app.octoblu.mom' userDeviceManagerUrl: 'http://manage-my.endo' meshbluPublicKeyUri: 'http://localhost:53261/publickey' @server = new Server serverOptions @server.run (error) => return done error if error? @serverPort = @server.address().port done() afterEach (done) -> @server.stop done afterEach (done) -> @meshblu.destroy done describe 'On POST /v2/messages', -> describe 'when not signed by meshblu', -> beforeEach (done) -> options = baseUrl: "http://localhost:#{@serverPort}" headers: 'x-meshblu-uuid': 'peter' 'x-meshblu-route': JSON.stringify [ {"from": "flow-uuid", "to": "user-uuid", "type": "message.sent"} {"from": "user-uuid", "to": "cred-uuid", "type": "message.received"} {"from": "cred-uuid", "to": "cred-uuid", "type": "message.received"} {"from": "cred-uuid", "to": "peter", "type": "message.received"} ] json: metadata: jobType: 'hello' data: greeting: 'hola' auth: username: 'cred-uuid' password: 'cred-token' request.post '/v2/messages', options, (error, @response) => done error it "should return a 401, because the signature doesn't exist", -> expect(@response.statusCode).to.equal 401 describe 'when signed by meshblu, but for the wrong uuid', -> beforeEach (done) -> options = httpSignature: @HTTP_SIGNATURE_OPTIONS baseUrl: "http://localhost:#{@serverPort}" headers: 'x-meshblu-uuid': 'Pumpkin Eater' 'x-meshblu-route': JSON.stringify [ {"from": "flow-uuid", "to": "user-uuid", "type": "message.sent"} {"from": "user-uuid", "to": "cred-uuid", "type": "message.received"} {"from": "cred-uuid", "to": "cred-uuid", "type": "message.received"} {"from": "cred-uuid", "to": "peter", "type": "message.received"} ] json: metadata: jobType: 'hello' data: greeting: 'hola' request.post '/v2/messages', options, (error, @response) => done error it "should return a 401, because that webhook is for someone else", -> expect(@response.statusCode).to.equal 401 describe 'when signed by meshblu, for the service', -> beforeEach 'requestOptions', -> @requestOptions = httpSignature: @HTTP_SIGNATURE_OPTIONS baseUrl: "http://localhost:#{@serverPort}" headers: 'x-meshblu-uuid': 'peter' 'x-meshblu-route': JSON.stringify [ {"from": "flow-uuid", "to": "user-uuid", "type": "message.sent"} {"from": "user-uuid", "to": "cred-uuid", "type": "message.received"} {"from": "cred-uuid", "to": "cred-uuid", "type": "message.received"} {"from": "cred-uuid", "to": "peter", "type": "message.received"} ] json: metadata: jobType: 'hello' respondTo: foo: 'bar' data: greeting: 'hola' describe "but the credentials device doesn't have an encrypted token for the service", -> beforeEach 'credentials-device', -> unencrypted = secrets: credentials: secret: 'this is secret' endo = authorizedKey: 'some-uuid' credentialsDeviceUuid: 'cred-uuid' encrypted: @encryption.encrypt unencrypted endoSignature = @encryption.sign { authorizedKey: 'some-uuid' credentialsDeviceUuid: 'cred-uuid' encrypted: unencrypted } @meshblu .post '/search/devices' .set 'Authorization', "Basic #{@serviceAuth}" .set 'x-meshblu-as', 'cred-uuid' .send uuid: 'cred-uuid' .reply 200, [ uuid: 'cred-uuid' endoSignature: endoSignature endo: endo ] beforeEach (done) -> request.post '/v2/messages', @requestOptions, (error, @response) => done error it "should return a 422, because the credentials device is misconfigured", -> expect(@response.statusCode).to.equal 422 describe "and the credentials device has an encrypted token", -> beforeEach 'credentials-device', -> unencrypted = secrets: credentialsDeviceToken: 'cred-token' credentials: secret: 'this is secret' endo = authorizedKey: 'some-uuid' credentialsDeviceUuid: 'cred-uuid' encrypted: @encryption.encrypt unencrypted endoSignature = @encryption.sign { authorizedKey: 'some-uuid' credentialsDeviceUuid: 'cred-uuid' encrypted: unencrypted } @meshblu .post '/search/devices' .set 'Authorization', "Basic #{@serviceAuth}" .set 'x-meshblu-as', 'cred-uuid' .send uuid: 'cred-uuid' .reply 200, [ uuid: 'cred-uuid' endoSignature: endoSignature endo: endo ] beforeEach (done) -> credentialsDeviceAuth = new Buffer('cred-uuid:cred-token').toString 'base64' @messageHandler.onMessage.yields null, metadata: {code: 200}, data: {whatever: 'this is a response'} @responseHandler = @meshblu .post '/messages' .set 'Authorization', "Basic #{credentialsDeviceAuth}" .set 'x-meshblu-as', 'user-uuid' .send devices: ['flow-uuid'] metadata: code: 200 to: { foo: 'bar' } data: whatever: 'this is a response' .reply 201 request.post '/v2/messages', @requestOptions, (error, @response) => done error it 'should return a 201', -> expect(@response.statusCode).to.equal 201 it 'should respond to the message via meshblu', -> @responseHandler.done() it 'should call the hello messageHandler with the message and auth', -> expect(@messageHandler.onMessage).to.have.been.calledWith { encrypted: secrets: credentials: secret: 'this is secret' metadata: jobType: 'hello' respondTo: foo: 'bar' data: greeting: 'hola' } describe "and we can't discover.as the credentials device", -> beforeEach 'credentials-device', -> unencrypted = secrets: credentialsDeviceToken: 'cred-token' credentials: secret: 'this is secret' endo = authorizedKey: 'some-uuid' credentialsDeviceUuid: 'cred-uuid' encrypted: @encryption.encrypt unencrypted endoSignature = @encryption.sign { authorizedKey: 'some-uuid' credentialsDeviceUuid: 'cred-uuid' encrypted: unencrypted } @meshblu .post '/search/devices' .set 'Authorization', "Basic #{@serviceAuth}" .set 'x-meshblu-as', 'cred-uuid' .send uuid: 'cred-uuid' .reply 403 .on 'done', => @meshblu .post '/search/devices' .set 'Authorization', "Basic #{@serviceAuth}" .set 'x-meshblu-as', 'cred-uuid' .send uuid: 'cred-uuid' .reply 200, [ uuid: 'cred-uuid' endoSignature: endoSignature endo: endo ] @meshblu .get '/v2/devices/cred-uuid' .set 'Authorization', "Basic #{@serviceAuth}" .set 'x-meshblu-as', 'cred-uuid' .reply 403 .on 'done', => @meshblu .get '/v2/devices/cred-uuid' .set 'Authorization', "Basic #{@serviceAuth}" .set 'x-meshblu-as', 'cred-uuid' .reply 200, uuid: 'cred-uuid' endoSignature: endoSignature endo: endo @updateCredentialsDevice = @meshblu .put '/v2/devices/cred-uuid' .set 'Authorization', "Basic #{@serviceAuth}" .send $addToSet: "meshblu.whitelists.discover.as": {uuid: 'peter'} .reply 204 beforeEach (done) -> credentialsDeviceAuth = new Buffer('cred-uuid:cred-token').toString 'base64' @messageHandler.onMessage.yields null, metadata: {code: 200}, data: {whatever: 'this is a response'} @responseHandler = @meshblu .post '/messages' .set 'Authorization', "Basic #{credentialsDeviceAuth}" .set 'x-meshblu-as', 'user-uuid' .send devices: ['flow-uuid'] metadata: code: 200 to: { foo: 'bar' } data: whatever: 'this is a response' .reply 201 request.post '/v2/messages', @requestOptions, (error, @response) => done error it 'should update the credentials device discover.as whitelist', -> @updateCredentialsDevice.done()