diff --git a/.gitignore b/.gitignore index 97d8d25..babcf49 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ dist/ release/ test/integration/src/ .elasticbeanstalk/ +test/unit/index.js +test/unit/index.js.map diff --git a/.jshintrc b/.jshintrc index 79d663e..a3064a8 100644 --- a/.jshintrc +++ b/.jshintrc @@ -18,19 +18,18 @@ "unused": true, "predef": [ + "self", "console", - "Notification", - "importScripts", - "process", - "Event", + "process", "chrome", - "define", - "self", + "Notification", + "Event", + "sinon", + "mocha", + "chai", + "expect", "describe", "it", - "chai", - "sinon", - "mocha", "before", "beforeEach", "after", diff --git a/Gruntfile.js b/Gruntfile.js index dacb48e..ce09983 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,6 +1,8 @@ module.exports = function(grunt) { 'use strict'; + require('time-grunt')(grunt); + var version = grunt.option('release'), zipName = (version) ? version : 'DEV'; @@ -24,7 +26,7 @@ module.exports = function(grunt) { }, jshint: { - all: ['Gruntfile.js', 'src/*.js', 'src/js/**/*.js', 'test/unit/*.js', 'test/integration/*.js'], + all: ['Gruntfile.js', 'src/*.js', 'src/js/**/*.js', 'test/unit/*-test.js', 'test/integration/*.js'], options: { jshintrc: '.jshintrc' } @@ -109,16 +111,22 @@ module.exports = function(grunt) { 'dist/js/app.min.js': ['src/js/app.js'] }, options: { - external: ['node-forge', 'net', 'tls'] // common.js apis not required at build time + external: [] } }, - /* TODO: - tls-worker: {}, - mailreader-worker: {}, - pbkdf2-worker: {}, - unitTest: {}, - unitTest: {}, - integrationTest: {} + unitTest: { + files: { + 'test/unit/index.js': ['test/unit/*-test.js'] + }, + options: { + external: [] + } + }, + /* + TODO: + mailreader-worker: {}, + pbkdf2-worker: {}, + integrationTest: {} */ }, @@ -126,6 +134,7 @@ module.exports = function(grunt) { all: { files: { 'dist/js/app.min.js': [ + 'src/lib/openpgp/openpgp.js', 'src/lib/underscore/underscore-min.js', 'node_modules/jquery/dist/jquery.min.js', 'src/lib/angular/angular.min.js', @@ -142,6 +151,28 @@ module.exports = function(grunt) { ] } }, + unitTest: { + files: { + 'test/unit/index.js': [ + 'src/lib/underscore/underscore-min.js', + 'node_modules/jquery/dist/jquery.min.js', + 'src/lib/openpgp/openpgp.js', + 'src/lib/angular/angular.min.js', + 'node_modules/angular-mocks/angular-mocks.js', + 'src/lib/angular/angular-route.min.js', + 'src/lib/angular/angular-animate.min.js', + 'src/lib/ngtagsinput/ng-tags-input.min.js', + 'src/lib/fastclick/fastclick.js', + 'node_modules/ng-infinite-scroll/build/ng-infinite-scroll.min.js', + 'src/lib/lawnchair/lawnchair-git.js', + 'src/lib/lawnchair/lawnchair-adapter-webkit-sqlite-git.js', + 'src/lib/lawnchair/lawnchair-adapter-indexed-db-git.js', + 'node_modules/dompurify/purify.js', + 'test/lib/angular-mocks.js', + 'test/unit/index.js' + ] + } + }, options: { banner: '/*! Copyright © <%= grunt.template.today("yyyy") %>, Whiteout Networks GmbH.*/\n' } @@ -152,7 +183,7 @@ module.exports = function(grunt) { expand: true, flatten: true, cwd: 'node_modules/', - src: ['requirejs/require.js', 'mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js', 'angularjs/src/ngMock/angular-mocks.js', 'browsercrow/src/*.js', 'browsersmtp/src/*.js'], + src: ['mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js', 'browsercrow/src/*.js', 'browsersmtp/src/*.js'], dest: 'test/lib/' }, font: { diff --git a/package.json b/package.json index a6e3162..614c632 100644 --- a/package.json +++ b/package.json @@ -1,70 +1,72 @@ { - "name": "whiteout-mail", - "version": "0.0.1", - "description": "Mail App with integrated OpenPGP encryption.", - "author": "Whiteout Networks", - "homepage": "https://whiteout.io", - "repository": { - "type": "git", - "url": "https://github.com/whiteout-io/mail-html5.git" - }, - "keywords": [ - "email", - "mail", - "client", - "app", - "openpgp", - "pgp", - "gpg", - "imap", - "smtp" - ], - "engines": { - "node": ">=0.10" - }, - "scripts": { - "test": "grunt && grunt test", - "start": "node server.js" - }, - "dependencies": { - "axe-logger": "~0.0.2", - "compression": "^1.0.11", - "config": "^1.0.2", - "crypto-lib": "~0.2.1", - "dompurify": "~0.4.2", - "express": "^4.8.3", - "imap-client": "~0.4.3", - "jquery": "~2.1.1", - "mailreader": "~0.3.5", - "morgan": "^1.2.3", - "ng-infinite-scroll": "~1.1.2", - "npmlog": "^0.1.1", - "pgpbuilder": "~0.4.0", - "pgpmailer": "~0.4.0", - "socket.io": "^1.0.6", - "tcp-socket": "^0.3.9", - "wo-smtpclient": "^0.3.8" - }, - "devDependencies": { - "angularjs": "https://github.com/whiteout-io/angular.js/tarball/npm-version", - "browsercrow": "https://github.com/whiteout-io/browsercrow/tarball/master", - "browsersmtp": "https://github.com/whiteout-io/browsersmtp/tarball/master", - "chai": "~1.7.2", - "grunt": "~0.4.1", - "grunt-autoprefixer": "~0.7.2", - "grunt-browserify": "^3.0.1", - "grunt-contrib-clean": "~0.5.0", - "grunt-contrib-compress": "~0.5.2", - "grunt-contrib-connect": "~0.5.0", - "grunt-contrib-copy": "~0.4.1", - "grunt-contrib-jshint": "~0.6.4", - "grunt-contrib-sass": "~0.7.3", - "grunt-contrib-uglify": "^0.6.0", - "grunt-contrib-watch": "~0.5.3", - "grunt-csso": "~0.6.1", - "grunt-manifest": "^0.4.0", - "grunt-mocha": "~0.4.1", - "mocha": "~1.13.0", - "sinon": "~1.7.3" - } -} \ No newline at end of file + "name": "whiteout-mail", + "version": "0.0.1", + "description": "Mail App with integrated OpenPGP encryption.", + "author": "Whiteout Networks", + "homepage": "https://whiteout.io", + "repository": { + "type": "git", + "url": "https://github.com/whiteout-io/mail-html5.git" + }, + "keywords": [ + "email", + "mail", + "client", + "app", + "openpgp", + "pgp", + "gpg", + "imap", + "smtp" + ], + "engines": { + "node": ">=0.10" + }, + "scripts": { + "test": "grunt && grunt test", + "start": "node server.js" + }, + "dependencies": { + "axe-logger": "~0.0.2", + "compression": "^1.0.11", + "config": "^1.0.2", + "crypto-lib": "~0.2.1", + "dompurify": "~0.4.2", + "express": "^4.8.3", + "imap-client": "~0.4.3", + "jquery": "~2.1.1", + "mailreader": "~0.3.5", + "morgan": "^1.2.3", + "ng-infinite-scroll": "~1.1.2", + "npmlog": "^0.1.1", + "pgpbuilder": "~0.4.0", + "pgpmailer": "~0.4.0", + "socket.io": "^1.0.6", + "tcp-socket": "^0.3.9", + "wo-smtpclient": "^0.3.8" + }, + "devDependencies": { + "angular-mocks": "^1.2.25", + "angularjs": "https://github.com/whiteout-io/angular.js/tarball/npm-version", + "browsercrow": "https://github.com/whiteout-io/browsercrow/tarball/master", + "browsersmtp": "https://github.com/whiteout-io/browsersmtp/tarball/master", + "chai": "~1.7.2", + "grunt": "~0.4.1", + "grunt-autoprefixer": "~0.7.2", + "grunt-browserify": "^3.0.1", + "grunt-contrib-clean": "~0.5.0", + "grunt-contrib-compress": "~0.5.2", + "grunt-contrib-connect": "~0.5.0", + "grunt-contrib-copy": "~0.4.1", + "grunt-contrib-jshint": "~0.6.4", + "grunt-contrib-sass": "~0.7.3", + "grunt-contrib-uglify": "^0.6.0", + "grunt-contrib-watch": "~0.5.3", + "grunt-csso": "~0.6.1", + "grunt-manifest": "^0.4.0", + "grunt-mocha": "~0.4.1", + "mocha": "~1.13.0", + "sinon": "~1.7.3", + "time-grunt": "^1.0.0" + } +} diff --git a/test/unit/account-ctrl-test.js b/test/unit/account-ctrl-test.js index 1902d0b..5deacd7 100644 --- a/test/unit/account-ctrl-test.js +++ b/test/unit/account-ctrl-test.js @@ -1,101 +1,97 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - AccountCtrl = require('js/controller/account'), - PGP = require('js/crypto/pgp'), - dl = require('js/util/download'), - appController = require('js/app-controller'), - KeychainDAO = require('js/dao/keychain-dao'); +var mocks = angular.mocks, + AccountCtrl = require('../../src/js/controller/account'), + PGP = require('../../src/js/crypto/pgp'), + dl = require('../../src/js/util/download'), + appController = require('../../src/js/app-controller'), + KeychainDAO = require('../../src/js/dao/keychain-dao'); - describe('Account Controller unit test', function() { - var scope, accountCtrl, - dummyFingerprint, expectedFingerprint, - dummyKeyId, expectedKeyId, - emailAddress, keySize, pgpMock, keychainMock; +describe('Account Controller unit test', function() { + var scope, accountCtrl, + dummyFingerprint, expectedFingerprint, + dummyKeyId, expectedKeyId, + emailAddress, keySize, pgpMock, keychainMock; - beforeEach(function() { - appController._pgp = pgpMock = sinon.createStubInstance(PGP); - appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); + beforeEach(function() { + appController._pgp = pgpMock = sinon.createStubInstance(PGP); + appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); - dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926'; - expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926'; - dummyKeyId = '9FEB47936E712926'; - expectedKeyId = '6E712926'; - pgpMock.getFingerprint.returns(dummyFingerprint); - pgpMock.getKeyId.returns(dummyKeyId); - emailAddress = 'fred@foo.com'; - keySize = 1234; - appController._emailDao = { - _account: { - emailAddress: emailAddress, - asymKeySize: keySize - } - }; - pgpMock.getKeyParams.returns({ - _id: dummyKeyId, - fingerprint: dummyFingerprint, - userId: emailAddress, - bitSize: keySize - }); - - angular.module('accounttest', []); - mocks.module('accounttest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = {}; - accountCtrl = $controller(AccountCtrl, { - $scope: scope - }); - }); + dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926'; + expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926'; + dummyKeyId = '9FEB47936E712926'; + expectedKeyId = '6E712926'; + pgpMock.getFingerprint.returns(dummyFingerprint); + pgpMock.getKeyId.returns(dummyKeyId); + emailAddress = 'fred@foo.com'; + keySize = 1234; + appController._emailDao = { + _account: { + emailAddress: emailAddress, + asymKeySize: keySize + } + }; + pgpMock.getKeyParams.returns({ + _id: dummyKeyId, + fingerprint: dummyFingerprint, + userId: emailAddress, + bitSize: keySize }); - afterEach(function() {}); - - describe('scope variables', function() { - it('should be set correctly', function() { - expect(scope.eMail).to.equal(emailAddress); - expect(scope.keyId).to.equal(expectedKeyId); - expect(scope.fingerprint).to.equal(expectedFingerprint); - expect(scope.keysize).to.equal(keySize); - }); - }); - describe('export to key file', function() { - it('should work', function() { - var createDownloadMock = sinon.stub(dl, 'createDownload'); - keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, { - publicKey: { - _id: dummyKeyId, - publicKey: 'a' - }, - privateKey: { - encryptedKey: 'b' - } - }); - createDownloadMock.withArgs(sinon.match(function(arg) { - return arg.content === 'a\r\nb' && arg.filename === 'whiteout_mail_' + emailAddress + '_' + expectedKeyId + '.asc' && arg.contentType === 'text/plain'; - })).returns(); - - scope.exportKeyFile(); - - expect(scope.state.lightbox).to.equal(undefined); - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - expect(dl.createDownload.calledOnce).to.be.true; - dl.createDownload.restore(); - }); - - it('should not work when key export failed', function(done) { - keychainMock.getUserKeyPair.yields(new Error('Boom!')); - scope.onError = function(err) { - expect(err.message).to.equal('Boom!'); - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - done(); - }; - - scope.exportKeyFile(); + angular.module('accounttest', []); + mocks.module('accounttest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = {}; + accountCtrl = $controller(AccountCtrl, { + $scope: scope }); }); }); + + afterEach(function() {}); + + describe('scope variables', function() { + it('should be set correctly', function() { + expect(scope.eMail).to.equal(emailAddress); + expect(scope.keyId).to.equal(expectedKeyId); + expect(scope.fingerprint).to.equal(expectedFingerprint); + expect(scope.keysize).to.equal(keySize); + }); + }); + describe('export to key file', function() { + it('should work', function() { + var createDownloadMock = sinon.stub(dl, 'createDownload'); + keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, { + publicKey: { + _id: dummyKeyId, + publicKey: 'a' + }, + privateKey: { + encryptedKey: 'b' + } + }); + createDownloadMock.withArgs(sinon.match(function(arg) { + return arg.content === 'a\r\nb' && arg.filename === 'whiteout_mail_' + emailAddress + '_' + expectedKeyId + '.asc' && arg.contentType === 'text/plain'; + })).returns(); + + scope.exportKeyFile(); + + expect(scope.state.lightbox).to.equal(undefined); + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + expect(dl.createDownload.calledOnce).to.be.true; + dl.createDownload.restore(); + }); + + it('should not work when key export failed', function(done) { + keychainMock.getUserKeyPair.yields(new Error('Boom!')); + scope.onError = function(err) { + expect(err.message).to.equal('Boom!'); + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + done(); + }; + + scope.exportKeyFile(); + }); + }); }); \ No newline at end of file diff --git a/test/unit/add-account-ctrl-test.js b/test/unit/add-account-ctrl-test.js index 4f42e92..69d2430 100644 --- a/test/unit/add-account-ctrl-test.js +++ b/test/unit/add-account-ctrl-test.js @@ -1,216 +1,212 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - AddAccountCtrl = require('js/controller/add-account'), - Auth = require('js/bo/auth'), - AdminDao = require('js/dao/admin-dao'), - appController = require('js/app-controller'); +var mocks = angular.mocks, + AddAccountCtrl = require('../../src/js/controller/add-account'), + Auth = require('../../src/js/bo/auth'), + AdminDao = require('../../src/js/dao/admin-dao'), + appController = require('../../src/js/app-controller'); - describe('Add Account Controller unit test', function() { - var scope, location, ctrl, authStub, origAuth, adminStub; +describe('Add Account Controller unit test', function() { + var scope, location, ctrl, authStub, origAuth, adminStub; - beforeEach(function() { - // remember original module to restore later, then replace it - origAuth = appController._auth; - appController._auth = authStub = sinon.createStubInstance(Auth); - appController._adminDao = adminStub = sinon.createStubInstance(AdminDao); + beforeEach(function() { + // remember original module to restore later, then replace it + origAuth = appController._auth; + appController._auth = authStub = sinon.createStubInstance(Auth); + appController._adminDao = adminStub = sinon.createStubInstance(AdminDao); - angular.module('addaccounttest', []); - mocks.module('addaccounttest'); - mocks.inject(function($controller, $rootScope, $location) { - location = $location; - scope = $rootScope.$new(); - scope.state = {}; - scope.form = {}; - scope.formValidate = {}; + angular.module('addaccounttest', []); + mocks.module('addaccounttest'); + mocks.inject(function($controller, $rootScope, $location) { + location = $location; + scope = $rootScope.$new(); + scope.state = {}; + scope.form = {}; + scope.formValidate = {}; - sinon.stub(location, 'path').returns(location); - sinon.stub(location, 'search').returns(location); - sinon.stub(scope, '$apply', function() {}); + sinon.stub(location, 'path').returns(location); + sinon.stub(location, 'search').returns(location); + sinon.stub(scope, '$apply', function() {}); - ctrl = $controller(AddAccountCtrl, { - $location: location, - $scope: scope, - $routeParams: {} - }); + ctrl = $controller(AddAccountCtrl, { + $location: location, + $scope: scope, + $routeParams: {} }); }); - - afterEach(function() { - // restore the app controller module - appController._auth = origAuth; - - location.path.restore(); - location.search.restore(); - if (scope.$apply.restore) { - scope.$apply.restore(); - } - }); - - describe('createWhiteoutAccount', function() { - it('should return early for invalid form', function() { - scope.form.$invalid = true; - scope.createWhiteoutAccount(); - expect(adminStub.createUser.called).to.be.false; - }); - - it('should fail to error creating user', function(done) { - scope.form.$invalid = false; - scope.betaCode = 'asfd'; - scope.phone = '12345'; - adminStub.createUser.yieldsAsync(new Error('asdf')); - - scope.$apply = function() { - expect(scope.busy).to.be.false; - expect(scope.errMsg).to.equal('asdf'); - expect(adminStub.createUser.calledOnce).to.be.true; - done(); - }; - - scope.createWhiteoutAccount(); - expect(scope.busy).to.be.true; - }); - - it('should work', function(done) { - scope.form.$invalid = false; - scope.betaCode = 'asfd'; - scope.phone = '12345'; - adminStub.createUser.yieldsAsync(); - - scope.$apply = function() { - expect(scope.busy).to.be.false; - expect(scope.errMsg).to.be.undefined; - expect(scope.step).to.equal(3); - expect(adminStub.createUser.calledOnce).to.be.true; - done(); - }; - - scope.createWhiteoutAccount(); - expect(scope.busy).to.be.true; - }); - }); - - describe('validateUser', function() { - it('should return early for invalid form', function() { - scope.formValidate.$invalid = true; - scope.validateUser(); - expect(adminStub.validateUser.called).to.be.false; - }); - - it('should fail to error creating user', function(done) { - scope.formValidate.$invalid = false; - scope.token = 'asfd'; - adminStub.validateUser.yieldsAsync(new Error('asdf')); - - scope.$apply = function() { - expect(scope.busyValidate).to.be.false; - expect(scope.errMsgValidate).to.equal('asdf'); - expect(adminStub.validateUser.calledOnce).to.be.true; - done(); - }; - - scope.validateUser(); - expect(scope.busyValidate).to.be.true; - }); - - it('should work', function(done) { - scope.formValidate.$invalid = false; - scope.token = 'asfd'; - adminStub.validateUser.yieldsAsync(); - - scope.login = function() { - expect(scope.busyValidate).to.be.true; - expect(scope.errMsgValidate).to.be.undefined; - expect(adminStub.validateUser.calledOnce).to.be.true; - done(); - }; - - scope.validateUser(); - expect(scope.busyValidate).to.be.true; - }); - }); - - describe('login', function() { - it('should work', function() { - scope.form.$invalid = false; - authStub.setCredentials.returns(); - - scope.login(); - expect(authStub.setCredentials.calledOnce).to.be.true; - expect(location.path.calledWith('/login')).to.be.true; - }); - }); - - describe('connectToGoogle', function() { - it('should forward to login', function() { - authStub._oauth = { - isSupported: function() { - return true; - } - }; - - authStub.getOAuthToken.yields(); - - scope.connectToGoogle(); - - expect(location.path.calledWith('/login-set-credentials')).to.be.true; - expect(location.search.calledWith({ - provider: 'gmail' - })).to.be.true; - expect(authStub.getOAuthToken.calledOnce).to.be.true; - }); - - it('should not use oauth for gmail', function() { - authStub._oauth = { - isSupported: function() { - return false; - } - }; - - scope.connectToGoogle(); - - expect(location.path.calledWith('/login-set-credentials')).to.be.true; - expect(location.search.calledWith({ - provider: 'gmail' - })).to.be.true; - expect(authStub.getOAuthToken.called).to.be.false; - }); - - it('should not forward to login when oauth fails', function(done) { - authStub._oauth = { - isSupported: function() { - return true; - } - }; - - authStub.getOAuthToken.yields(new Error()); - - scope.onError = function(err) { - expect(err).to.exist; - expect(location.path.called).to.be.false; - expect(location.search.called).to.be.false; - - done(); - }; - - scope.connectToGoogle(); - }); - }); - - describe('connectTo', function() { - it('should forward to login', function() { - var provider = 'wmail'; - scope.connectTo(provider); - - expect(location.path.calledWith('/login-set-credentials')).to.be.true; - expect(location.search.calledWith({ - provider: provider - })).to.be.true; - }); - }); - }); + + afterEach(function() { + // restore the app controller module + appController._auth = origAuth; + + location.path.restore(); + location.search.restore(); + if (scope.$apply.restore) { + scope.$apply.restore(); + } + }); + + describe('createWhiteoutAccount', function() { + it('should return early for invalid form', function() { + scope.form.$invalid = true; + scope.createWhiteoutAccount(); + expect(adminStub.createUser.called).to.be.false; + }); + + it('should fail to error creating user', function(done) { + scope.form.$invalid = false; + scope.betaCode = 'asfd'; + scope.phone = '12345'; + adminStub.createUser.yieldsAsync(new Error('asdf')); + + scope.$apply = function() { + expect(scope.busy).to.be.false; + expect(scope.errMsg).to.equal('asdf'); + expect(adminStub.createUser.calledOnce).to.be.true; + done(); + }; + + scope.createWhiteoutAccount(); + expect(scope.busy).to.be.true; + }); + + it('should work', function(done) { + scope.form.$invalid = false; + scope.betaCode = 'asfd'; + scope.phone = '12345'; + adminStub.createUser.yieldsAsync(); + + scope.$apply = function() { + expect(scope.busy).to.be.false; + expect(scope.errMsg).to.be.undefined; + expect(scope.step).to.equal(3); + expect(adminStub.createUser.calledOnce).to.be.true; + done(); + }; + + scope.createWhiteoutAccount(); + expect(scope.busy).to.be.true; + }); + }); + + describe('validateUser', function() { + it('should return early for invalid form', function() { + scope.formValidate.$invalid = true; + scope.validateUser(); + expect(adminStub.validateUser.called).to.be.false; + }); + + it('should fail to error creating user', function(done) { + scope.formValidate.$invalid = false; + scope.token = 'asfd'; + adminStub.validateUser.yieldsAsync(new Error('asdf')); + + scope.$apply = function() { + expect(scope.busyValidate).to.be.false; + expect(scope.errMsgValidate).to.equal('asdf'); + expect(adminStub.validateUser.calledOnce).to.be.true; + done(); + }; + + scope.validateUser(); + expect(scope.busyValidate).to.be.true; + }); + + it('should work', function(done) { + scope.formValidate.$invalid = false; + scope.token = 'asfd'; + adminStub.validateUser.yieldsAsync(); + + scope.login = function() { + expect(scope.busyValidate).to.be.true; + expect(scope.errMsgValidate).to.be.undefined; + expect(adminStub.validateUser.calledOnce).to.be.true; + done(); + }; + + scope.validateUser(); + expect(scope.busyValidate).to.be.true; + }); + }); + + describe('login', function() { + it('should work', function() { + scope.form.$invalid = false; + authStub.setCredentials.returns(); + + scope.login(); + expect(authStub.setCredentials.calledOnce).to.be.true; + expect(location.path.calledWith('/login')).to.be.true; + }); + }); + + describe('connectToGoogle', function() { + it('should forward to login', function() { + authStub._oauth = { + isSupported: function() { + return true; + } + }; + + authStub.getOAuthToken.yields(); + + scope.connectToGoogle(); + + expect(location.path.calledWith('/login-set-credentials')).to.be.true; + expect(location.search.calledWith({ + provider: 'gmail' + })).to.be.true; + expect(authStub.getOAuthToken.calledOnce).to.be.true; + }); + + it('should not use oauth for gmail', function() { + authStub._oauth = { + isSupported: function() { + return false; + } + }; + + scope.connectToGoogle(); + + expect(location.path.calledWith('/login-set-credentials')).to.be.true; + expect(location.search.calledWith({ + provider: 'gmail' + })).to.be.true; + expect(authStub.getOAuthToken.called).to.be.false; + }); + + it('should not forward to login when oauth fails', function(done) { + authStub._oauth = { + isSupported: function() { + return true; + } + }; + + authStub.getOAuthToken.yields(new Error()); + + scope.onError = function(err) { + expect(err).to.exist; + expect(location.path.called).to.be.false; + expect(location.search.called).to.be.false; + + done(); + }; + + scope.connectToGoogle(); + }); + }); + + describe('connectTo', function() { + it('should forward to login', function() { + var provider = 'wmail'; + scope.connectTo(provider); + + expect(location.path.calledWith('/login-set-credentials')).to.be.true; + expect(location.search.calledWith({ + provider: provider + })).to.be.true; + }); + }); + }); \ No newline at end of file diff --git a/test/unit/admin-dao-test.js b/test/unit/admin-dao-test.js index 06811b2..2550374 100644 --- a/test/unit/admin-dao-test.js +++ b/test/unit/admin-dao-test.js @@ -1,146 +1,142 @@ -define(function(require) { - 'use strict'; +'use strict'; - var RestDAO = require('js/dao/rest-dao'), - AdminDAO = require('js/dao/admin-dao'), - expect = chai.expect; +var RestDAO = require('../../src/js/dao/rest-dao'), + AdminDAO = require('../../src/js/dao/admin-dao'); - describe('Admin DAO unit tests', function() { +describe('Admin DAO unit tests', function() { - var adminDao, restDaoStub, - emailAddress = 'test@example.com', - password = 'secret'; + var adminDao, restDaoStub, + emailAddress = 'test@example.com', + password = 'secret'; - beforeEach(function() { - restDaoStub = sinon.createStubInstance(RestDAO); - adminDao = new AdminDAO(restDaoStub); - }); + beforeEach(function() { + restDaoStub = sinon.createStubInstance(RestDAO); + adminDao = new AdminDAO(restDaoStub); + }); - afterEach(function() {}); + afterEach(function() {}); - describe('createUser', function() { - it('should fail due to incomplete args', function(done) { - var opt = { - emailAddress: emailAddress - }; + describe('createUser', function() { + it('should fail due to incomplete args', function(done) { + var opt = { + emailAddress: emailAddress + }; - adminDao.createUser(opt, function(err) { - expect(err).to.exist; - done(); - }); - }); - - it('should fail if user already exists', function(done) { - var opt = { - emailAddress: emailAddress, - password: password, - phone: '12345' - }; - - restDaoStub.post.withArgs(opt, '/user').yields({ - code: 409 - }); - - adminDao.createUser(opt, function(err) { - expect(err.message).to.contain('already taken'); - expect(restDaoStub.post.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to unknown error', function(done) { - var opt = { - emailAddress: emailAddress, - password: password, - phone: '12345' - }; - - restDaoStub.post.withArgs(opt, '/user').yields(new Error()); - - adminDao.createUser(opt, function(err) { - expect(err).to.exist; - expect(restDaoStub.post.calledOnce).to.be.true; - done(); - }); - }); - - it('should work', function(done) { - var opt = { - emailAddress: emailAddress, - password: password, - phone: '12345' - }; - - restDaoStub.post.withArgs(opt, '/user').yields(); - - adminDao.createUser(opt, function(err) { - expect(err).to.not.exist; - expect(restDaoStub.post.calledOnce).to.be.true; - done(); - }); + adminDao.createUser(opt, function(err) { + expect(err).to.exist; + done(); }); }); - describe('validateUser', function() { - it('should fail due to incomplete args', function(done) { - var opt = { - emailAddress: emailAddress - }; + it('should fail if user already exists', function(done) { + var opt = { + emailAddress: emailAddress, + password: password, + phone: '12345' + }; - adminDao.validateUser(opt, function(err) { - expect(err).to.exist; - done(); - }); + restDaoStub.post.withArgs(opt, '/user').yields({ + code: 409 }); - it('should fail due to error in rest api', function(done) { - var opt = { - emailAddress: emailAddress, - token: 'H45Z6D' - }; - - restDaoStub.post.withArgs(opt, '/user/validate').yields(new Error()); - - adminDao.validateUser(opt, function(err) { - expect(err).to.exist; - expect(restDaoStub.post.calledOnce).to.be.true; - done(); - }); - }); - - it('should work with no error object', function(done) { - var opt = { - emailAddress: emailAddress, - token: 'H45Z6D' - }; - - restDaoStub.post.withArgs(opt, '/user/validate').yields(); - - adminDao.validateUser(opt, function(err) { - expect(err).to.not.exist; - expect(restDaoStub.post.calledOnce).to.be.true; - done(); - }); - }); - - it('should work with 202', function(done) { - var opt = { - emailAddress: emailAddress, - token: 'H45Z6D' - }; - - restDaoStub.post.withArgs(opt, '/user/validate').yields({ - code: 202 - }); - - adminDao.validateUser(opt, function(err) { - expect(err).to.not.exist; - expect(restDaoStub.post.calledOnce).to.be.true; - done(); - }); + adminDao.createUser(opt, function(err) { + expect(err.message).to.contain('already taken'); + expect(restDaoStub.post.calledOnce).to.be.true; + done(); }); }); + it('should fail due to unknown error', function(done) { + var opt = { + emailAddress: emailAddress, + password: password, + phone: '12345' + }; + + restDaoStub.post.withArgs(opt, '/user').yields(new Error()); + + adminDao.createUser(opt, function(err) { + expect(err).to.exist; + expect(restDaoStub.post.calledOnce).to.be.true; + done(); + }); + }); + + it('should work', function(done) { + var opt = { + emailAddress: emailAddress, + password: password, + phone: '12345' + }; + + restDaoStub.post.withArgs(opt, '/user').yields(); + + adminDao.createUser(opt, function(err) { + expect(err).to.not.exist; + expect(restDaoStub.post.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('validateUser', function() { + it('should fail due to incomplete args', function(done) { + var opt = { + emailAddress: emailAddress + }; + + adminDao.validateUser(opt, function(err) { + expect(err).to.exist; + done(); + }); + }); + + it('should fail due to error in rest api', function(done) { + var opt = { + emailAddress: emailAddress, + token: 'H45Z6D' + }; + + restDaoStub.post.withArgs(opt, '/user/validate').yields(new Error()); + + adminDao.validateUser(opt, function(err) { + expect(err).to.exist; + expect(restDaoStub.post.calledOnce).to.be.true; + done(); + }); + }); + + it('should work with no error object', function(done) { + var opt = { + emailAddress: emailAddress, + token: 'H45Z6D' + }; + + restDaoStub.post.withArgs(opt, '/user/validate').yields(); + + adminDao.validateUser(opt, function(err) { + expect(err).to.not.exist; + expect(restDaoStub.post.calledOnce).to.be.true; + done(); + }); + }); + + it('should work with 202', function(done) { + var opt = { + emailAddress: emailAddress, + token: 'H45Z6D' + }; + + restDaoStub.post.withArgs(opt, '/user/validate').yields({ + code: 202 + }); + + adminDao.validateUser(opt, function(err) { + expect(err).to.not.exist; + expect(restDaoStub.post.calledOnce).to.be.true; + done(); + }); + }); }); }); \ No newline at end of file diff --git a/test/unit/app-controller-test.js b/test/unit/app-controller-test.js index 21f622b..b260ab2 100644 --- a/test/unit/app-controller-test.js +++ b/test/unit/app-controller-test.js @@ -1,212 +1,209 @@ -define(function(require) { - 'use strict'; +'use strict'; - var controller = require('js/app-controller'), - EmailDAO = require('js/dao/email-dao'), - OutboxBO = require('js/bo/outbox'), - DeviceStorageDAO = require('js/dao/devicestorage-dao'), - UpdateHandler = require('js/util/update/update-handler'), - Auth = require('js/bo/auth'), - expect = chai.expect; +var controller = require('../../src/js/app-controller'), + EmailDAO = require('../../src/js/dao/email-dao'), + OutboxBO = require('../../src/js/bo/outbox'), + DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'), + UpdateHandler = require('../../src/js/util/update/update-handler'), + Auth = require('../../src/js/bo/auth'); - describe('App Controller unit tests', function() { - var emailDaoStub, outboxStub, updateHandlerStub, appConfigStoreStub, devicestorageStub, isOnlineStub, authStub; +describe('App Controller unit tests', function() { + var emailDaoStub, outboxStub, updateHandlerStub, appConfigStoreStub, devicestorageStub, isOnlineStub, authStub; + + beforeEach(function() { + controller._emailDao = emailDaoStub = sinon.createStubInstance(EmailDAO); + controller._outboxBo = outboxStub = sinon.createStubInstance(OutboxBO); + controller._appConfigStore = appConfigStoreStub = sinon.createStubInstance(DeviceStorageDAO); + controller._userStorage = devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); + controller._updateHandler = updateHandlerStub = sinon.createStubInstance(UpdateHandler); + controller._auth = authStub = sinon.createStubInstance(Auth); + + isOnlineStub = sinon.stub(controller, 'isOnline'); + }); + + afterEach(function() { + isOnlineStub.restore(); + }); + + describe('buildModules', function() { + it('should work', function() { + controller.buildModules({ + onError: function() {} + }); + expect(controller._appConfigStore).to.exist; + expect(controller._auth).to.exist; + expect(controller._userStorage).to.exist; + expect(controller._invitationDao).to.exist; + expect(controller._keychain).to.exist; + expect(controller._pgp).to.exist; + expect(controller._pgpbuilder).to.exist; + expect(controller._emailDao).to.exist; + expect(controller._outboxBo).to.exist; + expect(controller._updateHandler).to.exist; + }); + }); + + describe('start', function() { + it('should not explode', function(done) { + controller.start({ + onError: function() {} + }, function(err) { + expect(err).to.not.exist; + done(); + }); + }); + }); + + describe('onDisconnect', function() { + it('should work', function() { + controller.onDisconnect(); + + expect(emailDaoStub.onDisconnect.calledOnce).to.be.true; + }); + }); + + describe('logout', function() { + it('should work', function(done) { + authStub.logout.yields(); + emailDaoStub.onDisconnect.yields(new Error()); + + controller.onError = function(err) { + expect(err).to.exist; + expect(authStub.logout.calledOnce).to.be.true; + expect(emailDaoStub.onDisconnect.calledOnce).to.be.true; + done(); + }; + + controller.logout(); + }); + }); + + describe('onConnect', function() { + beforeEach(function() { + controller._emailDao._account = {}; + }); + + it('should not connect if offline', function(done) { + isOnlineStub.returns(false); + + controller.onConnect(function(err) { + expect(err).to.not.exist; + done(); + }); + }); + + it('should not connect if account is not initialized', function(done) { + controller._emailDao._account = null; + + controller.onConnect(function(err) { + expect(err).to.not.exist; + done(); + }); + }); + + it('should fail due to error in auth.getCredentials', function(done) { + isOnlineStub.returns(true); + authStub.getCredentials.yields(new Error()); + + controller.onConnect(function(err) { + expect(err).to.exist; + expect(authStub.getCredentials.calledOnce).to.be.true; + done(); + }); + }); + + it('should work', function(done) { + isOnlineStub.returns(true); + authStub.getCredentials.yields(null, { + emailAddress: 'asdf@example.com', + oauthToken: 'token', + sslCert: 'cert', + imap: {}, + smtp: {} + }); + emailDaoStub.onConnect.yields(); + + controller.onConnect(function(err) { + expect(err).to.not.exist; + expect(authStub.getCredentials.calledOnce).to.be.true; + expect(emailDaoStub.onConnect.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('init', function() { + var onConnectStub, emailAddress; beforeEach(function() { - controller._emailDao = emailDaoStub = sinon.createStubInstance(EmailDAO); - controller._outboxBo = outboxStub = sinon.createStubInstance(OutboxBO); - controller._appConfigStore = appConfigStoreStub = sinon.createStubInstance(DeviceStorageDAO); - controller._userStorage = devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); - controller._updateHandler = updateHandlerStub = sinon.createStubInstance(UpdateHandler); - controller._auth = authStub = sinon.createStubInstance(Auth); + emailAddress = 'alice@bob.com'; - isOnlineStub = sinon.stub(controller, 'isOnline'); + // onConnect + onConnectStub = sinon.stub(controller, 'onConnect'); }); afterEach(function() { - isOnlineStub.restore(); + onConnectStub.restore(); }); - describe('buildModules', function() { - it('should work', function() { - controller.buildModules({ - onError: function() {} - }); - expect(controller._appConfigStore).to.exist; - expect(controller._auth).to.exist; - expect(controller._userStorage).to.exist; - expect(controller._invitationDao).to.exist; - expect(controller._keychain).to.exist; - expect(controller._pgp).to.exist; - expect(controller._pgpbuilder).to.exist; - expect(controller._emailDao).to.exist; - expect(controller._outboxBo).to.exist; - expect(controller._updateHandler).to.exist; + it('should fail due to error in storage initialization', function(done) { + devicestorageStub.init.withArgs(undefined).yields({}); + + controller.init({}, function(err, keypair) { + expect(err).to.exist; + expect(keypair).to.not.exist; + expect(devicestorageStub.init.calledOnce).to.be.true; + expect(updateHandlerStub.update.calledOnce).to.be.false; + done(); }); }); - describe('start', function() { - it('should not explode', function(done) { - controller.start({ - onError: function() {} - }, function(err) { - expect(err).to.not.exist; - done(); - }); + it('should fail due to error in update handler', function(done) { + devicestorageStub.init.yields(); + updateHandlerStub.update.yields({}); + + controller.init({ + emailAddress: emailAddress + }, function(err, keypair) { + expect(err).to.exist; + expect(keypair).to.not.exist; + expect(updateHandlerStub.update.calledOnce).to.be.true; + expect(devicestorageStub.init.calledOnce).to.be.true; + done(); }); }); - describe('onDisconnect', function() { - it('should work', function() { - controller.onDisconnect(); + it('should fail due to error in emailDao.init', function(done) { + devicestorageStub.init.yields(); + updateHandlerStub.update.yields(); + emailDaoStub.init.yields({}); - expect(emailDaoStub.onDisconnect.calledOnce).to.be.true; + controller.init({ + emailAddress: emailAddress + }, function(err, keypair) { + expect(err).to.exist; + expect(keypair).to.not.exist; + expect(updateHandlerStub.update.calledOnce).to.be.true; + expect(emailDaoStub.init.calledOnce).to.be.true; + expect(devicestorageStub.init.calledOnce).to.be.true; + done(); }); }); - describe('logout', function() { - it('should work', function(done) { - authStub.logout.yields(); - emailDaoStub.onDisconnect.yields(new Error()); + it('should work and return a keypair', function(done) { + devicestorageStub.init.withArgs(emailAddress).yields(); + emailDaoStub.init.yields(null, {}); + updateHandlerStub.update.yields(); - controller.onError = function(err) { - expect(err).to.exist; - expect(authStub.logout.calledOnce).to.be.true; - expect(emailDaoStub.onDisconnect.calledOnce).to.be.true; - done(); - }; - - controller.logout(); - }); - }); - - describe('onConnect', function() { - beforeEach(function() { - controller._emailDao._account = {}; - }); - - it('should not connect if offline', function(done) { - isOnlineStub.returns(false); - - controller.onConnect(function(err) { - expect(err).to.not.exist; - done(); - }); - }); - - it('should not connect if account is not initialized', function(done) { - controller._emailDao._account = null; - - controller.onConnect(function(err) { - expect(err).to.not.exist; - done(); - }); - }); - - it('should fail due to error in auth.getCredentials', function(done) { - isOnlineStub.returns(true); - authStub.getCredentials.yields(new Error()); - - controller.onConnect(function(err) { - expect(err).to.exist; - expect(authStub.getCredentials.calledOnce).to.be.true; - done(); - }); - }); - - it('should work', function(done) { - isOnlineStub.returns(true); - authStub.getCredentials.yields(null, { - emailAddress: 'asdf@example.com', - oauthToken: 'token', - sslCert: 'cert', - imap: {}, - smtp: {} - }); - emailDaoStub.onConnect.yields(); - - controller.onConnect(function(err) { - expect(err).to.not.exist; - expect(authStub.getCredentials.calledOnce).to.be.true; - expect(emailDaoStub.onConnect.calledOnce).to.be.true; - done(); - }); - }); - }); - - describe('init', function() { - var onConnectStub, emailAddress; - - beforeEach(function() { - emailAddress = 'alice@bob.com'; - - // onConnect - onConnectStub = sinon.stub(controller, 'onConnect'); - }); - - afterEach(function() { - onConnectStub.restore(); - }); - - it('should fail due to error in storage initialization', function(done) { - devicestorageStub.init.withArgs(undefined).yields({}); - - controller.init({}, function(err, keypair) { - expect(err).to.exist; - expect(keypair).to.not.exist; - expect(devicestorageStub.init.calledOnce).to.be.true; - expect(updateHandlerStub.update.calledOnce).to.be.false; - done(); - }); - }); - - it('should fail due to error in update handler', function(done) { - devicestorageStub.init.yields(); - updateHandlerStub.update.yields({}); - - controller.init({ - emailAddress: emailAddress - }, function(err, keypair) { - expect(err).to.exist; - expect(keypair).to.not.exist; - expect(updateHandlerStub.update.calledOnce).to.be.true; - expect(devicestorageStub.init.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to error in emailDao.init', function(done) { - devicestorageStub.init.yields(); - updateHandlerStub.update.yields(); - emailDaoStub.init.yields({}); - - controller.init({ - emailAddress: emailAddress - }, function(err, keypair) { - expect(err).to.exist; - expect(keypair).to.not.exist; - expect(updateHandlerStub.update.calledOnce).to.be.true; - expect(emailDaoStub.init.calledOnce).to.be.true; - expect(devicestorageStub.init.calledOnce).to.be.true; - done(); - }); - }); - - it('should work and return a keypair', function(done) { - devicestorageStub.init.withArgs(emailAddress).yields(); - emailDaoStub.init.yields(null, {}); - updateHandlerStub.update.yields(); - - controller.init({ - emailAddress: emailAddress - }, function(err, keypair) { - expect(err).to.not.exist; - expect(keypair).to.exist; - expect(updateHandlerStub.update.calledOnce).to.be.true; - expect(emailDaoStub.init.calledOnce).to.be.true; - expect(devicestorageStub.init.calledOnce).to.be.true; - done(); - }); + controller.init({ + emailAddress: emailAddress + }, function(err, keypair) { + expect(err).to.not.exist; + expect(keypair).to.exist; + expect(updateHandlerStub.update.calledOnce).to.be.true; + expect(emailDaoStub.init.calledOnce).to.be.true; + expect(devicestorageStub.init.calledOnce).to.be.true; + done(); }); }); }); diff --git a/test/unit/auth-test.js b/test/unit/auth-test.js index 5df3c25..c3bea37 100644 --- a/test/unit/auth-test.js +++ b/test/unit/auth-test.js @@ -1,377 +1,374 @@ -define(function(require) { - 'use strict'; +'use strict'; - var Auth = require('js/bo/auth'), - OAuth = require('js/util/oauth'), - PGP = require('js/crypto/pgp'), - DeviceStorageDAO = require('js/dao/devicestorage-dao'), - expect = chai.expect; +var Auth = require('../../src/js/bo/auth'), + OAuth = require('../../src/js/util/oauth'), + PGP = require('../../src/js/crypto/pgp'), + DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'); - describe('Auth unit tests', function() { - // Constancts - var EMAIL_ADDR_DB_KEY = 'emailaddress'; - var USERNAME_DB_KEY = 'username'; - var REALNAME_DB_KEY = 'realname'; - var PASSWD_DB_KEY = 'password'; - var PROVIDER_DB_KEY = 'provider'; - var IMAP_DB_KEY = 'imap'; - var SMTP_DB_KEY = 'smtp'; - // SUT - var auth; +describe('Auth unit tests', function() { + // Constancts + var EMAIL_ADDR_DB_KEY = 'emailaddress'; + var USERNAME_DB_KEY = 'username'; + var REALNAME_DB_KEY = 'realname'; + var PASSWD_DB_KEY = 'password'; + var PROVIDER_DB_KEY = 'provider'; + var IMAP_DB_KEY = 'imap'; + var SMTP_DB_KEY = 'smtp'; + // SUT + var auth; - // Dependencies - var storageStub, oauthStub, pgpStub; + // Dependencies + var storageStub, oauthStub, pgpStub; - // test data - var emailAddress = 'bla@blubb.com'; - var password = 'passwordpasswordpassword'; - var encryptedPassword = 'pgppasswordpgppassword'; - var oauthToken = 'tokentokentokentoken'; - var provider = 'gmail'; - var realname = 'Bla Blubb'; - var username = 'bla'; - var imap = { - host: 'mail.blablubb.com', - port: 123, - secure: true, - ca: 'PEMPEMPEMPEMPEMPEMPEMPEMPEMPEM' - }; - var smtp = { - host: 'mail.blablubb.com', - port: 456, - secure: true, - ca: 'PEMPEMPEMPEMPEMPEMPEMPEMPEMPEM' - }; + // test data + var emailAddress = 'bla@blubb.com'; + var password = 'passwordpasswordpassword'; + var encryptedPassword = 'pgppasswordpgppassword'; + var oauthToken = 'tokentokentokentoken'; + var provider = 'gmail'; + var realname = 'Bla Blubb'; + var username = 'bla'; + var imap = { + host: 'mail.blablubb.com', + port: 123, + secure: true, + ca: 'PEMPEMPEMPEMPEMPEMPEMPEMPEMPEM' + }; + var smtp = { + host: 'mail.blablubb.com', + port: 456, + secure: true, + ca: 'PEMPEMPEMPEMPEMPEMPEMPEMPEMPEM' + }; - beforeEach(function() { - storageStub = sinon.createStubInstance(DeviceStorageDAO); - oauthStub = sinon.createStubInstance(OAuth); - pgpStub = sinon.createStubInstance(PGP); - auth = new Auth(storageStub, oauthStub, pgpStub); + beforeEach(function() { + storageStub = sinon.createStubInstance(DeviceStorageDAO); + oauthStub = sinon.createStubInstance(OAuth); + pgpStub = sinon.createStubInstance(PGP); + auth = new Auth(storageStub, oauthStub, pgpStub); + }); + + describe('#getCredentials', function() { + it('should load credentials and retrieve credentials from cfg', function(done) { + storageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY, 0, null).yieldsAsync(null, [emailAddress]); + storageStub.listItems.withArgs(PASSWD_DB_KEY, 0, null).yieldsAsync(null, [encryptedPassword]); + storageStub.listItems.withArgs(PROVIDER_DB_KEY, 0, null).yieldsAsync(null, [provider]); + storageStub.listItems.withArgs(USERNAME_DB_KEY, 0, null).yieldsAsync(null, [username]); + storageStub.listItems.withArgs(REALNAME_DB_KEY, 0, null).yieldsAsync(null, [realname]); + storageStub.listItems.withArgs(IMAP_DB_KEY, 0, null).yieldsAsync(null, [imap]); + storageStub.listItems.withArgs(SMTP_DB_KEY, 0, null).yieldsAsync(null, [smtp]); + pgpStub.decrypt.withArgs(encryptedPassword, undefined).yields(null, password); + + auth.getCredentials(function(err, cred) { + expect(err).to.not.exist; + + expect(auth.provider).to.equal(provider); + expect(auth.emailAddress).to.equal(emailAddress); + expect(auth.password).to.equal(password); + + expect(cred.imap.host).to.equal(imap.host); + expect(cred.imap.port).to.equal(imap.port); + expect(cred.imap.secure).to.equal(imap.secure); + expect(cred.imap.ca).to.equal(imap.ca); + expect(cred.imap.auth.user).to.equal(username); + expect(cred.imap.auth.pass).to.equal(password); + + expect(cred.smtp.host).to.equal(smtp.host); + expect(cred.smtp.port).to.equal(smtp.port); + expect(cred.smtp.secure).to.equal(smtp.secure); + expect(cred.smtp.ca).to.equal(smtp.ca); + expect(cred.smtp.auth.user).to.equal(username); + expect(cred.smtp.auth.pass).to.equal(password); + + expect(storageStub.listItems.callCount).to.equal(7); + expect(pgpStub.decrypt.calledOnce).to.be.true; + + done(); + }); + }); + }); + + describe('#setCredentials', function() { + it('should set the credentials', function() { + auth.setCredentials({ + provider: 'albhsvadlbvsdalbsadflb', + emailAddress: emailAddress, + username: username, + realname: realname, + password: password, + imap: imap, + smtp: smtp + }); + + expect(auth.provider).to.equal('albhsvadlbvsdalbsadflb'); + expect(auth.emailAddress).to.equal(emailAddress); + expect(auth.username).to.equal(username); + expect(auth.realname).to.equal(realname); + expect(auth.password).to.equal(password); + expect(auth.smtp).to.equal(smtp); + expect(auth.imap).to.equal(imap); + expect(auth.credentialsDirty).to.be.true; }); - describe('#getCredentials', function() { - it('should load credentials and retrieve credentials from cfg', function(done) { - storageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY, 0, null).yieldsAsync(null, [emailAddress]); - storageStub.listItems.withArgs(PASSWD_DB_KEY, 0, null).yieldsAsync(null, [encryptedPassword]); - storageStub.listItems.withArgs(PROVIDER_DB_KEY, 0, null).yieldsAsync(null, [provider]); - storageStub.listItems.withArgs(USERNAME_DB_KEY, 0, null).yieldsAsync(null, [username]); - storageStub.listItems.withArgs(REALNAME_DB_KEY, 0, null).yieldsAsync(null, [realname]); - storageStub.listItems.withArgs(IMAP_DB_KEY, 0, null).yieldsAsync(null, [imap]); - storageStub.listItems.withArgs(SMTP_DB_KEY, 0, null).yieldsAsync(null, [smtp]); - pgpStub.decrypt.withArgs(encryptedPassword, undefined).yields(null, password); + }); - auth.getCredentials(function(err, cred) { - expect(err).to.not.exist; + describe('#storeCredentials', function() { + it('should persist ALL the things!', function(done) { + auth.credentialsDirty = true; + auth.emailAddress = emailAddress; + auth.username = username; + auth.realname = realname; + auth.password = password; + auth.smtp = smtp; + auth.imap = imap; + auth.provider = provider; - expect(auth.provider).to.equal(provider); - expect(auth.emailAddress).to.equal(emailAddress); - expect(auth.password).to.equal(password); + storageStub.storeList.withArgs([encryptedPassword], PASSWD_DB_KEY).yieldsAsync(); + storageStub.storeList.withArgs([emailAddress], EMAIL_ADDR_DB_KEY).yieldsAsync(); + storageStub.storeList.withArgs([provider], PROVIDER_DB_KEY).yieldsAsync(); + storageStub.storeList.withArgs([username], USERNAME_DB_KEY).yieldsAsync(); + storageStub.storeList.withArgs([realname], REALNAME_DB_KEY).yieldsAsync(); + storageStub.storeList.withArgs([imap], IMAP_DB_KEY).yieldsAsync(); + storageStub.storeList.withArgs([smtp], SMTP_DB_KEY).yieldsAsync(); + pgpStub.encrypt.withArgs(password).yields(null, encryptedPassword); - expect(cred.imap.host).to.equal(imap.host); - expect(cred.imap.port).to.equal(imap.port); - expect(cred.imap.secure).to.equal(imap.secure); - expect(cred.imap.ca).to.equal(imap.ca); - expect(cred.imap.auth.user).to.equal(username); - expect(cred.imap.auth.pass).to.equal(password); + auth.storeCredentials(function(err) { + expect(err).to.not.exist; - expect(cred.smtp.host).to.equal(smtp.host); - expect(cred.smtp.port).to.equal(smtp.port); - expect(cred.smtp.secure).to.equal(smtp.secure); - expect(cred.smtp.ca).to.equal(smtp.ca); - expect(cred.smtp.auth.user).to.equal(username); - expect(cred.smtp.auth.pass).to.equal(password); + expect(storageStub.storeList.callCount).to.equal(7); + expect(pgpStub.encrypt.calledOnce).to.be.true; - expect(storageStub.listItems.callCount).to.equal(7); - expect(pgpStub.decrypt.calledOnce).to.be.true; + done(); + }); + }); + }); - done(); - }); + describe('#getOAuthToken', function() { + it('should refresh token with known email address', function(done) { + auth.emailAddress = emailAddress; + auth.oauthToken = 'oldToken'; + + oauthStub.refreshToken.withArgs({ + emailAddress: emailAddress, + oldToken: 'oldToken' + }).yieldsAsync(null, oauthToken); + + auth.getOAuthToken(function(err) { + expect(err).to.not.exist; + expect(auth.emailAddress).to.equal(emailAddress); + expect(auth.oauthToken).to.equal(oauthToken); + + expect(oauthStub.refreshToken.calledOnce).to.be.true; + + done(); }); }); - describe('#setCredentials', function() { - it('should set the credentials', function() { - auth.setCredentials({ - provider: 'albhsvadlbvsdalbsadflb', - emailAddress: emailAddress, - username: username, - realname: realname, - password: password, - imap: imap, - smtp: smtp - }); + it('should fetch token with known email address', function(done) { + auth.emailAddress = emailAddress; + oauthStub.getOAuthToken.withArgs(emailAddress).yieldsAsync(null, oauthToken); - expect(auth.provider).to.equal('albhsvadlbvsdalbsadflb'); + auth.getOAuthToken(function(err) { + expect(err).to.not.exist; expect(auth.emailAddress).to.equal(emailAddress); + expect(auth.oauthToken).to.equal(oauthToken); + + expect(oauthStub.getOAuthToken.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fetch token with unknown email address', function(done) { + oauthStub.getOAuthToken.withArgs(undefined).yieldsAsync(null, oauthToken); + oauthStub.queryEmailAddress.withArgs(oauthToken).yieldsAsync(null, emailAddress); + + auth.getOAuthToken(function(err) { + expect(err).to.not.exist; + expect(auth.emailAddress).to.equal(emailAddress); + expect(auth.oauthToken).to.equal(oauthToken); + + expect(oauthStub.getOAuthToken.calledOnce).to.be.true; + expect(oauthStub.queryEmailAddress.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when email address fetch fails', function(done) { + oauthStub.getOAuthToken.yieldsAsync(null, oauthToken); + oauthStub.queryEmailAddress.yieldsAsync(new Error()); + + auth.getOAuthToken(function(err) { + expect(err).to.exist; + expect(auth.emailAddress).to.not.exist; + expect(auth.oauthToken).to.not.exist; + + expect(oauthStub.getOAuthToken.calledOnce).to.be.true; + expect(oauthStub.queryEmailAddress.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when oauth fetch fails', function(done) { + oauthStub.getOAuthToken.yieldsAsync(new Error()); + + auth.getOAuthToken(function(err) { + expect(err).to.exist; + expect(auth.emailAddress).to.not.exist; + expect(auth.oauthToken).to.not.exist; + + expect(oauthStub.getOAuthToken.calledOnce).to.be.true; + expect(oauthStub.queryEmailAddress.called).to.be.false; + + done(); + }); + }); + }); + + describe('#_loadCredentials', function() { + it('should work', function(done) { + storageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY, 0, null).yieldsAsync(null, [emailAddress]); + storageStub.listItems.withArgs(PASSWD_DB_KEY, 0, null).yieldsAsync(null, [encryptedPassword]); + storageStub.listItems.withArgs(PROVIDER_DB_KEY, 0, null).yieldsAsync(null, [provider]); + storageStub.listItems.withArgs(USERNAME_DB_KEY, 0, null).yieldsAsync(null, [username]); + storageStub.listItems.withArgs(REALNAME_DB_KEY, 0, null).yieldsAsync(null, [realname]); + storageStub.listItems.withArgs(IMAP_DB_KEY, 0, null).yieldsAsync(null, [imap]); + storageStub.listItems.withArgs(SMTP_DB_KEY, 0, null).yieldsAsync(null, [smtp]); + + auth._loadCredentials(function(err) { + expect(err).to.not.exist; + expect(auth.emailAddress).to.equal(emailAddress); + expect(auth.password).to.equal(encryptedPassword); + expect(auth.provider).to.equal(provider); + expect(auth.imap).to.equal(imap); + expect(auth.smtp).to.equal(smtp); expect(auth.username).to.equal(username); expect(auth.realname).to.equal(realname); - expect(auth.password).to.equal(password); - expect(auth.smtp).to.equal(smtp); - expect(auth.imap).to.equal(imap); - expect(auth.credentialsDirty).to.be.true; - }); - }); + expect(auth.passwordNeedsDecryption).to.be.true; - describe('#storeCredentials', function() { - it('should persist ALL the things!', function(done) { - auth.credentialsDirty = true; - auth.emailAddress = emailAddress; - auth.username = username; - auth.realname = realname; - auth.password = password; - auth.smtp = smtp; - auth.imap = imap; - auth.provider = provider; + expect(storageStub.listItems.callCount).to.equal(7); - storageStub.storeList.withArgs([encryptedPassword], PASSWD_DB_KEY).yieldsAsync(); - storageStub.storeList.withArgs([emailAddress], EMAIL_ADDR_DB_KEY).yieldsAsync(); - storageStub.storeList.withArgs([provider], PROVIDER_DB_KEY).yieldsAsync(); - storageStub.storeList.withArgs([username], USERNAME_DB_KEY).yieldsAsync(); - storageStub.storeList.withArgs([realname], REALNAME_DB_KEY).yieldsAsync(); - storageStub.storeList.withArgs([imap], IMAP_DB_KEY).yieldsAsync(); - storageStub.storeList.withArgs([smtp], SMTP_DB_KEY).yieldsAsync(); - pgpStub.encrypt.withArgs(password).yields(null, encryptedPassword); - - auth.storeCredentials(function(err) { - expect(err).to.not.exist; - - expect(storageStub.storeList.callCount).to.equal(7); - expect(pgpStub.encrypt.calledOnce).to.be.true; - - done(); - }); + done(); }); }); - describe('#getOAuthToken', function() { - it('should refresh token with known email address', function(done) { - auth.emailAddress = emailAddress; - auth.oauthToken = 'oldToken'; + it('should fail', function(done) { + storageStub.listItems.yieldsAsync(new Error()); - oauthStub.refreshToken.withArgs({ - emailAddress: emailAddress, - oldToken: 'oldToken' - }).yieldsAsync(null, oauthToken); + auth._loadCredentials(function(err) { + expect(err).to.exist; + expect(auth.emailAddress).to.not.exist; + expect(auth.password).to.not.exist; + expect(auth.provider).to.not.exist; + expect(auth.imap).to.not.exist; + expect(auth.smtp).to.not.exist; + expect(auth.username).to.not.exist; + expect(auth.realname).to.not.exist; - auth.getOAuthToken(function(err) { - expect(err).to.not.exist; - expect(auth.emailAddress).to.equal(emailAddress); - expect(auth.oauthToken).to.equal(oauthToken); + expect(storageStub.listItems.calledOnce).to.be.true; - expect(oauthStub.refreshToken.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fetch token with known email address', function(done) { - auth.emailAddress = emailAddress; - oauthStub.getOAuthToken.withArgs(emailAddress).yieldsAsync(null, oauthToken); - - auth.getOAuthToken(function(err) { - expect(err).to.not.exist; - expect(auth.emailAddress).to.equal(emailAddress); - expect(auth.oauthToken).to.equal(oauthToken); - - expect(oauthStub.getOAuthToken.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fetch token with unknown email address', function(done) { - oauthStub.getOAuthToken.withArgs(undefined).yieldsAsync(null, oauthToken); - oauthStub.queryEmailAddress.withArgs(oauthToken).yieldsAsync(null, emailAddress); - - auth.getOAuthToken(function(err) { - expect(err).to.not.exist; - expect(auth.emailAddress).to.equal(emailAddress); - expect(auth.oauthToken).to.equal(oauthToken); - - expect(oauthStub.getOAuthToken.calledOnce).to.be.true; - expect(oauthStub.queryEmailAddress.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when email address fetch fails', function(done) { - oauthStub.getOAuthToken.yieldsAsync(null, oauthToken); - oauthStub.queryEmailAddress.yieldsAsync(new Error()); - - auth.getOAuthToken(function(err) { - expect(err).to.exist; - expect(auth.emailAddress).to.not.exist; - expect(auth.oauthToken).to.not.exist; - - expect(oauthStub.getOAuthToken.calledOnce).to.be.true; - expect(oauthStub.queryEmailAddress.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when oauth fetch fails', function(done) { - oauthStub.getOAuthToken.yieldsAsync(new Error()); - - auth.getOAuthToken(function(err) { - expect(err).to.exist; - expect(auth.emailAddress).to.not.exist; - expect(auth.oauthToken).to.not.exist; - - expect(oauthStub.getOAuthToken.calledOnce).to.be.true; - expect(oauthStub.queryEmailAddress.called).to.be.false; - - done(); - }); + done(); }); }); + }); - describe('#_loadCredentials', function() { - it('should work', function(done) { - storageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY, 0, null).yieldsAsync(null, [emailAddress]); - storageStub.listItems.withArgs(PASSWD_DB_KEY, 0, null).yieldsAsync(null, [encryptedPassword]); - storageStub.listItems.withArgs(PROVIDER_DB_KEY, 0, null).yieldsAsync(null, [provider]); - storageStub.listItems.withArgs(USERNAME_DB_KEY, 0, null).yieldsAsync(null, [username]); - storageStub.listItems.withArgs(REALNAME_DB_KEY, 0, null).yieldsAsync(null, [realname]); - storageStub.listItems.withArgs(IMAP_DB_KEY, 0, null).yieldsAsync(null, [imap]); - storageStub.listItems.withArgs(SMTP_DB_KEY, 0, null).yieldsAsync(null, [smtp]); + describe('#handleCertificateUpdate', function() { + var storeCredentialsStub; + var dummyCert = 'cert'; - auth._loadCredentials(function(err) { - expect(err).to.not.exist; - expect(auth.emailAddress).to.equal(emailAddress); - expect(auth.password).to.equal(encryptedPassword); - expect(auth.provider).to.equal(provider); - expect(auth.imap).to.equal(imap); - expect(auth.smtp).to.equal(smtp); - expect(auth.username).to.equal(username); - expect(auth.realname).to.equal(realname); + function onConnectDummy() {} - expect(auth.passwordNeedsDecryption).to.be.true; - - expect(storageStub.listItems.callCount).to.equal(7); - - done(); - }); - }); - - it('should fail', function(done) { - storageStub.listItems.yieldsAsync(new Error()); - - auth._loadCredentials(function(err) { - expect(err).to.exist; - expect(auth.emailAddress).to.not.exist; - expect(auth.password).to.not.exist; - expect(auth.provider).to.not.exist; - expect(auth.imap).to.not.exist; - expect(auth.smtp).to.not.exist; - expect(auth.username).to.not.exist; - expect(auth.realname).to.not.exist; - - expect(storageStub.listItems.calledOnce).to.be.true; - - done(); - }); - }); + beforeEach(function() { + storeCredentialsStub = sinon.stub(auth, 'storeCredentials'); }); - describe('#handleCertificateUpdate', function() { - var storeCredentialsStub; - var dummyCert = 'cert'; + it('should work for Trust on first use', function(done) { + auth.imap = {}; + storeCredentialsStub.yields(); - function onConnectDummy() {} + function callback(err) { + expect(err).to.not.exist; + expect(storeCredentialsStub.callCount).to.equal(1); + done(); + } + auth.handleCertificateUpdate('imap', onConnectDummy, callback, dummyCert); + }); - beforeEach(function() { - storeCredentialsStub = sinon.stub(auth, 'storeCredentials'); - }); + it('should work for stored cert', function() { + auth.imap = { + ca: dummyCert + }; + storeCredentialsStub.yields(); - it('should work for Trust on first use', function(done) { - auth.imap = {}; - storeCredentialsStub.yields(); + auth.handleCertificateUpdate('imap', onConnectDummy, onConnectDummy, dummyCert); + expect(storeCredentialsStub.callCount).to.equal(0); + }); - function callback(err) { - expect(err).to.not.exist; - expect(storeCredentialsStub.callCount).to.equal(1); - done(); - } - auth.handleCertificateUpdate('imap', onConnectDummy, callback, dummyCert); - }); + it('should work for pinned cert', function(done) { + auth.imap = { + ca: 'other', + pinned: true + }; + storeCredentialsStub.yields(); - it('should work for stored cert', function() { - auth.imap = { - ca: dummyCert - }; - storeCredentialsStub.yields(); - - auth.handleCertificateUpdate('imap', onConnectDummy, onConnectDummy, dummyCert); + function callback(err) { + expect(err).to.exist; + expect(err.message).to.exist; expect(storeCredentialsStub.callCount).to.equal(0); - }); + done(); + } + auth.handleCertificateUpdate('imap', onConnectDummy, callback, dummyCert); + }); - it('should work for pinned cert', function(done) { - auth.imap = { - ca: 'other', - pinned: true - }; - storeCredentialsStub.yields(); + it('should work for updated cert', function(done) { + auth.imap = { + ca: 'other' + }; + storeCredentialsStub.yields(); - function callback(err) { + function callback(err) { + if (err && err.callback) { expect(err).to.exist; expect(err.message).to.exist; expect(storeCredentialsStub.callCount).to.equal(0); + err.callback(true); + } else { + expect(storeCredentialsStub.callCount).to.equal(1); done(); } - auth.handleCertificateUpdate('imap', onConnectDummy, callback, dummyCert); - }); + } - it('should work for updated cert', function(done) { - auth.imap = { - ca: 'other' - }; - storeCredentialsStub.yields(); + function onConnect(callback) { + callback(); + } - function callback(err) { - if (err && err.callback) { - expect(err).to.exist; - expect(err.message).to.exist; - expect(storeCredentialsStub.callCount).to.equal(0); - err.callback(true); - } else { - expect(storeCredentialsStub.callCount).to.equal(1); - done(); - } - } + auth.handleCertificateUpdate('imap', onConnect, callback, dummyCert); + }); + }); - function onConnect(callback) { - callback(); - } + describe('#logout', function() { + it('should fail to to error in calling db clear', function(done) { + storageStub.clear.yields(new Error()); - auth.handleCertificateUpdate('imap', onConnect, callback, dummyCert); + auth.logout(function(err) { + expect(err).to.exist; + done(); }); }); - describe('#logout', function() { - it('should fail to to error in calling db clear', function(done) { - storageStub.clear.yields(new Error()); + it('should work', function(done) { + storageStub.clear.yields(); - auth.logout(function(err) { - expect(err).to.exist; - done(); - }); - }); - - it('should work', function(done) { - storageStub.clear.yields(); - - auth.logout(function(err) { - expect(err).to.not.exist; - expect(auth.password).to.be.undefined; - expect(auth.initialized).to.be.undefined; - expect(auth.credentialsDirty).to.be.undefined; - expect(auth.passwordNeedsDecryption).to.be.undefined; - done(); - }); + auth.logout(function(err) { + expect(err).to.not.exist; + expect(auth.password).to.be.undefined; + expect(auth.initialized).to.be.undefined; + expect(auth.credentialsDirty).to.be.undefined; + expect(auth.passwordNeedsDecryption).to.be.undefined; + done(); }); }); }); diff --git a/test/unit/backbutton-handler-test.js b/test/unit/backbutton-handler-test.js index 3e312b3..66fc05b 100644 --- a/test/unit/backbutton-handler-test.js +++ b/test/unit/backbutton-handler-test.js @@ -1,67 +1,64 @@ -define(function(require) { - 'use strict'; +'use strict'; - var btnHandler = require('js/util/backbutton-handler'), - expect = chai.expect; +var btnHandler = require('../../src/js/util/backbutton-handler'); - describe('Backbutton Handler', function() { - chai.Assertion.includeStack = true; +describe('Backbutton Handler', function() { + chai.Assertion.includeStack = true; - var scope, event; + var scope, event; - beforeEach(function() { - scope = { - state: {}, - $apply: function() {} - }; + beforeEach(function() { + scope = { + state: {}, + $apply: function() {} + }; - event = new CustomEvent('backbutton'); + event = new CustomEvent('backbutton'); - // this is a precondition for the test. throw an exception - // if this would produce side effects - expect(navigator.app).to.not.exist; - navigator.app = {}; + // this is a precondition for the test. throw an exception + // if this would produce side effects + expect(navigator.app).to.not.exist; + navigator.app = {}; - btnHandler.attachHandler(scope); - btnHandler.start(); - }); + btnHandler.attachHandler(scope); + btnHandler.start(); + }); - afterEach(function() { - btnHandler.stop(); - delete navigator.app; - }); + afterEach(function() { + btnHandler.stop(); + delete navigator.app; + }); - it('should close lightbox', function() { - scope.state.lightbox = 'asd'; - document.dispatchEvent(event); - expect(scope.state.lightbox).to.be.undefined; - }); + it('should close lightbox', function() { + scope.state.lightbox = 'asd'; + document.dispatchEvent(event); + expect(scope.state.lightbox).to.be.undefined; + }); - it('should close reader', function() { - scope.state.read = { - open: true, - toggle: function(state) { - scope.state.read.open = state; - } - }; - document.dispatchEvent(event); - expect(scope.state.read.open).to.be.false; - }); + it('should close reader', function() { + scope.state.read = { + open: true, + toggle: function(state) { + scope.state.read.open = state; + } + }; + document.dispatchEvent(event); + expect(scope.state.read.open).to.be.false; + }); - it('should close navigation', function() { - scope.state.nav = { - open: true, - toggle: function(state) { - scope.state.nav.open = state; - } - }; - document.dispatchEvent(event); - expect(scope.state.nav.open).to.be.false; - }); + it('should close navigation', function() { + scope.state.nav = { + open: true, + toggle: function(state) { + scope.state.nav.open = state; + } + }; + document.dispatchEvent(event); + expect(scope.state.nav.open).to.be.false; + }); - it('should close app', function(done) { - navigator.app.exitApp = done; - document.dispatchEvent(event); - }); + it('should close app', function(done) { + navigator.app.exitApp = done; + document.dispatchEvent(event); }); }); \ No newline at end of file diff --git a/test/unit/connection-doctor-test.js b/test/unit/connection-doctor-test.js index 1ffeb08..7a50499 100644 --- a/test/unit/connection-doctor-test.js +++ b/test/unit/connection-doctor-test.js @@ -1,413 +1,410 @@ -define(function(require) { - 'use strict'; +'use strict'; - var ConnectionDoctor = require('js/util/connection-doctor'), - TCPSocket = require('tcp-socket'), - ImapClient = require('imap-client'), - SmtpClient = require('smtpclient'), - cfg = require('js/app-config').config, - expect = chai.expect; +var TCPSocket = require('tcp-socket'), + ImapClient = require('imap-client'), + SmtpClient = require('wo-smtpclient'), + ConnectionDoctor = require('../../src/js/util/connection-doctor'), + cfg = require('../../src/js/app-config').config; - describe('Connection Doctor', function() { - var doctor; - var socketStub, imapStub, smtpStub, credentials; +describe('Connection Doctor', function() { + var doctor; + var socketStub, imapStub, smtpStub, credentials; - beforeEach(function() { - // - // Stubs - // + beforeEach(function() { + // + // Stubs + // - // there is no socket shim for for this use case, use dummy object - socketStub = { - close: function() { - this.onclose(); + // there is no socket shim for for this use case, use dummy object + socketStub = { + close: function() { + this.onclose(); + } + }; + + imapStub = sinon.createStubInstance(ImapClient); + smtpStub = sinon.createStubInstance(SmtpClient); + + // + // Fixture + // + credentials = { + imap: { + host: 'asd', + port: 1234, + secure: true, + ca: 'cert' + }, + smtp: { + host: 'qwe', + port: 5678, + secure: false, + ca: 'cert' + }, + username: 'username', + password: 'password' + }; + + sinon.stub(TCPSocket, 'open').returns(socketStub); // convenience constructors suck + + // + // Setup SUT + // + doctor = new ConnectionDoctor(); + doctor.configure(credentials); + doctor._imap = imapStub; + doctor._smtp = smtpStub; + }); + + afterEach(function() { + TCPSocket.open.restore(); + }); + + describe('#_checkOnline', function() { + it('should check if browser is online', function(done) { + doctor._checkOnline(function(error) { + if (navigator.onLine) { + expect(error).to.not.exist; + } else { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.OFFLINE); } - }; + done(); + }); + }); + }); - imapStub = sinon.createStubInstance(ImapClient); - smtpStub = sinon.createStubInstance(SmtpClient); + describe('#_checkReachable', function() { + it('should be able to reach the host w/o cert', function(done) { + credentials.imap.ca = undefined; - // - // Fixture - // - credentials = { - imap: { - host: 'asd', - port: 1234, - secure: true, - ca: 'cert' - }, - smtp: { - host: 'qwe', - port: 5678, - secure: false, - ca: 'cert' - }, - username: 'username', - password: 'password' - }; + doctor._checkReachable(credentials.imap, function(error) { + expect(error).to.not.exist; + expect(TCPSocket.open.calledOnce).to.be.true; + expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, { + binaryType: 'arraybuffer', + useSecureTransport: credentials.imap.secure, + ca: credentials.imap.ca + })).to.be.true; - sinon.stub(TCPSocket, 'open').returns(socketStub); // convenience constructors suck + done(); + }); - // - // Setup SUT - // - doctor = new ConnectionDoctor(); - doctor.configure(credentials); - doctor._imap = imapStub; - doctor._smtp = smtpStub; + socketStub.oncert(); + socketStub.onopen(); }); - afterEach(function() { - TCPSocket.open.restore(); + it('should catch Mozilla TCPSocket exception', function(done) { + // Mozilla forbids extensions to the TCPSocket object + Object.defineProperty(socketStub, 'oncert', { + set: function() { + throw 'Mozilla specific behavior'; + } + }); + + doctor._checkReachable(credentials.imap, function(error) { + expect(error).to.not.exist; + expect(TCPSocket.open.calledOnce).to.be.true; + expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, { + binaryType: 'arraybuffer', + useSecureTransport: credentials.imap.secure, + ca: credentials.imap.ca + })).to.be.true; + + done(); + }); + + socketStub.onopen(); }); - describe('#_checkOnline', function() { - it('should check if browser is online', function(done) { - doctor._checkOnline(function(error) { - if (navigator.onLine) { - expect(error).to.not.exist; - } else { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.OFFLINE); - } - done(); - }); + it('should fail w/ wrong cert', function(done) { + doctor._checkReachable(credentials.imap, function(error) { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.TLS_WRONG_CERT); + expect(TCPSocket.open.calledOnce).to.be.true; + expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, { + binaryType: 'arraybuffer', + useSecureTransport: credentials.imap.secure, + ca: credentials.imap.ca + })).to.be.true; + + done(); + }); + + socketStub.oncert(); + socketStub.onerror(); + socketStub.onclose(); + }); + + it('should fail w/ host unreachable', function(done) { + doctor._checkReachable(credentials.imap, function(error) { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.HOST_UNREACHABLE); + expect(TCPSocket.open.calledOnce).to.be.true; + + done(); + }); + + socketStub.onerror({ + data: new Error() + }); + socketStub.onclose(); + }); + + it('should fail w/ timeout', function(done) { + var origTimeout = cfg.connDocTimeout; // remember timeout from the config to reset it on done + cfg.connDocTimeout = 20; // set to 20ms for the test + + doctor._checkReachable(credentials.imap, function(error) { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.HOST_TIMEOUT); + expect(TCPSocket.open.calledOnce).to.be.true; + cfg.connDocTimeout = origTimeout; + + done(); + }); + }); + }); + + describe('#_checkImap', function() { + it('should perform IMAP login, list folders, logout', function(done) { + imapStub.login.yieldsAsync(); + imapStub.listWellKnownFolders.yieldsAsync(null, { + Inbox: [{}] + }); + imapStub.logout.yieldsAsync(); + + doctor._checkImap(function(error) { + expect(error).to.not.exist; + expect(imapStub.login.calledOnce).to.be.true; + expect(imapStub.listWellKnownFolders.calledOnce).to.be.true; + expect(imapStub.logout.calledOnce).to.be.true; + + done(); }); }); - describe('#_checkReachable', function() { - it('should be able to reach the host w/o cert', function(done) { - credentials.imap.ca = undefined; - - doctor._checkReachable(credentials.imap, function(error) { - expect(error).to.not.exist; - expect(TCPSocket.open.calledOnce).to.be.true; - expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, { - binaryType: 'arraybuffer', - useSecureTransport: credentials.imap.secure, - ca: credentials.imap.ca - })).to.be.true; - - done(); - }); - - socketStub.oncert(); - socketStub.onopen(); + it('should fail w/ generic error on logout', function(done) { + imapStub.login.yieldsAsync(); + imapStub.listWellKnownFolders.yieldsAsync(null, { + Inbox: [{}] }); - it('should catch Mozilla TCPSocket exception', function(done) { - // Mozilla forbids extensions to the TCPSocket object - Object.defineProperty(socketStub, 'oncert', { - set: function() { - throw 'Mozilla specific behavior'; - } - }); + doctor._checkImap(function(error) { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.GENERIC_ERROR); + expect(error.underlyingError).to.exist; + expect(imapStub.login.calledOnce).to.be.true; + expect(imapStub.listWellKnownFolders.calledOnce).to.be.true; + expect(imapStub.logout.calledOnce).to.be.true; - doctor._checkReachable(credentials.imap, function(error) { - expect(error).to.not.exist; - expect(TCPSocket.open.calledOnce).to.be.true; - expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, { - binaryType: 'arraybuffer', - useSecureTransport: credentials.imap.secure, - ca: credentials.imap.ca - })).to.be.true; - - done(); - }); - - socketStub.onopen(); + done(); }); - it('should fail w/ wrong cert', function(done) { - doctor._checkReachable(credentials.imap, function(error) { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.TLS_WRONG_CERT); - expect(TCPSocket.open.calledOnce).to.be.true; - expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, { - binaryType: 'arraybuffer', - useSecureTransport: credentials.imap.secure, - ca: credentials.imap.ca - })).to.be.true; + setTimeout(function() { + // this error is thrown while we're waiting for the logout + imapStub.onError(new Error()); + }, 50); + }); - done(); - }); - - socketStub.oncert(); - socketStub.onerror(); - socketStub.onclose(); + it('should fail w/ generic error on inbox missing', function(done) { + imapStub.login.yieldsAsync(); + imapStub.listWellKnownFolders.yieldsAsync(null, { + Inbox: [] }); - it('should fail w/ host unreachable', function(done) { - doctor._checkReachable(credentials.imap, function(error) { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.HOST_UNREACHABLE); - expect(TCPSocket.open.calledOnce).to.be.true; + doctor._checkImap(function(error) { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.NO_INBOX); + expect(imapStub.login.calledOnce).to.be.true; + expect(imapStub.listWellKnownFolders.calledOnce).to.be.true; + expect(imapStub.logout.called).to.be.false; - done(); - }); - - socketStub.onerror({ - data: new Error() - }); - socketStub.onclose(); - }); - - it('should fail w/ timeout', function(done) { - var origTimeout = cfg.connDocTimeout; // remember timeout from the config to reset it on done - cfg.connDocTimeout = 20; // set to 20ms for the test - - doctor._checkReachable(credentials.imap, function(error) { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.HOST_TIMEOUT); - expect(TCPSocket.open.calledOnce).to.be.true; - cfg.connDocTimeout = origTimeout; - - done(); - }); + done(); }); }); - describe('#_checkImap', function() { - it('should perform IMAP login, list folders, logout', function(done) { - imapStub.login.yieldsAsync(); - imapStub.listWellKnownFolders.yieldsAsync(null, { - Inbox: [{}] - }); - imapStub.logout.yieldsAsync(); + it('should fail w/ generic error on listing folders fails', function(done) { + imapStub.login.yieldsAsync(); + imapStub.listWellKnownFolders.yieldsAsync(new Error()); - doctor._checkImap(function(error) { - expect(error).to.not.exist; - expect(imapStub.login.calledOnce).to.be.true; - expect(imapStub.listWellKnownFolders.calledOnce).to.be.true; - expect(imapStub.logout.calledOnce).to.be.true; + doctor._checkImap(function(error) { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.GENERIC_ERROR); + expect(error.underlyingError).to.exist; + expect(imapStub.login.calledOnce).to.be.true; + expect(imapStub.listWellKnownFolders.calledOnce).to.be.true; + expect(imapStub.logout.called).to.be.false; - done(); - }); - }); - - it('should fail w/ generic error on logout', function(done) { - imapStub.login.yieldsAsync(); - imapStub.listWellKnownFolders.yieldsAsync(null, { - Inbox: [{}] - }); - - doctor._checkImap(function(error) { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.GENERIC_ERROR); - expect(error.underlyingError).to.exist; - expect(imapStub.login.calledOnce).to.be.true; - expect(imapStub.listWellKnownFolders.calledOnce).to.be.true; - expect(imapStub.logout.calledOnce).to.be.true; - - done(); - }); - - setTimeout(function() { - // this error is thrown while we're waiting for the logout - imapStub.onError(new Error()); - }, 50); - }); - - it('should fail w/ generic error on inbox missing', function(done) { - imapStub.login.yieldsAsync(); - imapStub.listWellKnownFolders.yieldsAsync(null, { - Inbox: [] - }); - - doctor._checkImap(function(error) { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.NO_INBOX); - expect(imapStub.login.calledOnce).to.be.true; - expect(imapStub.listWellKnownFolders.calledOnce).to.be.true; - expect(imapStub.logout.called).to.be.false; - - done(); - }); - }); - - it('should fail w/ generic error on listing folders fails', function(done) { - imapStub.login.yieldsAsync(); - imapStub.listWellKnownFolders.yieldsAsync(new Error()); - - doctor._checkImap(function(error) { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.GENERIC_ERROR); - expect(error.underlyingError).to.exist; - expect(imapStub.login.calledOnce).to.be.true; - expect(imapStub.listWellKnownFolders.calledOnce).to.be.true; - expect(imapStub.logout.called).to.be.false; - - done(); - }); - }); - - it('should fail w/ auth rejected', function(done) { - doctor._checkImap(function(error) { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.AUTH_REJECTED); - expect(error.underlyingError).to.exist; - expect(imapStub.login.calledOnce).to.be.true; - expect(imapStub.listWellKnownFolders.called).to.be.false; - expect(imapStub.logout.called).to.be.false; - - done(); - }); - - setTimeout(function() { - // this error is thrown while we're waiting for the login - imapStub.onError(new Error()); - }, 50); + done(); }); }); - describe('#_checkSmtp', function() { - it('should perform SMTP login, logout', function(done) { - doctor._checkSmtp(function(error) { - expect(error).to.not.exist; - expect(smtpStub.connect.calledOnce).to.be.true; - expect(smtpStub.quit.calledOnce).to.be.true; + it('should fail w/ auth rejected', function(done) { + doctor._checkImap(function(error) { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.AUTH_REJECTED); + expect(error.underlyingError).to.exist; + expect(imapStub.login.calledOnce).to.be.true; + expect(imapStub.listWellKnownFolders.called).to.be.false; + expect(imapStub.logout.called).to.be.false; - done(); - }); - - smtpStub.onidle(); - smtpStub.onclose(); + done(); }); - it('should fail w/ auth rejected', function(done) { - doctor._checkSmtp(function(error) { - expect(error).to.exist; - expect(error.code).to.equal(ConnectionDoctor.AUTH_REJECTED); - expect(error.underlyingError).to.exist; - expect(smtpStub.connect.calledOnce).to.be.true; - expect(smtpStub.quit.called).to.be.false; + setTimeout(function() { + // this error is thrown while we're waiting for the login + imapStub.onError(new Error()); + }, 50); + }); + }); - done(); - }); + describe('#_checkSmtp', function() { + it('should perform SMTP login, logout', function(done) { + doctor._checkSmtp(function(error) { + expect(error).to.not.exist; + expect(smtpStub.connect.calledOnce).to.be.true; + expect(smtpStub.quit.calledOnce).to.be.true; - smtpStub.onerror(new Error()); + done(); + }); + + smtpStub.onidle(); + smtpStub.onclose(); + }); + + it('should fail w/ auth rejected', function(done) { + doctor._checkSmtp(function(error) { + expect(error).to.exist; + expect(error.code).to.equal(ConnectionDoctor.AUTH_REJECTED); + expect(error.underlyingError).to.exist; + expect(smtpStub.connect.calledOnce).to.be.true; + expect(smtpStub.quit.called).to.be.false; + + done(); + }); + + smtpStub.onerror(new Error()); + }); + }); + + describe('#check', function() { + beforeEach(function() { + sinon.stub(doctor, '_checkOnline'); + sinon.stub(doctor, '_checkReachable'); + sinon.stub(doctor, '_checkImap'); + sinon.stub(doctor, '_checkSmtp'); + }); + + it('should perform all tests', function(done) { + doctor._checkOnline.yieldsAsync(); + doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(); + doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(); + doctor._checkImap.yieldsAsync(); + doctor._checkSmtp.yieldsAsync(); + + doctor.check(function(err) { + expect(err).to.not.exist; + expect(doctor._checkOnline.calledOnce).to.be.true; + expect(doctor._checkReachable.calledTwice).to.be.true; + expect(doctor._checkImap.calledOnce).to.be.true; + expect(doctor._checkSmtp.calledOnce).to.be.true; + + done(); }); }); - describe('#check', function() { - beforeEach(function() { - sinon.stub(doctor, '_checkOnline'); - sinon.stub(doctor, '_checkReachable'); - sinon.stub(doctor, '_checkImap'); - sinon.stub(doctor, '_checkSmtp'); + it('should fail for smtp', function(done) { + doctor._checkOnline.yieldsAsync(); + doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(); + doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(); + doctor._checkImap.yieldsAsync(); + doctor._checkSmtp.yieldsAsync(new Error()); + + doctor.check(function(err) { + expect(err).to.exist; + expect(doctor._checkOnline.calledOnce).to.be.true; + expect(doctor._checkReachable.calledTwice).to.be.true; + expect(doctor._checkImap.calledOnce).to.be.true; + expect(doctor._checkSmtp.calledOnce).to.be.true; + + done(); }); + }); - it('should perform all tests', function(done) { - doctor._checkOnline.yieldsAsync(); - doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(); - doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(); - doctor._checkImap.yieldsAsync(); - doctor._checkSmtp.yieldsAsync(); + it('should fail for imap', function(done) { + doctor._checkOnline.yieldsAsync(); + doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(); + doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(); + doctor._checkImap.yieldsAsync(new Error()); - doctor.check(function(err) { - expect(err).to.not.exist; - expect(doctor._checkOnline.calledOnce).to.be.true; - expect(doctor._checkReachable.calledTwice).to.be.true; - expect(doctor._checkImap.calledOnce).to.be.true; - expect(doctor._checkSmtp.calledOnce).to.be.true; + doctor.check(function(err) { + expect(err).to.exist; + expect(doctor._checkOnline.calledOnce).to.be.true; + expect(doctor._checkReachable.calledTwice).to.be.true; + expect(doctor._checkImap.calledOnce).to.be.true; + expect(doctor._checkSmtp.called).to.be.false; - done(); - }); + done(); }); + }); - it('should fail for smtp', function(done) { - doctor._checkOnline.yieldsAsync(); - doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(); - doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(); - doctor._checkImap.yieldsAsync(); - doctor._checkSmtp.yieldsAsync(new Error()); + it('should fail for smtp reachability', function(done) { + doctor._checkOnline.yieldsAsync(); + doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(); + doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(new Error()); - doctor.check(function(err) { - expect(err).to.exist; - expect(doctor._checkOnline.calledOnce).to.be.true; - expect(doctor._checkReachable.calledTwice).to.be.true; - expect(doctor._checkImap.calledOnce).to.be.true; - expect(doctor._checkSmtp.calledOnce).to.be.true; + doctor.check(function(err) { + expect(err).to.exist; + expect(doctor._checkOnline.calledOnce).to.be.true; + expect(doctor._checkReachable.calledTwice).to.be.true; + expect(doctor._checkImap.called).to.be.false; + expect(doctor._checkSmtp.called).to.be.false; - done(); - }); + done(); }); + }); - it('should fail for imap', function(done) { - doctor._checkOnline.yieldsAsync(); - doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(); - doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(); - doctor._checkImap.yieldsAsync(new Error()); + it('should fail for imap reachability', function(done) { + doctor._checkOnline.yieldsAsync(); + doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(new Error()); - doctor.check(function(err) { - expect(err).to.exist; - expect(doctor._checkOnline.calledOnce).to.be.true; - expect(doctor._checkReachable.calledTwice).to.be.true; - expect(doctor._checkImap.calledOnce).to.be.true; - expect(doctor._checkSmtp.called).to.be.false; + doctor.check(function(err) { + expect(err).to.exist; + expect(doctor._checkOnline.calledOnce).to.be.true; + expect(doctor._checkReachable.calledOnce).to.be.true; + expect(doctor._checkImap.called).to.be.false; + expect(doctor._checkSmtp.called).to.be.false; - done(); - }); + done(); }); + }); - it('should fail for smtp reachability', function(done) { - doctor._checkOnline.yieldsAsync(); - doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(); - doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(new Error()); + it('should fail for offline', function(done) { + doctor._checkOnline.yieldsAsync(new Error()); - doctor.check(function(err) { - expect(err).to.exist; - expect(doctor._checkOnline.calledOnce).to.be.true; - expect(doctor._checkReachable.calledTwice).to.be.true; - expect(doctor._checkImap.called).to.be.false; - expect(doctor._checkSmtp.called).to.be.false; + doctor.check(function(err) { + expect(err).to.exist; + expect(doctor._checkOnline.calledOnce).to.be.true; + expect(doctor._checkReachable.called).to.be.false; + expect(doctor._checkImap.called).to.be.false; + expect(doctor._checkSmtp.called).to.be.false; - done(); - }); + done(); }); + }); - it('should fail for imap reachability', function(done) { - doctor._checkOnline.yieldsAsync(); - doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(new Error()); + it('should fail w/o config', function(done) { + doctor.credentials = doctor._imap = doctor._smtp = undefined; - doctor.check(function(err) { - expect(err).to.exist; - expect(doctor._checkOnline.calledOnce).to.be.true; - expect(doctor._checkReachable.calledOnce).to.be.true; - expect(doctor._checkImap.called).to.be.false; - expect(doctor._checkSmtp.called).to.be.false; + doctor.check(function(err) { + expect(err).to.exist; + expect(doctor._checkOnline.called).to.be.false; + expect(doctor._checkReachable.called).to.be.false; + expect(doctor._checkImap.called).to.be.false; + expect(doctor._checkSmtp.called).to.be.false; - done(); - }); - }); - - it('should fail for offline', function(done) { - doctor._checkOnline.yieldsAsync(new Error()); - - doctor.check(function(err) { - expect(err).to.exist; - expect(doctor._checkOnline.calledOnce).to.be.true; - expect(doctor._checkReachable.called).to.be.false; - expect(doctor._checkImap.called).to.be.false; - expect(doctor._checkSmtp.called).to.be.false; - - done(); - }); - }); - - it('should fail w/o config', function(done) { - doctor.credentials = doctor._imap = doctor._smtp = undefined; - - doctor.check(function(err) { - expect(err).to.exist; - expect(doctor._checkOnline.called).to.be.false; - expect(doctor._checkReachable.called).to.be.false; - expect(doctor._checkImap.called).to.be.false; - expect(doctor._checkSmtp.called).to.be.false; - - done(); - }); + done(); }); }); }); diff --git a/test/unit/contacts-ctrl-test.js b/test/unit/contacts-ctrl-test.js index 15085ef..05212c4 100644 --- a/test/unit/contacts-ctrl-test.js +++ b/test/unit/contacts-ctrl-test.js @@ -1,190 +1,186 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - ContactsCtrl = require('js/controller/contacts'), - appController = require('js/app-controller'), - KeychainDAO = require('js/dao/keychain-dao'), - PGP = require('js/crypto/pgp'); +var mocks = angular.mocks, + ContactsCtrl = require('../../src/js/controller/contacts'), + appController = require('../../src/js/app-controller'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + PGP = require('../../src/js/crypto/pgp'); - describe('Contacts Controller unit test', function() { - var scope, contactsCtrl, - origKeychain, keychainMock, - origPgp, pgpMock; +describe('Contacts Controller unit test', function() { + var scope, contactsCtrl, + origKeychain, keychainMock, + origPgp, pgpMock; - beforeEach(function() { - origPgp = appController._pgp; - appController._pgp = pgpMock = sinon.createStubInstance(PGP); - origKeychain = appController._keychain; - appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); + beforeEach(function() { + origPgp = appController._pgp; + appController._pgp = pgpMock = sinon.createStubInstance(PGP); + origKeychain = appController._keychain; + appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); - angular.module('contactstest', []); - mocks.module('contactstest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = {}; - contactsCtrl = $controller(ContactsCtrl, { - $scope: scope - }); - }); - }); - - afterEach(function() { - // restore the module - appController._pgp = origPgp; - appController._keychain = origKeychain; - }); - - describe('scope variables', function() { - it('should be set correctly', function() { - expect(scope.fingerprint).to.equal('XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX'); - expect(scope.state.contacts.toggle).to.exist; - }); - }); - - describe('listKeys', function() { - it('should fail due to error in keychain.listLocalPublicKeys', function(done) { - keychainMock.listLocalPublicKeys.yields(42); - - scope.onError = function(err) { - expect(err).to.equal(42); - done(); - }; - - scope.listKeys(); - }); - - it('should work', function(done) { - keychainMock.listLocalPublicKeys.yields(null, [{ - _id: '12345' - }]); - pgpMock.getKeyParams.returns({ - fingerprint: 'asdf' - }); - - scope.$apply = function() { - expect(scope.keys.length).to.equal(1); - expect(scope.keys[0]._id).to.equal('12345'); - expect(scope.keys[0].fingerprint).to.equal('asdf'); - done(); - }; - - expect(scope.keys).to.not.exist; - scope.listKeys(); - }); - }); - - describe('getFingerprint', function() { - it('should work', function() { - var key = { - fingerprint: 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY' - }; - - scope.getFingerprint(key); - - expect(scope.fingerprint).to.equal('YYYY YYYY YYYY YYYY YYYY ... YYYY YYYY YYYY YYYY YYYY'); - }); - }); - - describe('importKey', function() { - it('should work', function(done) { - var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; - - pgpMock.getKeyParams.returns({ - _id: '12345', - userId: 'max@example.com', - userIds: [] - }); - - keychainMock.saveLocalPublicKey.withArgs({ - _id: '12345', - userId: 'max@example.com', - userIds: [], - publicKey: '-----BEGIN PGP PUBLIC KEY BLOCK-----', - imported: true - }).yields(); - - scope.listKeys = function() { - done(); - }; - - scope.importKey(keyArmored); - }); - - it('should fail due to invalid armored key', function(done) { - var keyArmored = '-----BEGIN PGP PRIVATE KEY BLOCK-----'; - - scope.onError = function(err) { - expect(err).to.exist; - done(); - }; - - scope.importKey(keyArmored); - }); - - it('should fail due to error in pgp.getKeyParams', function(done) { - var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; - - pgpMock.getKeyParams.throws(new Error('WAT')); - - scope.onError = function(err) { - expect(err).to.exist; - done(); - }; - - scope.importKey(keyArmored); - }); - - it('should fail due to error in keychain.saveLocalPublicKey', function(done) { - var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; - - pgpMock.getKeyParams.returns({ - _id: '12345', - userId: 'max@example.com' - }); - - keychainMock.saveLocalPublicKey.yields(42); - - scope.onError = function(err) { - expect(err).to.equal(42); - done(); - }; - - scope.importKey(keyArmored); - }); - }); - - describe('removeKey', function() { - it('should work', function(done) { - var key = { - _id: '12345' - }; - - keychainMock.removeLocalPublicKey.withArgs('12345').yields(); - - scope.listKeys = function() { - done(); - }; - - scope.removeKey(key); - }); - - it('should fail due to error in keychain.removeLocalPublicKey', function(done) { - var key = { - _id: '12345' - }; - - keychainMock.removeLocalPublicKey.withArgs('12345').yields(42); - - scope.onError = function(err) { - expect(err).to.equal(42); - done(); - }; - - scope.removeKey(key); + angular.module('contactstest', []); + mocks.module('contactstest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = {}; + contactsCtrl = $controller(ContactsCtrl, { + $scope: scope }); }); }); + + afterEach(function() { + // restore the module + appController._pgp = origPgp; + appController._keychain = origKeychain; + }); + + describe('scope variables', function() { + it('should be set correctly', function() { + expect(scope.fingerprint).to.equal('XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX'); + expect(scope.state.contacts.toggle).to.exist; + }); + }); + + describe('listKeys', function() { + it('should fail due to error in keychain.listLocalPublicKeys', function(done) { + keychainMock.listLocalPublicKeys.yields(42); + + scope.onError = function(err) { + expect(err).to.equal(42); + done(); + }; + + scope.listKeys(); + }); + + it('should work', function(done) { + keychainMock.listLocalPublicKeys.yields(null, [{ + _id: '12345' + }]); + pgpMock.getKeyParams.returns({ + fingerprint: 'asdf' + }); + + scope.$apply = function() { + expect(scope.keys.length).to.equal(1); + expect(scope.keys[0]._id).to.equal('12345'); + expect(scope.keys[0].fingerprint).to.equal('asdf'); + done(); + }; + + expect(scope.keys).to.not.exist; + scope.listKeys(); + }); + }); + + describe('getFingerprint', function() { + it('should work', function() { + var key = { + fingerprint: 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY' + }; + + scope.getFingerprint(key); + + expect(scope.fingerprint).to.equal('YYYY YYYY YYYY YYYY YYYY ... YYYY YYYY YYYY YYYY YYYY'); + }); + }); + + describe('importKey', function() { + it('should work', function(done) { + var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; + + pgpMock.getKeyParams.returns({ + _id: '12345', + userId: 'max@example.com', + userIds: [] + }); + + keychainMock.saveLocalPublicKey.withArgs({ + _id: '12345', + userId: 'max@example.com', + userIds: [], + publicKey: '-----BEGIN PGP PUBLIC KEY BLOCK-----', + imported: true + }).yields(); + + scope.listKeys = function() { + done(); + }; + + scope.importKey(keyArmored); + }); + + it('should fail due to invalid armored key', function(done) { + var keyArmored = '-----BEGIN PGP PRIVATE KEY BLOCK-----'; + + scope.onError = function(err) { + expect(err).to.exist; + done(); + }; + + scope.importKey(keyArmored); + }); + + it('should fail due to error in pgp.getKeyParams', function(done) { + var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; + + pgpMock.getKeyParams.throws(new Error('WAT')); + + scope.onError = function(err) { + expect(err).to.exist; + done(); + }; + + scope.importKey(keyArmored); + }); + + it('should fail due to error in keychain.saveLocalPublicKey', function(done) { + var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; + + pgpMock.getKeyParams.returns({ + _id: '12345', + userId: 'max@example.com' + }); + + keychainMock.saveLocalPublicKey.yields(42); + + scope.onError = function(err) { + expect(err).to.equal(42); + done(); + }; + + scope.importKey(keyArmored); + }); + }); + + describe('removeKey', function() { + it('should work', function(done) { + var key = { + _id: '12345' + }; + + keychainMock.removeLocalPublicKey.withArgs('12345').yields(); + + scope.listKeys = function() { + done(); + }; + + scope.removeKey(key); + }); + + it('should fail due to error in keychain.removeLocalPublicKey', function(done) { + var key = { + _id: '12345' + }; + + keychainMock.removeLocalPublicKey.withArgs('12345').yields(42); + + scope.onError = function(err) { + expect(err).to.equal(42); + done(); + }; + + scope.removeKey(key); + }); + }); }); \ No newline at end of file diff --git a/test/unit/crypto-test.js b/test/unit/crypto-test.js index 5cbe272..7647514 100644 --- a/test/unit/crypto-test.js +++ b/test/unit/crypto-test.js @@ -1,58 +1,55 @@ -define(function(require) { - 'use strict'; +'use strict'; - var Crypto = require('js/crypto/crypto'), - util = require('js/crypto/util'), - config = require('js/app-config').config, - expect = chai.expect; +var Crypto = require('../../src/js/crypto/crypto'), + config = require('../../src/js/app-config').config, + util = require('crypto-lib').util; - describe('Crypto unit tests', function() { - this.timeout(20000); +describe('Crypto unit tests', function() { + this.timeout(20000); - var crypto, - password = 'password', - keySize = config.symKeySize, - ivSize = config.symIvSize; + var crypto, + password = 'password', + keySize = config.symKeySize, + ivSize = config.symIvSize; - beforeEach(function() { - crypto = new Crypto(); - }); + beforeEach(function() { + crypto = new Crypto(); + }); - afterEach(function() {}); + afterEach(function() {}); - describe('AES encrypt/decrypt', function() { - it('should work', function(done) { - var plaintext = 'Hello, World!'; - var key = util.random(keySize); - var iv = util.random(ivSize); + describe('AES encrypt/decrypt', function() { + it('should work', function(done) { + var plaintext = 'Hello, World!'; + var key = util.random(keySize); + var iv = util.random(ivSize); - crypto.encrypt(plaintext, key, iv, function(err, ciphertext) { + crypto.encrypt(plaintext, key, iv, function(err, ciphertext) { + expect(err).to.not.exist; + expect(ciphertext).to.exist; + + crypto.decrypt(ciphertext, key, iv, function(err, decrypted) { expect(err).to.not.exist; - expect(ciphertext).to.exist; - - crypto.decrypt(ciphertext, key, iv, function(err, decrypted) { - expect(err).to.not.exist; - expect(decrypted).to.equal(plaintext); - - done(); - }); - }); - }); - }); - - describe("PBKDF2 (Async/Worker)", function() { - it('should work', function(done) { - var salt = util.random(keySize); - - crypto.deriveKey(password, salt, keySize, function(err, key) { - expect(err).to.not.exist; - expect(util.base642Str(key).length * 8).to.equal(keySize); + expect(decrypted).to.equal(plaintext); done(); }); }); + }); + }); + describe("PBKDF2 (Async/Worker)", function() { + it('should work', function(done) { + var salt = util.random(keySize); + + crypto.deriveKey(password, salt, keySize, function(err, key) { + expect(err).to.not.exist; + expect(util.base642Str(key).length * 8).to.equal(keySize); + + done(); + }); }); }); + }); \ No newline at end of file diff --git a/test/unit/devicestorage-dao-test.js b/test/unit/devicestorage-dao-test.js index f593e39..1cc49d5 100644 --- a/test/unit/devicestorage-dao-test.js +++ b/test/unit/devicestorage-dao-test.js @@ -1,105 +1,101 @@ -define(function(require) { - 'use strict'; +'use strict'; - var LawnchairDAO = require('js/dao/lawnchair-dao'), - DeviceStorageDAO = require('js/dao/devicestorage-dao'), - expect = chai.expect; +var LawnchairDAO = require('../../src/js/dao/lawnchair-dao'), + DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'); - var testUser = 'test@example.com'; +var testUser = 'test@example.com'; - describe('Device Storage DAO unit tests', function() { +describe('Device Storage DAO unit tests', function() { - var storageDao, lawnchairDaoStub; + var storageDao, lawnchairDaoStub; - beforeEach(function() { - lawnchairDaoStub = sinon.createStubInstance(LawnchairDAO); - storageDao = new DeviceStorageDAO(lawnchairDaoStub); + beforeEach(function() { + lawnchairDaoStub = sinon.createStubInstance(LawnchairDAO); + storageDao = new DeviceStorageDAO(lawnchairDaoStub); + }); + + afterEach(function() {}); + + describe('init', function() { + it('should work', function(done) { + lawnchairDaoStub.init.yields(); + + storageDao.init(testUser, function(err) { + expect(err).to.not.exist; + expect(lawnchairDaoStub.init.calledOnce).to.be.true; + done(); + }); }); + }); - afterEach(function() {}); + describe('store list', function() { + it('should fail', function(done) { + var list = [{}]; - describe('init', function() { - it('should work', function(done) { - lawnchairDaoStub.init.yields(); - - storageDao.init(testUser, function(err) { - expect(err).to.not.exist; - expect(lawnchairDaoStub.init.calledOnce).to.be.true; - done(); - }); + storageDao.storeList(list, '', function(err) { + expect(err).to.exist; + done(); }); }); - describe('store list', function() { - it('should fail', function(done) { - var list = [{}]; + it('should work with empty list', function(done) { + var list = []; - storageDao.storeList(list, '', function(err) { - expect(err).to.exist; - done(); - }); - }); - - it('should work with empty list', function(done) { - var list = []; - - storageDao.storeList(list, 'email', function(err) { - expect(err).to.not.exist; - done(); - }); - }); - - it('should work', function(done) { - lawnchairDaoStub.batch.yields(); - - var list = [{ - foo: 'bar' - }]; - - storageDao.storeList(list, 'email', function(err) { - expect(err).to.not.exist; - expect(lawnchairDaoStub.batch.calledOnce).to.be.true; - done(); - }); + storageDao.storeList(list, 'email', function(err) { + expect(err).to.not.exist; + done(); }); }); - describe('remove list', function() { - it('should work', function(done) { - lawnchairDaoStub.removeList.yields(); + it('should work', function(done) { + lawnchairDaoStub.batch.yields(); - storageDao.removeList('email', function(err) { - expect(err).to.not.exist; - expect(lawnchairDaoStub.removeList.calledOnce).to.be.true; - done(); - }); + var list = [{ + foo: 'bar' + }]; + + storageDao.storeList(list, 'email', function(err) { + expect(err).to.not.exist; + expect(lawnchairDaoStub.batch.calledOnce).to.be.true; + done(); }); }); + }); - describe('list items', function() { - it('should work', function(done) { - lawnchairDaoStub.list.yields(); + describe('remove list', function() { + it('should work', function(done) { + lawnchairDaoStub.removeList.yields(); - storageDao.listItems('email', 0, null, function(err) { - expect(err).to.not.exist; - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - done(); - }); + storageDao.removeList('email', function(err) { + expect(err).to.not.exist; + expect(lawnchairDaoStub.removeList.calledOnce).to.be.true; + done(); }); }); + }); - describe('clear', function() { - it('should work', function(done) { - lawnchairDaoStub.clear.yields(); + describe('list items', function() { + it('should work', function(done) { + lawnchairDaoStub.list.yields(); - storageDao.clear(function(err) { - expect(err).to.not.exist; - expect(lawnchairDaoStub.clear.calledOnce).to.be.true; - done(); - }); + storageDao.listItems('email', 0, null, function(err) { + expect(err).to.not.exist; + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + done(); }); }); + }); + describe('clear', function() { + it('should work', function(done) { + lawnchairDaoStub.clear.yields(); + + storageDao.clear(function(err) { + expect(err).to.not.exist; + expect(lawnchairDaoStub.clear.calledOnce).to.be.true; + done(); + }); + }); }); }); \ No newline at end of file diff --git a/test/unit/dialog-ctrl-test.js b/test/unit/dialog-ctrl-test.js index 7ff73cd..191cd4f 100644 --- a/test/unit/dialog-ctrl-test.js +++ b/test/unit/dialog-ctrl-test.js @@ -1,50 +1,46 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - DialogCtrl = require('js/controller/dialog'); +var mocks = angular.mocks, + DialogCtrl = require('../../src/js/controller/dialog'); - describe('Dialog Controller unit test', function() { - var scope, dialogCtrl; +describe('Dialog Controller unit test', function() { + var scope, dialogCtrl; - beforeEach(function() { - angular.module('dialogtest', []); - mocks.module('dialogtest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = { - dialog: {} - }; - dialogCtrl = $controller(DialogCtrl, { - $scope: scope - }); - }); - }); - - afterEach(function() {}); - - describe('confirm', function() { - it('should work', function(done) { - scope.state.dialog.callback = function(confirmed) { - expect(confirmed).to.be.true; - expect(scope.state.dialog.open).to.be.false; - done(); - }; - scope.confirm(true); - }); - }); - - describe('cancel', function() { - it('should work', function(done) { - scope.state.dialog.callback = function(confirmed) { - expect(confirmed).to.be.false; - expect(scope.state.dialog.open).to.be.false; - done(); - }; - scope.confirm(false); + beforeEach(function() { + angular.module('dialogtest', []); + mocks.module('dialogtest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = { + dialog: {} + }; + dialogCtrl = $controller(DialogCtrl, { + $scope: scope }); }); }); + + afterEach(function() {}); + + describe('confirm', function() { + it('should work', function(done) { + scope.state.dialog.callback = function(confirmed) { + expect(confirmed).to.be.true; + expect(scope.state.dialog.open).to.be.false; + done(); + }; + scope.confirm(true); + }); + }); + + describe('cancel', function() { + it('should work', function(done) { + scope.state.dialog.callback = function(confirmed) { + expect(confirmed).to.be.false; + expect(scope.state.dialog.open).to.be.false; + done(); + }; + scope.confirm(false); + }); + }); }); \ No newline at end of file diff --git a/test/unit/email-dao-test.js b/test/unit/email-dao-test.js index 305f8f1..0ba3553 100644 --- a/test/unit/email-dao-test.js +++ b/test/unit/email-dao-test.js @@ -1,2304 +1,2301 @@ -define(function(require) { - 'use strict'; +'use strict'; - var EmailDAO = require('js/dao/email-dao'), - KeychainDAO = require('js/dao/keychain-dao'), - ImapClient = require('imap-client'), - PgpMailer = require('pgpmailer'), - PgpBuilder = require('pgpbuilder'), - PGP = require('js/crypto/pgp'), - DeviceStorageDAO = require('js/dao/devicestorage-dao'), - mailreader = require('mailreader'), - cfg = require('js/app-config').config, - expect = chai.expect; +var mailreader = require('mailreader'), + ImapClient = require('imap-client'), + PgpMailer = require('pgpmailer'), + PgpBuilder = require('pgpbuilder'), + cfg = require('../../src/js/app-config').config, + EmailDAO = require('../../src/js/dao/email-dao'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + PGP = require('../../src/js/crypto/pgp'), + DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'); - describe('Email DAO unit tests', function() { - // show the stack trace when an error occurred - chai.Assertion.includeStack = true; +describe('Email DAO unit tests', function() { + // show the stack trace when an error occurred + chai.Assertion.includeStack = true; - // SUT - var dao; + // SUT + var dao; - // mocks - var keychainStub, imapClientStub, pgpMailerStub, pgpBuilderStub, pgpStub, devicestorageStub, parseStub; + // mocks + var keychainStub, imapClientStub, pgpMailerStub, pgpBuilderStub, pgpStub, devicestorageStub, parseStub; - // config - var emailAddress, passphrase, asymKeySize, account; + // config + var emailAddress, passphrase, asymKeySize, account; + // test data + var folders, inboxFolder, sentFolder, draftsFolder, outboxFolder, trashFolder, mockKeyPair; + + beforeEach(function() { + // // test data - var folders, inboxFolder, sentFolder, draftsFolder, outboxFolder, trashFolder, mockKeyPair; + // + emailAddress = 'asdf@asdf.com'; + passphrase = 'asdf'; + asymKeySize = 2048; - beforeEach(function() { - // - // test data - // - emailAddress = 'asdf@asdf.com'; - passphrase = 'asdf'; - asymKeySize = 2048; + inboxFolder = { + name: 'Inbox', + type: 'Inbox', + path: 'INBOX', + messages: [] + }; - inboxFolder = { - name: 'Inbox', - type: 'Inbox', - path: 'INBOX', - messages: [] - }; + sentFolder = { + name: 'Sent', + type: 'Sent', + path: 'SENT', + messages: [] + }; - sentFolder = { - name: 'Sent', - type: 'Sent', - path: 'SENT', - messages: [] - }; + draftsFolder = { + name: 'Drafts', + type: 'Drafts', + path: 'DRAFTS', + messages: [] + }; - draftsFolder = { - name: 'Drafts', - type: 'Drafts', - path: 'DRAFTS', - messages: [] - }; + outboxFolder = { + name: 'Outbox', + type: 'Outbox', + path: 'OUTBOX', + messages: [] + }; - outboxFolder = { - name: 'Outbox', - type: 'Outbox', - path: 'OUTBOX', - messages: [] - }; + trashFolder = { + name: 'Trash', + type: 'Trash', + path: 'TRASH', + messages: [] + }; - trashFolder = { - name: 'Trash', - type: 'Trash', - path: 'TRASH', - messages: [] - }; + folders = [inboxFolder, outboxFolder, trashFolder, sentFolder]; - folders = [inboxFolder, outboxFolder, trashFolder, sentFolder]; + account = { + emailAddress: emailAddress, + asymKeySize: asymKeySize, + folders: folders, + online: true + }; - account = { - emailAddress: emailAddress, - asymKeySize: asymKeySize, - folders: folders, - online: true - }; + mockKeyPair = { + publicKey: { + _id: 1234, + userId: emailAddress, + publicKey: 'publicpublicpublicpublic' + }, + privateKey: { + _id: 1234, + userId: emailAddress, + encryptedKey: 'privateprivateprivateprivate' + } + }; - mockKeyPair = { - publicKey: { - _id: 1234, - userId: emailAddress, - publicKey: 'publicpublicpublicpublic' - }, - privateKey: { - _id: 1234, - userId: emailAddress, - encryptedKey: 'privateprivateprivateprivate' - } - }; + // + // setup the mocks + // + keychainStub = sinon.createStubInstance(KeychainDAO); + imapClientStub = sinon.createStubInstance(ImapClient); + pgpMailerStub = sinon.createStubInstance(PgpMailer); + pgpBuilderStub = sinon.createStubInstance(PgpBuilder); + pgpStub = sinon.createStubInstance(PGP); + parseStub = sinon.stub(mailreader, 'parse'); + devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); - // - // setup the mocks - // - keychainStub = sinon.createStubInstance(KeychainDAO); - imapClientStub = sinon.createStubInstance(ImapClient); - pgpMailerStub = sinon.createStubInstance(PgpMailer); - pgpBuilderStub = sinon.createStubInstance(PgpBuilder); - pgpStub = sinon.createStubInstance(PGP); - parseStub = sinon.stub(mailreader, 'parse'); - devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); + // + // setup the SUT + // + dao = new EmailDAO(keychainStub, pgpStub, devicestorageStub, pgpBuilderStub, mailreader); + dao._account = account; + dao._pgpMailer = pgpMailerStub; + dao._imapClient = imapClientStub; - // - // setup the SUT - // - dao = new EmailDAO(keychainStub, pgpStub, devicestorageStub, pgpBuilderStub, mailreader); - dao._account = account; - dao._pgpMailer = pgpMailerStub; - dao._imapClient = imapClientStub; + // + // check configuration + // + expect(dao._keychain).to.equal(keychainStub); + expect(dao._pgp).to.equal(pgpStub); + expect(dao._devicestorage).to.equal(devicestorageStub); + expect(dao._mailreader).to.equal(mailreader); + expect(dao._pgpbuilder).to.equal(pgpBuilderStub); + }); - // - // check configuration - // - expect(dao._keychain).to.equal(keychainStub); - expect(dao._pgp).to.equal(pgpStub); - expect(dao._devicestorage).to.equal(devicestorageStub); - expect(dao._mailreader).to.equal(mailreader); - expect(dao._pgpbuilder).to.equal(pgpBuilderStub); - }); + afterEach(function() { + mailreader.parse.restore(); + }); - afterEach(function() { - mailreader.parse.restore(); - }); + describe('public API', function() { + describe('#init', function() { + var initFoldersStub; - describe('public API', function() { - describe('#init', function() { - var initFoldersStub; + beforeEach(function() { + delete dao._account; + initFoldersStub = sinon.stub(dao, '_initFoldersFromDisk'); + }); - beforeEach(function() { - delete dao._account; - initFoldersStub = sinon.stub(dao, '_initFoldersFromDisk'); - }); + it('should initialize folders and return keypair', function(done) { + keychainStub.getUserKeyPair.withArgs(emailAddress).yieldsAsync(null, mockKeyPair); + initFoldersStub.yieldsAsync(); - it('should initialize folders and return keypair', function(done) { - keychainStub.getUserKeyPair.withArgs(emailAddress).yieldsAsync(null, mockKeyPair); - initFoldersStub.yieldsAsync(); + dao.init({ + account: account + }, function(err, keypair) { + expect(err).to.not.exist; + expect(keypair).to.exist; + expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; + expect(initFoldersStub.calledOnce).to.be.true; - dao.init({ - account: account - }, function(err, keypair) { - expect(err).to.not.exist; - expect(keypair).to.exist; - expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; - expect(initFoldersStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when keychain errors', function(done) { - keychainStub.getUserKeyPair.yieldsAsync({}); - - dao.init({ - account: account - }, function(err, keypair) { - expect(err).to.exist; - expect(keypair).to.not.exist; - expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; - expect(initFoldersStub.called).to.be.false; - - done(); - }); + done(); }); }); - describe('#unlock', function() { - it('should unlock', function(done) { - pgpStub.getKeyParams.returns({ - _id: mockKeyPair.publicKey._id, - userId: emailAddress, - userIds: [{ - emailAddress: emailAddress - }] - }); + it('should fail when keychain errors', function(done) { + keychainStub.getUserKeyPair.yieldsAsync({}); - pgpStub.importKeys.withArgs({ - passphrase: passphrase, - privateKeyArmored: mockKeyPair.privateKey.encryptedKey, - publicKeyArmored: mockKeyPair.publicKey.publicKey - }).yieldsAsync(); - pgpStub._privateKey = { - foo: 'bar' - }; + dao.init({ + account: account + }, function(err, keypair) { + expect(err).to.exist; + expect(keypair).to.not.exist; + expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; + expect(initFoldersStub.called).to.be.false; - dao.unlock({ - passphrase: passphrase, - keypair: mockKeyPair - }, function(err) { - expect(err).to.not.exist; + done(); + }); + }); + }); - expect(pgpStub.importKeys.calledOnce).to.be.true; - expect(dao._pgpbuilder._privateKey).to.equal(pgpStub._privateKey); - - done(); - }); + describe('#unlock', function() { + it('should unlock', function(done) { + pgpStub.getKeyParams.returns({ + _id: mockKeyPair.publicKey._id, + userId: emailAddress, + userIds: [{ + emailAddress: emailAddress + }] }); - it('should generate a keypair and unlock', function(done) { - var keypair = { - keyId: 123, - publicKeyArmored: mockKeyPair.publicKey.publicKey, - privateKeyArmored: mockKeyPair.privateKey.encryptedKey - }; + pgpStub.importKeys.withArgs({ + passphrase: passphrase, + privateKeyArmored: mockKeyPair.privateKey.encryptedKey, + publicKeyArmored: mockKeyPair.publicKey.publicKey + }).yieldsAsync(); + pgpStub._privateKey = { + foo: 'bar' + }; - pgpStub.generateKeys.withArgs({ - emailAddress: emailAddress, - keySize: asymKeySize, - passphrase: passphrase - }).yieldsAsync(null, keypair); + dao.unlock({ + passphrase: passphrase, + keypair: mockKeyPair + }, function(err) { + expect(err).to.not.exist; - pgpStub.importKeys.withArgs({ - passphrase: passphrase, - privateKeyArmored: mockKeyPair.privateKey.encryptedKey, - publicKeyArmored: mockKeyPair.publicKey.publicKey - }).yieldsAsync(); - keychainStub.putUserKeyPair.withArgs().yieldsAsync(); + expect(pgpStub.importKeys.calledOnce).to.be.true; + expect(dao._pgpbuilder._privateKey).to.equal(pgpStub._privateKey); - dao.unlock({ - passphrase: passphrase - }, function(err) { - expect(err).to.not.exist; - - expect(pgpStub.generateKeys.calledOnce).to.be.true; - expect(pgpStub.importKeys.calledOnce).to.be.true; - expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when persisting fails', function(done) { - var keypair = { - keyId: 123, - publicKeyArmored: 'qwerty', - privateKeyArmored: 'asdfgh' - }; - pgpStub.generateKeys.yieldsAsync(null, keypair); - pgpStub.importKeys.withArgs().yieldsAsync(); - keychainStub.putUserKeyPair.yieldsAsync({}); - - dao.unlock({ - passphrase: passphrase - }, function(err) { - expect(err).to.exist; - - expect(pgpStub.generateKeys.calledOnce).to.be.true; - expect(pgpStub.importKeys.calledOnce).to.be.true; - expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when import fails', function(done) { - var keypair = { - keyId: 123, - publicKeyArmored: 'qwerty', - privateKeyArmored: 'asdfgh' - }; - - pgpStub.generateKeys.withArgs().yieldsAsync(null, keypair); - pgpStub.importKeys.withArgs().yieldsAsync({}); - - dao.unlock({ - passphrase: passphrase - }, function(err) { - expect(err).to.exist; - - expect(pgpStub.generateKeys.calledOnce).to.be.true; - expect(pgpStub.importKeys.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when generation fails', function(done) { - pgpStub.generateKeys.yieldsAsync({}); - - dao.unlock({ - passphrase: passphrase - }, function(err) { - expect(err).to.exist; - - expect(pgpStub.generateKeys.calledOnce).to.be.true; - - done(); - }); + done(); }); }); - describe('#openFolder', function() { - it('should open an imap mailbox', function(done) { - imapClientStub.selectMailbox.withArgs({ - path: inboxFolder.path - }).yieldsAsync(); + it('should generate a keypair and unlock', function(done) { + var keypair = { + keyId: 123, + publicKeyArmored: mockKeyPair.publicKey.publicKey, + privateKeyArmored: mockKeyPair.privateKey.encryptedKey + }; - dao.openFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.not.exist; - expect(imapClientStub.selectMailbox.calledOnce).to.be.true; - done(); - }); + pgpStub.generateKeys.withArgs({ + emailAddress: emailAddress, + keySize: asymKeySize, + passphrase: passphrase + }).yieldsAsync(null, keypair); + + pgpStub.importKeys.withArgs({ + passphrase: passphrase, + privateKeyArmored: mockKeyPair.privateKey.encryptedKey, + publicKeyArmored: mockKeyPair.publicKey.publicKey + }).yieldsAsync(); + keychainStub.putUserKeyPair.withArgs().yieldsAsync(); + + dao.unlock({ + passphrase: passphrase + }, function(err) { + expect(err).to.not.exist; + + expect(pgpStub.generateKeys.calledOnce).to.be.true; + expect(pgpStub.importKeys.calledOnce).to.be.true; + expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when persisting fails', function(done) { + var keypair = { + keyId: 123, + publicKeyArmored: 'qwerty', + privateKeyArmored: 'asdfgh' + }; + pgpStub.generateKeys.yieldsAsync(null, keypair); + pgpStub.importKeys.withArgs().yieldsAsync(); + keychainStub.putUserKeyPair.yieldsAsync({}); + + dao.unlock({ + passphrase: passphrase + }, function(err) { + expect(err).to.exist; + + expect(pgpStub.generateKeys.calledOnce).to.be.true; + expect(pgpStub.importKeys.calledOnce).to.be.true; + expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when import fails', function(done) { + var keypair = { + keyId: 123, + publicKeyArmored: 'qwerty', + privateKeyArmored: 'asdfgh' + }; + + pgpStub.generateKeys.withArgs().yieldsAsync(null, keypair); + pgpStub.importKeys.withArgs().yieldsAsync({}); + + dao.unlock({ + passphrase: passphrase + }, function(err) { + expect(err).to.exist; + + expect(pgpStub.generateKeys.calledOnce).to.be.true; + expect(pgpStub.importKeys.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when generation fails', function(done) { + pgpStub.generateKeys.yieldsAsync({}); + + dao.unlock({ + passphrase: passphrase + }, function(err) { + expect(err).to.exist; + + expect(pgpStub.generateKeys.calledOnce).to.be.true; + + done(); + }); + }); + }); + + describe('#openFolder', function() { + it('should open an imap mailbox', function(done) { + imapClientStub.selectMailbox.withArgs({ + path: inboxFolder.path + }).yieldsAsync(); + + dao.openFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.not.exist; + expect(imapClientStub.selectMailbox.calledOnce).to.be.true; + done(); + }); + }); + + it('should not open the virtual outbox folder in imap', function() { + dao.openFolder({ + folder: outboxFolder }); - it('should not open the virtual outbox folder in imap', function() { - dao.openFolder({ - folder: outboxFolder - }); + expect(imapClientStub.selectMailbox.called).to.be.false; + }); + it('should not do anything in offline mode', function(done) { + account.online = false; + + dao.openFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.exist; expect(imapClientStub.selectMailbox.called).to.be.false; + done(); }); - it('should not do anything in offline mode', function(done) { - account.online = false; + }); + }); - dao.openFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.exist; - expect(imapClientStub.selectMailbox.called).to.be.false; - done(); - }); + describe('#refreshFolder', function() { + var localListStub, mail; + beforeEach(function() { + localListStub = sinon.stub(dao, '_localListMessages'); + mail = { + uid: 123, + unread: true + }; + }); + + it('should add messages from disk', function(done) { + localListStub.withArgs({ + folder: inboxFolder + }).yieldsAsync(null, [mail]); + + dao.refreshFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.count).to.equal(1); + expect(inboxFolder.messages).to.contain(mail); + + done(); }); }); - describe('#refreshFolder', function() { - var localListStub, mail; + it('should not add messages from disk', function(done) { + inboxFolder.messages = [mail]; + localListStub.withArgs({ + folder: inboxFolder + }).yieldsAsync(null, [mail]); - beforeEach(function() { - localListStub = sinon.stub(dao, '_localListMessages'); - mail = { - uid: 123, - unread: true - }; - }); + dao.refreshFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.count).to.equal(1); + expect(inboxFolder.messages).to.contain(mail); - it('should add messages from disk', function(done) { - localListStub.withArgs({ - folder: inboxFolder - }).yieldsAsync(null, [mail]); - - dao.refreshFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.count).to.equal(1); - expect(inboxFolder.messages).to.contain(mail); - - done(); - }); - }); - - it('should not add messages from disk', function(done) { - inboxFolder.messages = [mail]; - localListStub.withArgs({ - folder: inboxFolder - }).yieldsAsync(null, [mail]); - - dao.refreshFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.count).to.equal(1); - expect(inboxFolder.messages).to.contain(mail); - - done(); - }); - }); - - it('should remove messages from memory', function(done) { - inboxFolder.messages = [mail]; - localListStub.withArgs({ - folder: inboxFolder - }).yieldsAsync(null, []); - - dao.refreshFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.count).to.equal(0); - expect(inboxFolder.messages).to.be.empty; - - done(); - }); + done(); }); }); - describe('#fetchMessages', function() { - var imapListStub, imapGetStub, imapDeleteStub, localStoreStub; - var opts, message, validUuid, corruptedUuid, verificationSubject; - var notified; + it('should remove messages from memory', function(done) { + inboxFolder.messages = [mail]; + localListStub.withArgs({ + folder: inboxFolder + }).yieldsAsync(null, []); - beforeEach(function() { - imapListStub = sinon.stub(dao, '_imapListMessages'); - imapDeleteStub = sinon.stub(dao, '_imapDeleteMessage'); - imapGetStub = sinon.stub(dao, '_getBodyParts'); - localStoreStub = sinon.stub(dao, '_localStoreMessages'); + dao.refreshFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.count).to.equal(0); + expect(inboxFolder.messages).to.be.empty; - opts = { - folder: inboxFolder, - firstUid: 123, - lastUid: 123 - }; - message = { - uid: 123, - subject: 'asdasd', - unread: true, - bodyParts: [] - }; - validUuid = '9A858952-17EE-4273-9E74-D309EAFDFAFB'; - corruptedUuid = 'OMFG_FUCKING_BASTARD_UUID_FROM_HELL!'; - verificationSubject = "[whiteout] New public key uploaded"; - - notified = false; - dao.onIncomingMessage = function(newMessages) { - expect(newMessages).to.contain(message); - notified = true; - }; + done(); }); + }); + }); - it('should fetch message downstream', function(done) { - imapListStub.withArgs(opts).yieldsAsync(null, [message]); + describe('#fetchMessages', function() { + var imapListStub, imapGetStub, imapDeleteStub, localStoreStub; + var opts, message, validUuid, corruptedUuid, verificationSubject; + var notified; - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); + beforeEach(function() { + imapListStub = sinon.stub(dao, '_imapListMessages'); + imapDeleteStub = sinon.stub(dao, '_imapDeleteMessage'); + imapGetStub = sinon.stub(dao, '_getBodyParts'); + localStoreStub = sinon.stub(dao, '_localStoreMessages'); - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.messages).to.contain(message); - expect(notified).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - expect(imapListStub.calledOnce).to.be.true; + opts = { + folder: inboxFolder, + firstUid: 123, + lastUid: 123 + }; + message = { + uid: 123, + subject: 'asdasd', + unread: true, + bodyParts: [] + }; + validUuid = '9A858952-17EE-4273-9E74-D309EAFDFAFB'; + corruptedUuid = 'OMFG_FUCKING_BASTARD_UUID_FROM_HELL!'; + verificationSubject = "[whiteout] New public key uploaded"; - done(); - }); - }); + notified = false; + dao.onIncomingMessage = function(newMessages) { + expect(newMessages).to.contain(message); + notified = true; + }; + }); - it('should not notify for other folders', function(done) { - opts.folder = sentFolder; + it('should fetch message downstream', function(done) { + imapListStub.withArgs(opts).yieldsAsync(null, [message]); - imapListStub.withArgs(opts).yieldsAsync(null, [message]); + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); - localStoreStub.withArgs({ - folder: sentFolder, - emails: [message] - }).yieldsAsync(); + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.messages).to.contain(message); + expect(notified).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + expect(imapListStub.calledOnce).to.be.true; - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(sentFolder.messages).to.contain(message); - expect(notified).to.be.false; - expect(localStoreStub.calledOnce).to.be.true; - expect(imapListStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should verify verification mails', function(done) { - message.subject = verificationSubject; - - imapListStub.withArgs(opts).yieldsAsync(null, [message]); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ - type: 'text', - content: '' + cfg.cloudUrl + cfg.verificationUrl + validUuid - }]); - - keychainStub.verifyPublicKey.withArgs(validUuid).yieldsAsync(); - - imapDeleteStub.withArgs({ - folder: inboxFolder, - uid: message.uid - }).yieldsAsync(); - - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.messages).to.not.contain(message); - expect(notified).to.be.false; - expect(imapListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(keychainStub.verifyPublicKey.calledOnce).to.be.true; - expect(imapDeleteStub.calledOnce).to.be.true; - expect(localStoreStub.called).to.be.false; - done(); - }); - }); - - it('should not verify invalid verification mails', function(done) { - message.subject = verificationSubject; - - imapListStub.withArgs(opts).yieldsAsync(null, [message]); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ - type: 'text', - content: '' + cfg.cloudUrl + cfg.verificationUrl + corruptedUuid - }]); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.messages).to.contain(message); - expect(notified).to.be.true; - expect(imapListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(keychainStub.verifyPublicKey.called).to.be.false; - expect(imapDeleteStub.called).to.be.false; - expect(localStoreStub.calledOnce).to.be.true; - done(); - }); - }); - - it('should display verification mail when verification failed', function(done) { - message.subject = verificationSubject; - - imapListStub.withArgs(opts).yieldsAsync(null, [message]); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ - type: 'text', - content: '' + cfg.cloudUrl + cfg.verificationUrl + validUuid - }]); - - keychainStub.verifyPublicKey.withArgs(validUuid).yieldsAsync({}); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.messages).to.contain(message); - expect(notified).to.be.true; - expect(imapListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(keychainStub.verifyPublicKey.calledOnce).to.be.true; - expect(imapDeleteStub.called).to.be.false; - expect(localStoreStub.calledOnce).to.be.true; - done(); - }); + done(); }); }); - describe('#deleteMessage', function() { - var imapDeleteStub, localDeleteStub, message; + it('should not notify for other folders', function(done) { + opts.folder = sentFolder; - beforeEach(function() { - message = { - uid: 1234 - }; - imapDeleteStub = sinon.stub(dao, '_imapDeleteMessage'); - localDeleteStub = sinon.stub(dao, '_localDeleteMessage'); - inboxFolder.messages = [message]; - outboxFolder.messages = [message]; - }); + imapListStub.withArgs(opts).yieldsAsync(null, [message]); - it('should delete from imap, local, memory', function(done) { - var deleteOpts = { - folder: inboxFolder, - uid: message.uid - }; + localStoreStub.withArgs({ + folder: sentFolder, + emails: [message] + }).yieldsAsync(); - imapDeleteStub.withArgs(deleteOpts).yieldsAsync(); - localDeleteStub.withArgs(deleteOpts).yieldsAsync(); + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(sentFolder.messages).to.contain(message); + expect(notified).to.be.false; + expect(localStoreStub.calledOnce).to.be.true; + expect(imapListStub.calledOnce).to.be.true; - dao.deleteMessage({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.not.exist; - expect(imapDeleteStub.calledOnce).to.be.true; - expect(localDeleteStub.calledOnce).to.be.true; - expect(inboxFolder.messages).to.not.contain(message); - - done(); - }); - }); - - it('should delete from local, memory', function(done) { - var deleteOpts = { - folder: inboxFolder, - uid: message.uid - }; - - localDeleteStub.withArgs(deleteOpts).yieldsAsync(); - - dao.deleteMessage({ - folder: inboxFolder, - message: message, - localOnly: true - }, function(err) { - expect(err).to.not.exist; - expect(imapDeleteStub.called).to.be.false; - expect(localDeleteStub.calledOnce).to.be.true; - expect(inboxFolder.messages).to.not.contain(message); - - done(); - }); - }); - - it('should delete from outbox from local, memory', function(done) { - var deleteOpts = { - folder: outboxFolder, - uid: message.uid - }; - - localDeleteStub.withArgs(deleteOpts).yieldsAsync(); - - dao.deleteMessage({ - folder: outboxFolder, - message: message - }, function(err) { - expect(err).to.not.exist; - expect(imapDeleteStub.called).to.be.false; - expect(localDeleteStub.calledOnce).to.be.true; - expect(outboxFolder.messages).to.not.contain(message); - - done(); - }); - }); - - it('should fail at delete from local', function(done) { - var deleteOpts = { - folder: inboxFolder, - uid: message.uid - }; - - imapDeleteStub.withArgs(deleteOpts).yieldsAsync(); - localDeleteStub.withArgs(deleteOpts).yieldsAsync({}); - - dao.deleteMessage({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapDeleteStub.calledOnce).to.be.true; - expect(localDeleteStub.calledOnce).to.be.true; - expect(inboxFolder.messages).to.contain(message); - - done(); - }); - }); - - it('should fail at delete from imap', function(done) { - var deleteOpts = { - folder: inboxFolder, - uid: message.uid - }; - - imapDeleteStub.withArgs(deleteOpts).yieldsAsync({}); - - dao.deleteMessage({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapDeleteStub.calledOnce).to.be.true; - expect(localDeleteStub.called).to.be.false; - expect(inboxFolder.messages).to.contain(message); - - done(); - }); - }); - - it('should fail at delete from imap in offline', function(done) { - account.online = false; - dao.deleteMessage({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapDeleteStub.called).to.be.false; - expect(localDeleteStub.called).to.be.false; - expect(inboxFolder.messages).to.contain(message); - - done(); - }); + done(); }); }); - describe('#setFlags', function() { - var imapMark, localListStub, localStoreStub, message; + it('should verify verification mails', function(done) { + message.subject = verificationSubject; - beforeEach(function() { - message = { - uid: 1234 - }; - imapMark = sinon.stub(dao, '_imapMark'); - localListStub = sinon.stub(dao, '_localListMessages'); - localStoreStub = sinon.stub(dao, '_localStoreMessages'); - inboxFolder.messages = [message]; - outboxFolder.messages = [message]; - }); + imapListStub.withArgs(opts).yieldsAsync(null, [message]); - it('should set flags for imap, disk, memory', function(done) { - imapMark.withArgs({ - folder: inboxFolder, - uid: message.uid, - unread: message.unread, - answered: message.answered - }).yieldsAsync(); + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: '' + cfg.cloudUrl + cfg.verificationUrl + validUuid + }]); - localListStub.withArgs({ - folder: inboxFolder, - uid: message.uid - }).yieldsAsync(null, [message]); + keychainStub.verifyPublicKey.withArgs(validUuid).yieldsAsync(); - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); + imapDeleteStub.withArgs({ + folder: inboxFolder, + uid: message.uid + }).yieldsAsync(); - dao.setFlags({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.not.exist; - expect(imapMark.calledOnce).to.be.true; - expect(localListStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should set flags for outbox for disk, memory', function(done) { - localListStub.withArgs({ - folder: outboxFolder, - uid: message.uid - }).yieldsAsync(null, [message]); - - localStoreStub.withArgs({ - folder: outboxFolder, - emails: [message] - }).yieldsAsync(); - - dao.setFlags({ - folder: outboxFolder, - message: message - }, function(err) { - expect(err).to.not.exist; - expect(imapMark.called).to.be.false; - expect(localListStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should set flags for disk, memory', function(done) { - localListStub.withArgs({ - folder: inboxFolder, - uid: message.uid - }).yieldsAsync(null, [message]); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - dao.setFlags({ - folder: inboxFolder, - message: message, - localOnly: true - }, function(err) { - expect(err).to.not.exist; - expect(imapMark.called).to.be.false; - expect(localListStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail to set flags for imap', function(done) { - imapMark.yieldsAsync({}); - localListStub.yieldsAsync(null, [message]); - localStoreStub.yieldsAsync(); - - dao.setFlags({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapMark.calledOnce).to.be.true; - expect(localListStub.called).to.be.false; - expect(localStoreStub.called).to.be.false; - - done(); - }); - }); - it('should fail to set flags for imap in offline mode', function(done) { - account.online = false; - localListStub.yieldsAsync(null, [message]); - localStoreStub.yieldsAsync(); - - dao.setFlags({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapMark.called).to.be.false; - expect(localListStub.called).to.be.false; - expect(localStoreStub.called).to.be.false; - - done(); - }); + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.messages).to.not.contain(message); + expect(notified).to.be.false; + expect(imapListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(keychainStub.verifyPublicKey.calledOnce).to.be.true; + expect(imapDeleteStub.calledOnce).to.be.true; + expect(localStoreStub.called).to.be.false; + done(); }); }); - describe('#getBody', function() { - var localListStub, localStoreStub, imapGetStub, uid; + it('should not verify invalid verification mails', function(done) { + message.subject = verificationSubject; - beforeEach(function() { - uid = 12345, - localListStub = sinon.stub(dao, '_localListMessages'); - localStoreStub = sinon.stub(dao, '_localStoreMessages'); - imapGetStub = sinon.stub(dao, '_getBodyParts'); + imapListStub.withArgs(opts).yieldsAsync(null, [message]); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: '' + cfg.cloudUrl + cfg.verificationUrl + corruptedUuid + }]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.messages).to.contain(message); + expect(notified).to.be.true; + expect(imapListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(keychainStub.verifyPublicKey.called).to.be.false; + expect(imapDeleteStub.called).to.be.false; + expect(localStoreStub.calledOnce).to.be.true; + done(); + }); + }); + + it('should display verification mail when verification failed', function(done) { + message.subject = verificationSubject; + + imapListStub.withArgs(opts).yieldsAsync(null, [message]); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: '' + cfg.cloudUrl + cfg.verificationUrl + validUuid + }]); + + keychainStub.verifyPublicKey.withArgs(validUuid).yieldsAsync({}); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.messages).to.contain(message); + expect(notified).to.be.true; + expect(imapListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(keychainStub.verifyPublicKey.calledOnce).to.be.true; + expect(imapDeleteStub.called).to.be.false; + expect(localStoreStub.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('#deleteMessage', function() { + var imapDeleteStub, localDeleteStub, message; + + beforeEach(function() { + message = { + uid: 1234 + }; + imapDeleteStub = sinon.stub(dao, '_imapDeleteMessage'); + localDeleteStub = sinon.stub(dao, '_localDeleteMessage'); + inboxFolder.messages = [message]; + outboxFolder.messages = [message]; + }); + + it('should delete from imap, local, memory', function(done) { + var deleteOpts = { + folder: inboxFolder, + uid: message.uid + }; + + imapDeleteStub.withArgs(deleteOpts).yieldsAsync(); + localDeleteStub.withArgs(deleteOpts).yieldsAsync(); + + dao.deleteMessage({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapDeleteStub.calledOnce).to.be.true; + expect(localDeleteStub.calledOnce).to.be.true; + expect(inboxFolder.messages).to.not.contain(message); + + done(); + }); + }); + + it('should delete from local, memory', function(done) { + var deleteOpts = { + folder: inboxFolder, + uid: message.uid + }; + + localDeleteStub.withArgs(deleteOpts).yieldsAsync(); + + dao.deleteMessage({ + folder: inboxFolder, + message: message, + localOnly: true + }, function(err) { + expect(err).to.not.exist; + expect(imapDeleteStub.called).to.be.false; + expect(localDeleteStub.calledOnce).to.be.true; + expect(inboxFolder.messages).to.not.contain(message); + + done(); + }); + }); + + it('should delete from outbox from local, memory', function(done) { + var deleteOpts = { + folder: outboxFolder, + uid: message.uid + }; + + localDeleteStub.withArgs(deleteOpts).yieldsAsync(); + + dao.deleteMessage({ + folder: outboxFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapDeleteStub.called).to.be.false; + expect(localDeleteStub.calledOnce).to.be.true; + expect(outboxFolder.messages).to.not.contain(message); + + done(); + }); + }); + + it('should fail at delete from local', function(done) { + var deleteOpts = { + folder: inboxFolder, + uid: message.uid + }; + + imapDeleteStub.withArgs(deleteOpts).yieldsAsync(); + localDeleteStub.withArgs(deleteOpts).yieldsAsync({}); + + dao.deleteMessage({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapDeleteStub.calledOnce).to.be.true; + expect(localDeleteStub.calledOnce).to.be.true; + expect(inboxFolder.messages).to.contain(message); + + done(); + }); + }); + + it('should fail at delete from imap', function(done) { + var deleteOpts = { + folder: inboxFolder, + uid: message.uid + }; + + imapDeleteStub.withArgs(deleteOpts).yieldsAsync({}); + + dao.deleteMessage({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapDeleteStub.calledOnce).to.be.true; + expect(localDeleteStub.called).to.be.false; + expect(inboxFolder.messages).to.contain(message); + + done(); + }); + }); + + it('should fail at delete from imap in offline', function(done) { + account.online = false; + dao.deleteMessage({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapDeleteStub.called).to.be.false; + expect(localDeleteStub.called).to.be.false; + expect(inboxFolder.messages).to.contain(message); + + done(); + }); + }); + }); + + describe('#setFlags', function() { + var imapMark, localListStub, localStoreStub, message; + + beforeEach(function() { + message = { + uid: 1234 + }; + imapMark = sinon.stub(dao, '_imapMark'); + localListStub = sinon.stub(dao, '_localListMessages'); + localStoreStub = sinon.stub(dao, '_localStoreMessages'); + inboxFolder.messages = [message]; + outboxFolder.messages = [message]; + }); + + it('should set flags for imap, disk, memory', function(done) { + imapMark.withArgs({ + folder: inboxFolder, + uid: message.uid, + unread: message.unread, + answered: message.answered + }).yieldsAsync(); + + localListStub.withArgs({ + folder: inboxFolder, + uid: message.uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + dao.setFlags({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapMark.calledOnce).to.be.true; + expect(localListStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should set flags for outbox for disk, memory', function(done) { + localListStub.withArgs({ + folder: outboxFolder, + uid: message.uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: outboxFolder, + emails: [message] + }).yieldsAsync(); + + dao.setFlags({ + folder: outboxFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapMark.called).to.be.false; + expect(localListStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should set flags for disk, memory', function(done) { + localListStub.withArgs({ + folder: inboxFolder, + uid: message.uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + dao.setFlags({ + folder: inboxFolder, + message: message, + localOnly: true + }, function(err) { + expect(err).to.not.exist; + expect(imapMark.called).to.be.false; + expect(localListStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail to set flags for imap', function(done) { + imapMark.yieldsAsync({}); + localListStub.yieldsAsync(null, [message]); + localStoreStub.yieldsAsync(); + + dao.setFlags({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapMark.calledOnce).to.be.true; + expect(localListStub.called).to.be.false; + expect(localStoreStub.called).to.be.false; + + done(); + }); + }); + it('should fail to set flags for imap in offline mode', function(done) { + account.online = false; + localListStub.yieldsAsync(null, [message]); + localStoreStub.yieldsAsync(); + + dao.setFlags({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapMark.called).to.be.false; + expect(localListStub.called).to.be.false; + expect(localStoreStub.called).to.be.false; + + done(); + }); + }); + }); + + describe('#getBody', function() { + var localListStub, localStoreStub, imapGetStub, uid; + + beforeEach(function() { + uid = 12345, + localListStub = sinon.stub(dao, '_localListMessages'); + localStoreStub = sinon.stub(dao, '_localStoreMessages'); + imapGetStub = sinon.stub(dao, '_getBodyParts'); + }); + + it('should not do anything if the message already has content', function() { + var message = { + body: 'bender is great!' + }; + + dao.getBody({ + message: message }); - it('should not do anything if the message already has content', function() { - var message = { - body: 'bender is great!' - }; + // should do nothing + }); - dao.getBody({ - message: message - }); + it('should read an unencrypted body from the device', function(done) { + var message, body; - // should do nothing - }); + body = 'bender is great! bender is great!'; + message = { + uid: uid + }; - it('should read an unencrypted body from the device', function(done) { - var message, body; - - body = 'bender is great! bender is great!'; - message = { - uid: uid - }; - - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: body - }] - }]); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(body); - expect(msg.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should read a pgp/mime from the device', function(done) { - var message, ct, pt; - - pt = 'bender is great!'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - message = { - uid: uid, - encrypted: true - }; - - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: pt - }, { - type: 'encrypted', - content: ct - }] - }]); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(ct); - expect(msg.encrypted).to.be.true; - expect(message.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should read a signed pgp/mime from the device', function(done) { - var message, signed, pt, signedMimeTree, signature; - - pt = 'bender is great!'; - signed = 'omg signed text'; - signedMimeTree = 'trallalalalala'; - signature = 'ugauga'; - message = { - uid: uid, - signed: true, - from: [{ - address: 'asdasdasd' - }] - }; - - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: pt - }, { - type: 'signed', - content: [{ - type: 'text', - content: signed - }], - signedMessage: signedMimeTree, - signature: signature - }] - }]); - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(signed); - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(message.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should read a pgp/inline from the device', function(done) { - var message, ct, pt; - - ct = '-----BEGIN PGP MESSAGE-----\nasdasdasd\n-----END PGP MESSAGE-----'; - pt = 'bla bla yadda yadda'; - message = { - uid: uid - }; - - localListStub.yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: pt - }, { - type: 'text', - content: ct - }, { - type: 'text', - content: pt - }] - }]); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(ct); - expect(msg.bodyParts[0].type).to.equal('encrypted'); - expect(msg.bodyParts[0].content).to.equal(ct); - expect(msg.encrypted).to.be.true; - expect(message.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should read a signed pgp/inline from the device', function(done) { - var message, pt, expected; - - expected = 'Lorem ipsum Aliquip tempor veniam proident.\n\nafguab;igab;igubalw\n\nLorem ipsum Dolor sed irure sint in non.\n\n\n'; - pt = '-----BEGIN PGP SIGNED MESSAGE-----\nHash: WTFHASH\n\n' + expected + '\n-----BEGIN PGP SIGNATURE----------END PGP SIGNATURE-----'; - message = { - uid: uid, - from: [{ - address: 'asdasdasd' - }] - }; - - localListStub.yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: pt - }] - }]); - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.verifyClearSignedMessage.withArgs(pt, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(expected); - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(message.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - expect(pgpStub.verifyClearSignedMessage.calledOnce).to.be.true; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should stream from imap and set plain text body', function(done) { - var message, body, uid; - - body = 'bender is great! bender is great!'; - uid = 1234; - message = { - uid: uid, - bodyParts: [{ - type: 'text' - }] - }; - - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [message]); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [{ + bodyParts: [{ type: 'text', content: body - }]); + }] + }]); - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; - expect(msg).to.equal(message); - expect(msg.body).to.equal(body); - expect(msg.loadingBody).to.be.false; + expect(msg).to.equal(message); + expect(msg.body).to.equal(body); + expect(msg.loadingBody).to.be.false; - expect(localListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; + expect(localListStub.calledOnce).to.be.true; - done(); - }); - expect(message.loadingBody).to.be.true; + done(); }); + expect(message.loadingBody).to.be.true; + }); - it('should stream from imap and set encrypted body', function(done) { - var message, ct, pt; + it('should read a pgp/mime from the device', function(done) { + var message, ct, pt; - pt = 'bender is great'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - message = { - uid: uid, - encrypted: true, - bodyParts: [{ - type: 'text' - }, { - type: 'encrypted' - }] - }; + pt = 'bender is great!'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + message = { + uid: uid, + encrypted: true + }; - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [message]); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [{ + bodyParts: [{ type: 'text', content: pt }, { type: 'encrypted', content: ct - }]); + }] + }]); + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; + expect(msg).to.equal(message); + expect(msg.body).to.equal(ct); + expect(msg.encrypted).to.be.true; + expect(message.loadingBody).to.be.false; - expect(msg).to.equal(message); - expect(msg.body).to.equal(ct); - expect(msg.encrypted).to.be.true; - expect(msg.loadingBody).to.be.false; + expect(localListStub.calledOnce).to.be.true; - expect(localListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; + done(); }); + expect(message.loadingBody).to.be.true; + }); - it('fail to stream from imap due to error when persisting', function(done) { - var message = { - uid: uid, - bodyParts: [{ - type: 'text' - }] - }; + it('should read a signed pgp/mime from the device', function(done) { + var message, signed, pt, signedMimeTree, signature; - localListStub.yieldsAsync(null, [message]); - localStoreStub.yieldsAsync({}); - imapGetStub.yieldsAsync(null, [{ + pt = 'bender is great!'; + signed = 'omg signed text'; + signedMimeTree = 'trallalalalala'; + signature = 'ugauga'; + message = { + uid: uid, + signed: true, + from: [{ + address: 'asdasdasd' + }] + }; + + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [{ + bodyParts: [{ type: 'text', - content: 'bender is great! bender is great!' - }]); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.exist; - expect(msg).to.not.exist; - expect(localListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - expect(message.loadingBody).to.be.false; - - done(); - }); - }); - - it('fail to stream from imap due to stream error', function(done) { - var message = { - uid: uid, - bodyParts: [{ - type: 'text' - }] - }; - - localListStub.yieldsAsync(null, [message]); - imapGetStub.yieldsAsync({}); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.exist; - expect(msg).to.not.exist; - expect(localListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(localStoreStub.called).to.be.false; - - expect(message.loadingBody).to.be.false; - - done(); - }); - }); - }); - - describe('#getAttachment', function() { - var imapGetStub, uid; - - beforeEach(function() { - uid = 123456; - imapGetStub = sinon.stub(dao, '_getBodyParts'); - }); - - it('should fetch an attachment from imap', function(done) { - var attmt = {}; - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: uid, - bodyParts: [attmt] - }).yieldsAsync(null, [{ - content: 'CONTENT!!!' - }]); - - dao.getAttachment({ - folder: inboxFolder, - uid: uid, - attachment: attmt - }, function(err, fetchedAttmt) { - expect(err).to.not.exist; - expect(fetchedAttmt).to.equal(attmt); - expect(attmt.content).to.not.be.empty; - expect(imapGetStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should error during fetch', function(done) { - var attmt = {}; - - imapGetStub.yieldsAsync({}); - - dao.getAttachment({ - folder: inboxFolder, - uid: uid, - attachment: attmt - }, function(err, fetchedAttmt) { - expect(err).to.exist; - expect(fetchedAttmt).to.not.exist; - expect(imapGetStub.calledOnce).to.be.true; - - done(); - }); - }); - }); - - describe('#decryptBody', function() { - it('should do nothing when the message is not encrypted', function(done) { - var message = { - encrypted: false, - decrypted: true, - body: 'asd' - }; - - dao.decryptBody({ - message: message - }, done); - }); - - it('should do nothing when the message is already decrypted', function(done) { - var message = { - encrypted: true, - decrypted: true, - body: 'asd' - }; - - dao.decryptBody({ - message: message - }, done); - }); - - it('should do nothing when the message has no body', function(done) { - var message = { - encrypted: true, - decrypted: false, - body: '' - }; - - dao.decryptBody({ - message: message - }, done); - }); - - it('should do nothing when the message is decrypting', function(done) { - var message = { - encrypted: true, - decrypted: false, - body: 'asd', - decryptingBody: true - }; - - dao.decryptBody({ - message: message - }, done); - }); - - it('decrypt a pgp/mime message', function(done) { - var message, ct, pt, parsed; - - pt = 'bender is great'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - parsed = 'bender! bender! bender!'; - message = { - from: [{ - address: 'asdasdasd' - }], - body: ct, - encrypted: true, - bodyParts: [{ - type: 'encrypted', - content: ct - }] - }; - - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, true); - parseStub.withArgs({ - bodyParts: [{ - type: 'encrypted', - content: ct, - raw: pt - }] - }).yieldsAsync(null, [{ - type: 'encrypted', + content: pt + }, { + type: 'signed', content: [{ type: 'text', - content: parsed - }] - }]); - - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.not.exist; - expect(msg).to.equal(message); - expect(message.decrypted).to.be.true; - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(message.body).to.equal(parsed); - expect(message.decryptingBody).to.be.false; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.decrypt.calledOnce).to.be.true; - expect(parseStub.calledOnce).to.be.true; - - done(); - }); - - expect(message.decryptingBody).to.be.true; - }); - - it('decrypt a pgp/mime message with inner signature', function(done) { - var message, ct, pt, parsed, signed, signedMimeTree, signature; - - pt = 'bender is great'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - signedMimeTree = 'trallalalalala'; - signature = 'ugauga'; - signed = 'omg signed text'; - parsed = 'bender! bender! bender!'; - message = { - from: [{ - address: 'asdasdasd' + content: signed }], - body: ct, - encrypted: true, - bodyParts: [{ - type: 'encrypted', - content: ct - }] - }; + signedMessage: signedMimeTree, + signature: signature + }] + }]); + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, undefined); - pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; - parseStub.withArgs({ - bodyParts: [{ - type: 'encrypted', - content: ct, - raw: pt - }] - }).yieldsAsync(null, [{ + expect(msg).to.equal(message); + expect(msg.body).to.equal(signed); + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(message.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should read a pgp/inline from the device', function(done) { + var message, ct, pt; + + ct = '-----BEGIN PGP MESSAGE-----\nasdasdasd\n-----END PGP MESSAGE-----'; + pt = 'bla bla yadda yadda'; + message = { + uid: uid + }; + + localListStub.yieldsAsync(null, [{ + bodyParts: [{ + type: 'text', + content: pt + }, { + type: 'text', + content: ct + }, { + type: 'text', + content: pt + }] + }]); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; + + expect(msg).to.equal(message); + expect(msg.body).to.equal(ct); + expect(msg.bodyParts[0].type).to.equal('encrypted'); + expect(msg.bodyParts[0].content).to.equal(ct); + expect(msg.encrypted).to.be.true; + expect(message.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should read a signed pgp/inline from the device', function(done) { + var message, pt, expected; + + expected = 'Lorem ipsum Aliquip tempor veniam proident.\n\nafguab;igab;igubalw\n\nLorem ipsum Dolor sed irure sint in non.\n\n\n'; + pt = '-----BEGIN PGP SIGNED MESSAGE-----\nHash: WTFHASH\n\n' + expected + '\n-----BEGIN PGP SIGNATURE----------END PGP SIGNATURE-----'; + message = { + uid: uid, + from: [{ + address: 'asdasdasd' + }] + }; + + localListStub.yieldsAsync(null, [{ + bodyParts: [{ + type: 'text', + content: pt + }] + }]); + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.verifyClearSignedMessage.withArgs(pt, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; + + expect(msg).to.equal(message); + expect(msg.body).to.equal(expected); + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(message.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(pgpStub.verifyClearSignedMessage.calledOnce).to.be.true; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should stream from imap and set plain text body', function(done) { + var message, body, uid; + + body = 'bender is great! bender is great!'; + uid = 1234; + message = { + uid: uid, + bodyParts: [{ + type: 'text' + }] + }; + + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: body + }]); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; + + expect(msg).to.equal(message); + expect(msg.body).to.equal(body); + expect(msg.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should stream from imap and set encrypted body', function(done) { + var message, ct, pt; + + pt = 'bender is great'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + message = { + uid: uid, + encrypted: true, + bodyParts: [{ + type: 'text' + }, { + type: 'encrypted' + }] + }; + + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: pt + }, { + type: 'encrypted', + content: ct + }]); + + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; + + expect(msg).to.equal(message); + expect(msg.body).to.equal(ct); + expect(msg.encrypted).to.be.true; + expect(msg.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('fail to stream from imap due to error when persisting', function(done) { + var message = { + uid: uid, + bodyParts: [{ + type: 'text' + }] + }; + + localListStub.yieldsAsync(null, [message]); + localStoreStub.yieldsAsync({}); + imapGetStub.yieldsAsync(null, [{ + type: 'text', + content: 'bender is great! bender is great!' + }]); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.exist; + expect(msg).to.not.exist; + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + expect(message.loadingBody).to.be.false; + + done(); + }); + }); + + it('fail to stream from imap due to stream error', function(done) { + var message = { + uid: uid, + bodyParts: [{ + type: 'text' + }] + }; + + localListStub.yieldsAsync(null, [message]); + imapGetStub.yieldsAsync({}); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.exist; + expect(msg).to.not.exist; + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.called).to.be.false; + + expect(message.loadingBody).to.be.false; + + done(); + }); + }); + }); + + describe('#getAttachment', function() { + var imapGetStub, uid; + + beforeEach(function() { + uid = 123456; + imapGetStub = sinon.stub(dao, '_getBodyParts'); + }); + + it('should fetch an attachment from imap', function(done) { + var attmt = {}; + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: uid, + bodyParts: [attmt] + }).yieldsAsync(null, [{ + content: 'CONTENT!!!' + }]); + + dao.getAttachment({ + folder: inboxFolder, + uid: uid, + attachment: attmt + }, function(err, fetchedAttmt) { + expect(err).to.not.exist; + expect(fetchedAttmt).to.equal(attmt); + expect(attmt.content).to.not.be.empty; + expect(imapGetStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should error during fetch', function(done) { + var attmt = {}; + + imapGetStub.yieldsAsync({}); + + dao.getAttachment({ + folder: inboxFolder, + uid: uid, + attachment: attmt + }, function(err, fetchedAttmt) { + expect(err).to.exist; + expect(fetchedAttmt).to.not.exist; + expect(imapGetStub.calledOnce).to.be.true; + + done(); + }); + }); + }); + + describe('#decryptBody', function() { + it('should do nothing when the message is not encrypted', function(done) { + var message = { + encrypted: false, + decrypted: true, + body: 'asd' + }; + + dao.decryptBody({ + message: message + }, done); + }); + + it('should do nothing when the message is already decrypted', function(done) { + var message = { + encrypted: true, + decrypted: true, + body: 'asd' + }; + + dao.decryptBody({ + message: message + }, done); + }); + + it('should do nothing when the message has no body', function(done) { + var message = { + encrypted: true, + decrypted: false, + body: '' + }; + + dao.decryptBody({ + message: message + }, done); + }); + + it('should do nothing when the message is decrypting', function(done) { + var message = { + encrypted: true, + decrypted: false, + body: 'asd', + decryptingBody: true + }; + + dao.decryptBody({ + message: message + }, done); + }); + + it('decrypt a pgp/mime message', function(done) { + var message, ct, pt, parsed; + + pt = 'bender is great'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + parsed = 'bender! bender! bender!'; + message = { + from: [{ + address: 'asdasdasd' + }], + body: ct, + encrypted: true, + bodyParts: [{ type: 'encrypted', + content: ct + }] + }; + + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, true); + parseStub.withArgs({ + bodyParts: [{ + type: 'encrypted', + content: ct, + raw: pt + }] + }).yieldsAsync(null, [{ + type: 'encrypted', + content: [{ + type: 'text', + content: parsed + }] + }]); + + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.not.exist; + expect(msg).to.equal(message); + expect(message.decrypted).to.be.true; + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(message.body).to.equal(parsed); + expect(message.decryptingBody).to.be.false; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.decrypt.calledOnce).to.be.true; + expect(parseStub.calledOnce).to.be.true; + + done(); + }); + + expect(message.decryptingBody).to.be.true; + }); + + it('decrypt a pgp/mime message with inner signature', function(done) { + var message, ct, pt, parsed, signed, signedMimeTree, signature; + + pt = 'bender is great'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + signedMimeTree = 'trallalalalala'; + signature = 'ugauga'; + signed = 'omg signed text'; + parsed = 'bender! bender! bender!'; + message = { + from: [{ + address: 'asdasdasd' + }], + body: ct, + encrypted: true, + bodyParts: [{ + type: 'encrypted', + content: ct + }] + }; + + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, undefined); + pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); + + parseStub.withArgs({ + bodyParts: [{ + type: 'encrypted', + content: ct, + raw: pt + }] + }).yieldsAsync(null, [{ + type: 'encrypted', + content: [{ + type: 'signed', content: [{ - type: 'signed', - content: [{ - type: 'text', - content: signed - }], - signedMessage: signedMimeTree, - signature: signature - }] - }]); + type: 'text', + content: signed + }], + signedMessage: signedMimeTree, + signature: signature + }] + }]); - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.not.exist; - expect(msg).to.equal(message); - expect(message.decrypted).to.be.true; - expect(message.body).to.equal(signed); - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(message.decryptingBody).to.be.false; - expect(keychainStub.getReceiverPublicKey.calledTwice).to.be.true; - expect(pgpStub.decrypt.calledOnce).to.be.true; - expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; - expect(parseStub.calledOnce).to.be.true; + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.not.exist; + expect(msg).to.equal(message); + expect(message.decrypted).to.be.true; + expect(message.body).to.equal(signed); + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(message.decryptingBody).to.be.false; + expect(keychainStub.getReceiverPublicKey.calledTwice).to.be.true; + expect(pgpStub.decrypt.calledOnce).to.be.true; + expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; + expect(parseStub.calledOnce).to.be.true; - done(); - }); - - expect(message.decryptingBody).to.be.true; + done(); }); - it('decrypt a pgp/inline message', function(done) { - var message, ct, pt; + expect(message.decryptingBody).to.be.true; + }); - pt = 'bender is great'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - message = { - from: [{ - address: 'asdasdasd' - }], - body: ct, - encrypted: true, - bodyParts: [{ - type: 'encrypted', - content: ct, - _isPgpInline: true - }] - }; + it('decrypt a pgp/inline message', function(done) { + var message, ct, pt; - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, true); + pt = 'bender is great'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + message = { + from: [{ + address: 'asdasdasd' + }], + body: ct, + encrypted: true, + bodyParts: [{ + type: 'encrypted', + content: ct, + _isPgpInline: true + }] + }; - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.not.exist; + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, true); - expect(msg).to.equal(message); - expect(message.decrypted).to.be.true; - expect(message.body).to.equal(pt); - expect(message.decryptingBody).to.be.false; - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.decrypt.calledOnce).to.be.true; - expect(parseStub.called).to.be.false; + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.not.exist; - done(); - }); + expect(msg).to.equal(message); + expect(message.decrypted).to.be.true; + expect(message.body).to.equal(pt); + expect(message.decryptingBody).to.be.false; + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.decrypt.calledOnce).to.be.true; + expect(parseStub.called).to.be.false; - expect(message.decryptingBody).to.be.true; + done(); }); - it('should fail during decryption message', function(done) { - var message = { - from: [{ - address: 'asdasdasd' - }], - body: 'asdjafuad', - encrypted: true, - bodyParts: [{ - type: 'encrypted', - content: '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----' - }] - }; + expect(message.decryptingBody).to.be.true; + }); - keychainStub.getReceiverPublicKey.yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.decrypt.yieldsAsync(new Error('fail.')); + it('should fail during decryption message', function(done) { + var message = { + from: [{ + address: 'asdasdasd' + }], + body: 'asdjafuad', + encrypted: true, + bodyParts: [{ + type: 'encrypted', + content: '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----' + }] + }; - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.not.exist; - expect(msg.body).to.equal('fail.'); - expect(msg).to.exist; - expect(message.decryptingBody).to.be.false; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.decrypt.calledOnce).to.be.true; - expect(parseStub.called).to.be.false; + keychainStub.getReceiverPublicKey.yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.decrypt.yieldsAsync(new Error('fail.')); - done(); - }); - }); + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.not.exist; + expect(msg.body).to.equal('fail.'); + expect(msg).to.exist; + expect(message.decryptingBody).to.be.false; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.decrypt.calledOnce).to.be.true; + expect(parseStub.called).to.be.false; - it('should fail during key export', function(done) { - var message = { - from: [{ - address: 'asdasdasd' - }], - encrypted: true, - body: 'asdjafuad', - bodyParts: [{ - type: 'encrypted', - content: '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----' - }] - }; - - keychainStub.getReceiverPublicKey.yieldsAsync({}); - - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.exist; - expect(msg).to.not.exist; - expect(message.decryptingBody).to.be.false; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.decrypt.called).to.be.false; - expect(parseStub.called).to.be.false; - - done(); - }); + done(); }); }); - describe('#sendEncrypted', function() { - var publicKeys = ["PUBLIC KEY"], - dummyMail = { - publicKeysArmored: publicKeys - }; + it('should fail during key export', function(done) { + var message = { + from: [{ + address: 'asdasdasd' + }], + encrypted: true, + body: 'asdjafuad', + bodyParts: [{ + type: 'encrypted', + content: '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----' + }] + }; - it('should send encrypted and upload to sent', function(done) { - var msg = 'wow. such message. much rfc2822.'; + keychainStub.getReceiverPublicKey.yieldsAsync({}); - imapClientStub.uploadMessage.withArgs({ - path: sentFolder.path, - message: msg - }).yields(); + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.exist; + expect(msg).to.not.exist; + expect(message.decryptingBody).to.be.false; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.decrypt.called).to.be.false; + expect(parseStub.called).to.be.false; - pgpMailerStub.send.withArgs({ - encrypt: true, - mail: dummyMail, - smtpclient: undefined, - publicKeysArmored: publicKeys - }).yieldsAsync(null, msg); - - dao.sendEncrypted({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.calledOnce).to.be.true; - - done(); - }); - }); - - it('should send encrypted and not upload to sent', function(done) { - var msg = 'wow. such message. much rfc2822.'; - - dao.ignoreUploadOnSent = true; - - pgpMailerStub.send.withArgs({ - encrypt: true, - mail: dummyMail, - smtpclient: undefined, - publicKeysArmored: publicKeys - }).yieldsAsync(null, msg); - - dao.sendEncrypted({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.called).to.be.false; - - done(); - }); - }); - - it('should not send when pgpmailer fails', function(done) { - pgpMailerStub.send.yieldsAsync({}); - - dao.sendEncrypted({ - email: dummyMail - }, function(err) { - expect(err).to.exist; - - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.called).to.be.false; - - done(); - }); - }); - - it('should not send in offline mode', function(done) { - account.online = false; - - dao.sendEncrypted({}, function(err) { - expect(err).to.exist; - expect(pgpMailerStub.send.called).to.be.false; - expect(imapClientStub.uploadMessage.called).to.be.false; - done(); - }); - }); - - }); - - describe('#sendPlaintext', function() { - var dummyMail = {}; - - it('should send in the plain and upload to sent', function(done) { - var msg = 'wow. such message. much rfc2822.'; - - pgpMailerStub.send.withArgs({ - smtpclient: undefined, - mail: dummyMail - }).yieldsAsync(null, msg); - - imapClientStub.uploadMessage.withArgs({ - path: sentFolder.path, - message: msg - }).yields(); - - dao.sendPlaintext({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.calledOnce).to.be.true; - done(); - }); - }); - - it('should send in the plain and not upload to sent', function(done) { - var msg = 'wow. such message. much rfc2822.'; - - dao.ignoreUploadOnSent = true; - - pgpMailerStub.send.withArgs({ - smtpclient: undefined, - mail: dummyMail - }).yieldsAsync(null, msg); - - dao.sendPlaintext({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.called).to.be.false; - done(); - }); - }); - - it('should not send due to error', function(done) { - pgpMailerStub.send.yieldsAsync({}); - - dao.sendPlaintext({ - email: dummyMail - }, function(err) { - expect(err).to.exist; - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.called).to.be.false; - done(); - }); - }); - - it('should not send in offline mode', function(done) { - account.online = false; - - dao.sendPlaintext({}, function(err) { - expect(err).to.exist; - expect(pgpMailerStub.send.called).to.be.false; - expect(imapClientStub.uploadMessage.called).to.be.false; - done(); - }); - }); - }); - - describe('#encrypt', function() { - it('should encrypt', function(done) { - pgpBuilderStub.encrypt.yieldsAsync(); - - dao.encrypt({}, function() { - expect(pgpBuilderStub.encrypt.calledOnce).to.be.true; - done(); - }); + done(); }); }); }); - describe('event handlers', function() { + describe('#sendEncrypted', function() { + var publicKeys = ["PUBLIC KEY"], + dummyMail = { + publicKeysArmored: publicKeys + }; - describe('#onConnect', function() { - var initFoldersStub; + it('should send encrypted and upload to sent', function(done) { + var msg = 'wow. such message. much rfc2822.'; - beforeEach(function() { - initFoldersStub = sinon.stub(dao, '_initFoldersFromImap'); - delete dao._imapClient; - delete dao._pgpMailer; - }); + imapClientStub.uploadMessage.withArgs({ + path: sentFolder.path, + message: msg + }).yields(); - it('should connect', function(done) { - inboxFolder.messages = [{ - uid: 123, - modseq: 123 - }]; - imapClientStub.login.yieldsAsync(); - imapClientStub.listenForChanges.yieldsAsync(); - initFoldersStub.yieldsAsync(); + pgpMailerStub.send.withArgs({ + encrypt: true, + mail: dummyMail, + smtpclient: undefined, + publicKeysArmored: publicKeys + }).yieldsAsync(null, msg); - dao.onConnect({ - imapClient: imapClientStub, - pgpMailer: pgpMailerStub - }, function(err) { + dao.sendEncrypted({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; - expect(err).to.not.exist; - expect(imapClientStub.login.calledOnce).to.be.true; - expect(initFoldersStub.calledOnce).to.be.true; - expect(imapClientStub.mailboxCache).to.deep.equal({ - 'INBOX': { - exists: 123, - uidNext: 124, - uidlist: [123], - highestModseq: 123 - } - }); + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.calledOnce).to.be.true; - done(); - }); + done(); }); }); - describe('#onDisconnect', function() { - it('should discard imapClient and pgpMailer', function(done) { - imapClientStub.logout.yieldsAsync(); + it('should send encrypted and not upload to sent', function(done) { + var msg = 'wow. such message. much rfc2822.'; - dao.onDisconnect(done); + dao.ignoreUploadOnSent = true; - expect(dao._account.online).to.be.false; - expect(dao._imapClient).to.not.exist; - expect(dao._pgpMailer).to.not.exist; + pgpMailerStub.send.withArgs({ + encrypt: true, + mail: dummyMail, + smtpclient: undefined, + publicKeysArmored: publicKeys + }).yieldsAsync(null, msg); + + dao.sendEncrypted({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; + + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.called).to.be.false; + + done(); }); }); - describe('#_onSyncUpdate', function() { - var fetchMessagesStub, deleteMessagesStub, setFlagsStub, msgs; + it('should not send when pgpmailer fails', function(done) { + pgpMailerStub.send.yieldsAsync({}); - beforeEach(function() { - msgs = [{ - uid: 5, - flags: ['\\Answered', '\\Seen'] - }]; - inboxFolder.messages = msgs; - fetchMessagesStub = sinon.stub(dao, 'fetchMessages'); - deleteMessagesStub = sinon.stub(dao, 'deleteMessage'); - setFlagsStub = sinon.stub(dao, 'setFlags'); + dao.sendEncrypted({ + email: dummyMail + }, function(err) { + expect(err).to.exist; + + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.called).to.be.false; + + done(); }); + }); - it('should get new message', function(done) { - fetchMessagesStub.withArgs({ - folder: inboxFolder, - firstUid: 1, - lastUid: 3 - }).yieldsAsync(); + it('should not send in offline mode', function(done) { + account.online = false; - dao.onError = function(err) { - expect(err).to.not.exist; - expect(fetchMessagesStub.calledOnce).to.be.true; - done(); - }; - - dao._onSyncUpdate({ - type: 'new', - path: inboxFolder.path, - list: [1, 3] - }); + dao.sendEncrypted({}, function(err) { + expect(err).to.exist; + expect(pgpMailerStub.send.called).to.be.false; + expect(imapClientStub.uploadMessage.called).to.be.false; + done(); }); + }); - it('should delete message', function(done) { - deleteMessagesStub.withArgs({ - folder: inboxFolder, - message: msgs[0], - localOnly: true - }).yieldsAsync(); + }); - dao.onError = function(err) { - expect(err).to.not.exist; - expect(deleteMessagesStub.calledOnce).to.be.true; - done(); - }; + describe('#sendPlaintext', function() { + var dummyMail = {}; - dao._onSyncUpdate({ - type: 'deleted', - path: inboxFolder.path, - list: [5] - }); + it('should send in the plain and upload to sent', function(done) { + var msg = 'wow. such message. much rfc2822.'; + + pgpMailerStub.send.withArgs({ + smtpclient: undefined, + mail: dummyMail + }).yieldsAsync(null, msg); + + imapClientStub.uploadMessage.withArgs({ + path: sentFolder.path, + message: msg + }).yields(); + + dao.sendPlaintext({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.calledOnce).to.be.true; + done(); }); + }); - it('should fetch flags', function(done) { - setFlagsStub.withArgs({ - folder: inboxFolder, - message: msgs[0], - localOnly: true - }).yieldsAsync(); + it('should send in the plain and not upload to sent', function(done) { + var msg = 'wow. such message. much rfc2822.'; - dao.onError = function(err) { - expect(err).to.not.exist; - expect(setFlagsStub.calledOnce).to.be.true; - done(); - }; + dao.ignoreUploadOnSent = true; - dao._onSyncUpdate({ - type: 'messages', - path: inboxFolder.path, - list: msgs - }); + pgpMailerStub.send.withArgs({ + smtpclient: undefined, + mail: dummyMail + }).yieldsAsync(null, msg); + + dao.sendPlaintext({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.called).to.be.false; + done(); + }); + }); + + it('should not send due to error', function(done) { + pgpMailerStub.send.yieldsAsync({}); + + dao.sendPlaintext({ + email: dummyMail + }, function(err) { + expect(err).to.exist; + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.called).to.be.false; + done(); + }); + }); + + it('should not send in offline mode', function(done) { + account.online = false; + + dao.sendPlaintext({}, function(err) { + expect(err).to.exist; + expect(pgpMailerStub.send.called).to.be.false; + expect(imapClientStub.uploadMessage.called).to.be.false; + done(); }); }); }); + describe('#encrypt', function() { + it('should encrypt', function(done) { + pgpBuilderStub.encrypt.yieldsAsync(); - describe('internal API', function() { - describe('#_checkSignatures', function() { - it('should check signatures in clearsigned message', function(done) { - var message = { - from: [{ - address: 'asdasdasd' - }], - clearSignedMessage: 'trallalalalala' - }; - - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.verifyClearSignedMessage.withArgs(message.clearSignedMessage, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); - - dao._checkSignatures(message, function(error, signaturesValid) { - expect(error).to.not.exist; - expect(signaturesValid).to.be.true; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.verifyClearSignedMessage.calledOnce).to.be.true; - done(); - }); + dao.encrypt({}, function() { + expect(pgpBuilderStub.encrypt.calledOnce).to.be.true; + done(); }); - - it('should check signatures in pgp/mime signed message', function(done) { - var message = { - from: [{ - address: 'asdasdasd' - }], - signedMessage: 'trallalalalala', - signature: 'ugauga' - }; - - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.verifySignedMessage.withArgs(message.signedMessage, message.signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); - - dao._checkSignatures(message, function(error, signaturesValid) { - expect(error).to.not.exist; - expect(signaturesValid).to.be.true; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; - done(); - }); - }); - - it('should error while checking signatures', function(done) { - var message = { - from: [{ - address: 'asdasdasd' - }], - signedMessage: 'trallalalalala', - signature: 'ugauga' - }; - - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.verifySignedMessage.yieldsAsync(new Error()); - - dao._checkSignatures(message, function(error, signaturesValid) { - expect(error).to.exist; - expect(signaturesValid).to.not.exist; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; - done(); - }); - }); - - it('should error while fetching public key', function(done) { - var message = { - from: [{ - address: 'asdasdasd' - }], - signedMessage: 'trallalalalala', - signature: 'ugauga' - }; - - keychainStub.getReceiverPublicKey.yieldsAsync(new Error()); - - dao._checkSignatures(message, function(error, signaturesValid) { - expect(error).to.exist; - expect(signaturesValid).to.not.exist; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.verifySignedMessage.called).to.be.false; - done(); - }); - }); - }); - - describe('#_initFoldersFromDisk', function() { - beforeEach(function() { - sinon.stub(dao, 'refreshFolder'); - }); - - it('should initialize from disk if offline and not refresh folder', function(done) { - devicestorageStub.listItems.withArgs('folders').yieldsAsync(null, [ - [inboxFolder] - ]); - dao.refreshFolder.withArgs({ - folder: inboxFolder - }).yieldsAsync(); - - dao._initFoldersFromDisk(function(err) { - expect(err).to.not.exist; - expect(devicestorageStub.listItems.calledOnce).to.be.true; - expect(dao.refreshFolder.called).to.be.false; - done(); - }); - }); - - it('should initialize from disk if offline and refresh folder', function(done) { - delete inboxFolder.messages; - devicestorageStub.listItems.withArgs('folders').yieldsAsync(null, [ - [inboxFolder] - ]); - dao.refreshFolder.withArgs({ - folder: inboxFolder - }).yieldsAsync(); - - dao._initFoldersFromDisk(function(err) { - expect(err).to.not.exist; - expect(devicestorageStub.listItems.calledOnce).to.be.true; - expect(dao.refreshFolder.calledOnce).to.be.true; - done(); - }); - }); - }); - - describe('#_initFoldersFromImap', function() { - beforeEach(function() { - sinon.stub(dao, 'refreshFolder'); - }); - - it('should initialize from imap if online', function(done) { - account.folders = []; - imapClientStub.listWellKnownFolders.yieldsAsync(null, { - Inbox: [inboxFolder], - Sent: [sentFolder], - Drafts: [draftsFolder], - Trash: [trashFolder] - }); - devicestorageStub.storeList.withArgs(sinon.match(function(arg) { - expect(arg[0][0].name).to.deep.equal(inboxFolder.name); - expect(arg[0][0].path).to.deep.equal(inboxFolder.path); - expect(arg[0][0].type).to.deep.equal(inboxFolder.type); - expect(arg[0][1].name).to.deep.equal(sentFolder.name); - expect(arg[0][1].path).to.deep.equal(sentFolder.path); - expect(arg[0][1].type).to.deep.equal(sentFolder.type); - expect(arg[0][2].name).to.deep.equal(outboxFolder.name); - expect(arg[0][2].path).to.deep.equal(outboxFolder.path); - expect(arg[0][2].type).to.deep.equal(outboxFolder.type); - expect(arg[0][3].name).to.deep.equal(draftsFolder.name); - expect(arg[0][3].path).to.deep.equal(draftsFolder.path); - expect(arg[0][3].type).to.deep.equal(draftsFolder.type); - expect(arg[0][4].name).to.deep.equal(trashFolder.name); - expect(arg[0][4].path).to.deep.equal(trashFolder.path); - expect(arg[0][4].type).to.deep.equal(trashFolder.type); - return true; - }), 'folders').yieldsAsync(); - - dao.refreshFolder.yieldsAsync(); - - dao._initFoldersFromImap(function(err) { - expect(err).to.not.exist; - expect(imapClientStub.listWellKnownFolders.calledOnce).to.be.true; - expect(devicestorageStub.storeList.calledOnce).to.be.true; - done(); - }); - }); - - it('should update folders from imap', function(done) { - account.folders = [inboxFolder, outboxFolder, trashFolder, { - name: 'foo', - type: 'Sent', - path: 'bar', - }]; - - imapClientStub.listWellKnownFolders.yieldsAsync(null, { - Inbox: [inboxFolder], - Sent: [sentFolder], - Drafts: [draftsFolder], - Trash: [trashFolder] - }); - devicestorageStub.storeList.withArgs(sinon.match(function(arg) { - expect(arg[0]).to.deep.equal([{ - name: inboxFolder.name, - path: inboxFolder.path, - type: inboxFolder.type - }, { - name: outboxFolder.name, - path: outboxFolder.path, - type: outboxFolder.type - }, { - name: trashFolder.name, - path: trashFolder.path, - type: trashFolder.type - }, { - name: sentFolder.name, - path: sentFolder.path, - type: sentFolder.type - }, { - name: draftsFolder.name, - path: draftsFolder.path, - type: draftsFolder.type - }]); - - return true; - }), 'folders').yieldsAsync(); - - dao.refreshFolder.yieldsAsync(); - - dao._initFoldersFromImap(function(err) { - expect(err).to.not.exist; - expect(imapClientStub.listWellKnownFolders.calledOnce).to.be.true; - expect(devicestorageStub.storeList.calledOnce).to.be.true; - done(); - }); - }); - }); - - describe('#_imapMark', function() { - it('should flag a mail', function(done) { - imapClientStub.updateFlags.withArgs({ - path: inboxFolder.path, - folder: inboxFolder, - uid: 1, - unread: false, - answered: false - }).yieldsAsync(); - - dao._imapMark({ - folder: inboxFolder, - uid: 1, - unread: false, - answered: false - }, function(err) { - expect(err).to.not.exist; - expect(imapClientStub.updateFlags.calledOnce).to.be.true; - done(); - }); - }); - }); - - describe('#_imapDeleteMessage', function() { - var uid = 1337; - - it('should fail when disconnected', function(done) { - dao._account.online = false; - - dao._imapDeleteMessage({}, function(err) { - expect(err.code).to.equal(42); - done(); - }); - }); - - it('should move to trash', function(done) { - imapClientStub.moveMessage.withArgs({ - path: inboxFolder.path, - uid: uid, - destination: trashFolder.path - }).yieldsAsync(); - - dao._imapDeleteMessage({ - folder: inboxFolder, - uid: uid - }, done); - }); - - it('should purge message', function(done) { - imapClientStub.deleteMessage.withArgs({ - path: trashFolder.path, - uid: uid - }).yieldsAsync(); - - dao._imapDeleteMessage({ - folder: trashFolder, - uid: uid - }, done); - }); - }); - - describe('#_imapListMessages', function() { - var firstUid = 1337, - lastUid = 1339; - - it('should list messages', function(done) { - imapClientStub.listMessages.withArgs({ - folder: inboxFolder, - path: inboxFolder.path, - firstUid: firstUid, - lastUid: lastUid - }).yieldsAsync(null, []); - - dao._imapListMessages({ - folder: inboxFolder, - firstUid: firstUid, - lastUid: lastUid - }, function(err, msgs) { - expect(err).to.not.exist; - expect(msgs).to.exist; - - expect(imapClientStub.listMessages.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when listMessages fails', function(done) { - imapClientStub.listMessages.yieldsAsync({}); - - dao._imapListMessages({ - folder: inboxFolder, - firstUid: firstUid, - lastUid: lastUid - }, function(err, msgs) { - expect(err).to.exist; - expect(msgs).to.not.exist; - expect(imapClientStub.listMessages.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when disconnected', function(done) { - dao._account.online = false; - - dao._imapListMessages({}, function(err) { - expect(err.code).to.equal(42); - done(); - }); - }); - }); - - describe('#_getBodyParts', function() { - it('should get bodyParts', function(done) { - imapClientStub.getBodyParts.withArgs({ - folder: inboxFolder, - path: inboxFolder.path, - uid: 123, - bodyParts: [] - }).yieldsAsync(null, {}); - parseStub.yieldsAsync(null, []); - - dao._getBodyParts({ - folder: inboxFolder, - uid: 123, - bodyParts: [] - }, function(err, parts) { - expect(err).to.not.exist; - expect(parts).to.exist; - - expect(imapClientStub.getBodyParts.calledOnce).to.be.true; - expect(parseStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when getBody fails', function(done) { - imapClientStub.getBodyParts.yieldsAsync({}); - - dao._getBodyParts({ - folder: inboxFolder, - uid: 123, - bodyParts: [] - }, function(err, msg) { - expect(err).to.exist; - expect(msg).to.not.exist; - - expect(imapClientStub.getBodyParts.calledOnce).to.be.true; - expect(parseStub.called).to.be.false; - - done(); - }); - }); - - it('should fail when disconnected', function(done) { - dao._account.online = false; - - dao._getBodyParts({}, function(err) { - expect(err.code).to.equal(42); - done(); - }); - }); - }); - - describe('#_localListMessages', function() { - var uid = 123; - - it('should list without uid', function(done) { - devicestorageStub.listItems.withArgs('email_' + inboxFolder.path, 0, null).yieldsAsync(); - - dao._localListMessages({ - folder: inboxFolder - }, done); - }); - - it('should list with uid', function(done) { - devicestorageStub.listItems.withArgs('email_' + inboxFolder.path + '_' + uid, 0, null).yieldsAsync(); - - dao._localListMessages({ - folder: inboxFolder, - uid: uid - }, done); - }); - - }); - - describe('#_localStoreMessages', function() { - it('should store messages', function(done) { - devicestorageStub.storeList.withArgs([{}], 'email_' + inboxFolder.path).yieldsAsync(); - - dao._localStoreMessages({ - folder: inboxFolder, - emails: [{}] - }, done); - }); - }); - - describe('#_localDeleteMessage', function() { - var uid = 1337; - - it('should delete message', function(done) { - devicestorageStub.removeList.withArgs('email_' + inboxFolder.path + '_' + uid).yieldsAsync(); - - dao._localDeleteMessage({ - folder: inboxFolder, - uid: uid - }, done); - }); - - it('should fail when uid is missing', function(done) { - dao._localDeleteMessage({ - folder: inboxFolder - }, function(err) { - expect(err).to.exist; - done(); - }); - }); - }); }); }); + + describe('event handlers', function() { + + describe('#onConnect', function() { + var initFoldersStub; + + beforeEach(function() { + initFoldersStub = sinon.stub(dao, '_initFoldersFromImap'); + delete dao._imapClient; + delete dao._pgpMailer; + }); + + it('should connect', function(done) { + inboxFolder.messages = [{ + uid: 123, + modseq: 123 + }]; + imapClientStub.login.yieldsAsync(); + imapClientStub.listenForChanges.yieldsAsync(); + initFoldersStub.yieldsAsync(); + + dao.onConnect({ + imapClient: imapClientStub, + pgpMailer: pgpMailerStub + }, function(err) { + + expect(err).to.not.exist; + expect(imapClientStub.login.calledOnce).to.be.true; + expect(initFoldersStub.calledOnce).to.be.true; + expect(imapClientStub.mailboxCache).to.deep.equal({ + 'INBOX': { + exists: 123, + uidNext: 124, + uidlist: [123], + highestModseq: 123 + } + }); + + done(); + }); + }); + }); + + describe('#onDisconnect', function() { + it('should discard imapClient and pgpMailer', function(done) { + imapClientStub.logout.yieldsAsync(); + + dao.onDisconnect(done); + + expect(dao._account.online).to.be.false; + expect(dao._imapClient).to.not.exist; + expect(dao._pgpMailer).to.not.exist; + }); + }); + + describe('#_onSyncUpdate', function() { + var fetchMessagesStub, deleteMessagesStub, setFlagsStub, msgs; + + beforeEach(function() { + msgs = [{ + uid: 5, + flags: ['\\Answered', '\\Seen'] + }]; + inboxFolder.messages = msgs; + fetchMessagesStub = sinon.stub(dao, 'fetchMessages'); + deleteMessagesStub = sinon.stub(dao, 'deleteMessage'); + setFlagsStub = sinon.stub(dao, 'setFlags'); + }); + + it('should get new message', function(done) { + fetchMessagesStub.withArgs({ + folder: inboxFolder, + firstUid: 1, + lastUid: 3 + }).yieldsAsync(); + + dao.onError = function(err) { + expect(err).to.not.exist; + expect(fetchMessagesStub.calledOnce).to.be.true; + done(); + }; + + dao._onSyncUpdate({ + type: 'new', + path: inboxFolder.path, + list: [1, 3] + }); + }); + + it('should delete message', function(done) { + deleteMessagesStub.withArgs({ + folder: inboxFolder, + message: msgs[0], + localOnly: true + }).yieldsAsync(); + + dao.onError = function(err) { + expect(err).to.not.exist; + expect(deleteMessagesStub.calledOnce).to.be.true; + done(); + }; + + dao._onSyncUpdate({ + type: 'deleted', + path: inboxFolder.path, + list: [5] + }); + }); + + it('should fetch flags', function(done) { + setFlagsStub.withArgs({ + folder: inboxFolder, + message: msgs[0], + localOnly: true + }).yieldsAsync(); + + dao.onError = function(err) { + expect(err).to.not.exist; + expect(setFlagsStub.calledOnce).to.be.true; + done(); + }; + + dao._onSyncUpdate({ + type: 'messages', + path: inboxFolder.path, + list: msgs + }); + }); + }); + }); + + + describe('internal API', function() { + describe('#_checkSignatures', function() { + it('should check signatures in clearsigned message', function(done) { + var message = { + from: [{ + address: 'asdasdasd' + }], + clearSignedMessage: 'trallalalalala' + }; + + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.verifyClearSignedMessage.withArgs(message.clearSignedMessage, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); + + dao._checkSignatures(message, function(error, signaturesValid) { + expect(error).to.not.exist; + expect(signaturesValid).to.be.true; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.verifyClearSignedMessage.calledOnce).to.be.true; + done(); + }); + }); + + it('should check signatures in pgp/mime signed message', function(done) { + var message = { + from: [{ + address: 'asdasdasd' + }], + signedMessage: 'trallalalalala', + signature: 'ugauga' + }; + + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.verifySignedMessage.withArgs(message.signedMessage, message.signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); + + dao._checkSignatures(message, function(error, signaturesValid) { + expect(error).to.not.exist; + expect(signaturesValid).to.be.true; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; + done(); + }); + }); + + it('should error while checking signatures', function(done) { + var message = { + from: [{ + address: 'asdasdasd' + }], + signedMessage: 'trallalalalala', + signature: 'ugauga' + }; + + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.verifySignedMessage.yieldsAsync(new Error()); + + dao._checkSignatures(message, function(error, signaturesValid) { + expect(error).to.exist; + expect(signaturesValid).to.not.exist; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; + done(); + }); + }); + + it('should error while fetching public key', function(done) { + var message = { + from: [{ + address: 'asdasdasd' + }], + signedMessage: 'trallalalalala', + signature: 'ugauga' + }; + + keychainStub.getReceiverPublicKey.yieldsAsync(new Error()); + + dao._checkSignatures(message, function(error, signaturesValid) { + expect(error).to.exist; + expect(signaturesValid).to.not.exist; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.verifySignedMessage.called).to.be.false; + done(); + }); + }); + }); + + describe('#_initFoldersFromDisk', function() { + beforeEach(function() { + sinon.stub(dao, 'refreshFolder'); + }); + + it('should initialize from disk if offline and not refresh folder', function(done) { + devicestorageStub.listItems.withArgs('folders').yieldsAsync(null, [ + [inboxFolder] + ]); + dao.refreshFolder.withArgs({ + folder: inboxFolder + }).yieldsAsync(); + + dao._initFoldersFromDisk(function(err) { + expect(err).to.not.exist; + expect(devicestorageStub.listItems.calledOnce).to.be.true; + expect(dao.refreshFolder.called).to.be.false; + done(); + }); + }); + + it('should initialize from disk if offline and refresh folder', function(done) { + delete inboxFolder.messages; + devicestorageStub.listItems.withArgs('folders').yieldsAsync(null, [ + [inboxFolder] + ]); + dao.refreshFolder.withArgs({ + folder: inboxFolder + }).yieldsAsync(); + + dao._initFoldersFromDisk(function(err) { + expect(err).to.not.exist; + expect(devicestorageStub.listItems.calledOnce).to.be.true; + expect(dao.refreshFolder.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('#_initFoldersFromImap', function() { + beforeEach(function() { + sinon.stub(dao, 'refreshFolder'); + }); + + it('should initialize from imap if online', function(done) { + account.folders = []; + imapClientStub.listWellKnownFolders.yieldsAsync(null, { + Inbox: [inboxFolder], + Sent: [sentFolder], + Drafts: [draftsFolder], + Trash: [trashFolder] + }); + devicestorageStub.storeList.withArgs(sinon.match(function(arg) { + expect(arg[0][0].name).to.deep.equal(inboxFolder.name); + expect(arg[0][0].path).to.deep.equal(inboxFolder.path); + expect(arg[0][0].type).to.deep.equal(inboxFolder.type); + expect(arg[0][1].name).to.deep.equal(sentFolder.name); + expect(arg[0][1].path).to.deep.equal(sentFolder.path); + expect(arg[0][1].type).to.deep.equal(sentFolder.type); + expect(arg[0][2].name).to.deep.equal(outboxFolder.name); + expect(arg[0][2].path).to.deep.equal(outboxFolder.path); + expect(arg[0][2].type).to.deep.equal(outboxFolder.type); + expect(arg[0][3].name).to.deep.equal(draftsFolder.name); + expect(arg[0][3].path).to.deep.equal(draftsFolder.path); + expect(arg[0][3].type).to.deep.equal(draftsFolder.type); + expect(arg[0][4].name).to.deep.equal(trashFolder.name); + expect(arg[0][4].path).to.deep.equal(trashFolder.path); + expect(arg[0][4].type).to.deep.equal(trashFolder.type); + return true; + }), 'folders').yieldsAsync(); + + dao.refreshFolder.yieldsAsync(); + + dao._initFoldersFromImap(function(err) { + expect(err).to.not.exist; + expect(imapClientStub.listWellKnownFolders.calledOnce).to.be.true; + expect(devicestorageStub.storeList.calledOnce).to.be.true; + done(); + }); + }); + + it('should update folders from imap', function(done) { + account.folders = [inboxFolder, outboxFolder, trashFolder, { + name: 'foo', + type: 'Sent', + path: 'bar', + }]; + + imapClientStub.listWellKnownFolders.yieldsAsync(null, { + Inbox: [inboxFolder], + Sent: [sentFolder], + Drafts: [draftsFolder], + Trash: [trashFolder] + }); + devicestorageStub.storeList.withArgs(sinon.match(function(arg) { + expect(arg[0]).to.deep.equal([{ + name: inboxFolder.name, + path: inboxFolder.path, + type: inboxFolder.type + }, { + name: outboxFolder.name, + path: outboxFolder.path, + type: outboxFolder.type + }, { + name: trashFolder.name, + path: trashFolder.path, + type: trashFolder.type + }, { + name: sentFolder.name, + path: sentFolder.path, + type: sentFolder.type + }, { + name: draftsFolder.name, + path: draftsFolder.path, + type: draftsFolder.type + }]); + + return true; + }), 'folders').yieldsAsync(); + + dao.refreshFolder.yieldsAsync(); + + dao._initFoldersFromImap(function(err) { + expect(err).to.not.exist; + expect(imapClientStub.listWellKnownFolders.calledOnce).to.be.true; + expect(devicestorageStub.storeList.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('#_imapMark', function() { + it('should flag a mail', function(done) { + imapClientStub.updateFlags.withArgs({ + path: inboxFolder.path, + folder: inboxFolder, + uid: 1, + unread: false, + answered: false + }).yieldsAsync(); + + dao._imapMark({ + folder: inboxFolder, + uid: 1, + unread: false, + answered: false + }, function(err) { + expect(err).to.not.exist; + expect(imapClientStub.updateFlags.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('#_imapDeleteMessage', function() { + var uid = 1337; + + it('should fail when disconnected', function(done) { + dao._account.online = false; + + dao._imapDeleteMessage({}, function(err) { + expect(err.code).to.equal(42); + done(); + }); + }); + + it('should move to trash', function(done) { + imapClientStub.moveMessage.withArgs({ + path: inboxFolder.path, + uid: uid, + destination: trashFolder.path + }).yieldsAsync(); + + dao._imapDeleteMessage({ + folder: inboxFolder, + uid: uid + }, done); + }); + + it('should purge message', function(done) { + imapClientStub.deleteMessage.withArgs({ + path: trashFolder.path, + uid: uid + }).yieldsAsync(); + + dao._imapDeleteMessage({ + folder: trashFolder, + uid: uid + }, done); + }); + }); + + describe('#_imapListMessages', function() { + var firstUid = 1337, + lastUid = 1339; + + it('should list messages', function(done) { + imapClientStub.listMessages.withArgs({ + folder: inboxFolder, + path: inboxFolder.path, + firstUid: firstUid, + lastUid: lastUid + }).yieldsAsync(null, []); + + dao._imapListMessages({ + folder: inboxFolder, + firstUid: firstUid, + lastUid: lastUid + }, function(err, msgs) { + expect(err).to.not.exist; + expect(msgs).to.exist; + + expect(imapClientStub.listMessages.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when listMessages fails', function(done) { + imapClientStub.listMessages.yieldsAsync({}); + + dao._imapListMessages({ + folder: inboxFolder, + firstUid: firstUid, + lastUid: lastUid + }, function(err, msgs) { + expect(err).to.exist; + expect(msgs).to.not.exist; + expect(imapClientStub.listMessages.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when disconnected', function(done) { + dao._account.online = false; + + dao._imapListMessages({}, function(err) { + expect(err.code).to.equal(42); + done(); + }); + }); + }); + + describe('#_getBodyParts', function() { + it('should get bodyParts', function(done) { + imapClientStub.getBodyParts.withArgs({ + folder: inboxFolder, + path: inboxFolder.path, + uid: 123, + bodyParts: [] + }).yieldsAsync(null, {}); + parseStub.yieldsAsync(null, []); + + dao._getBodyParts({ + folder: inboxFolder, + uid: 123, + bodyParts: [] + }, function(err, parts) { + expect(err).to.not.exist; + expect(parts).to.exist; + + expect(imapClientStub.getBodyParts.calledOnce).to.be.true; + expect(parseStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when getBody fails', function(done) { + imapClientStub.getBodyParts.yieldsAsync({}); + + dao._getBodyParts({ + folder: inboxFolder, + uid: 123, + bodyParts: [] + }, function(err, msg) { + expect(err).to.exist; + expect(msg).to.not.exist; + + expect(imapClientStub.getBodyParts.calledOnce).to.be.true; + expect(parseStub.called).to.be.false; + + done(); + }); + }); + + it('should fail when disconnected', function(done) { + dao._account.online = false; + + dao._getBodyParts({}, function(err) { + expect(err.code).to.equal(42); + done(); + }); + }); + }); + + describe('#_localListMessages', function() { + var uid = 123; + + it('should list without uid', function(done) { + devicestorageStub.listItems.withArgs('email_' + inboxFolder.path, 0, null).yieldsAsync(); + + dao._localListMessages({ + folder: inboxFolder + }, done); + }); + + it('should list with uid', function(done) { + devicestorageStub.listItems.withArgs('email_' + inboxFolder.path + '_' + uid, 0, null).yieldsAsync(); + + dao._localListMessages({ + folder: inboxFolder, + uid: uid + }, done); + }); + + }); + + describe('#_localStoreMessages', function() { + it('should store messages', function(done) { + devicestorageStub.storeList.withArgs([{}], 'email_' + inboxFolder.path).yieldsAsync(); + + dao._localStoreMessages({ + folder: inboxFolder, + emails: [{}] + }, done); + }); + }); + + describe('#_localDeleteMessage', function() { + var uid = 1337; + + it('should delete message', function(done) { + devicestorageStub.removeList.withArgs('email_' + inboxFolder.path + '_' + uid).yieldsAsync(); + + dao._localDeleteMessage({ + folder: inboxFolder, + uid: uid + }, done); + }); + + it('should fail when uid is missing', function(done) { + dao._localDeleteMessage({ + folder: inboxFolder + }, function(err) { + expect(err).to.exist; + done(); + }); + }); + + }); + }); }); \ No newline at end of file diff --git a/test/unit/index.html b/test/unit/index.html index 8a0094a..c6366e0 100644 --- a/test/unit/index.html +++ b/test/unit/index.html @@ -8,12 +8,71 @@
+ + - + - + + + + diff --git a/test/unit/invitation-dao-test.js b/test/unit/invitation-dao-test.js index 9982119..136c088 100644 --- a/test/unit/invitation-dao-test.js +++ b/test/unit/invitation-dao-test.js @@ -1,108 +1,105 @@ -define(function(require) { - 'use strict'; +'use strict'; - var RestDAO = require('js/dao/rest-dao'), - InvitationDAO = require('js/dao/invitation-dao'), - expect = chai.expect; +var RestDAO = require('../../src/js/dao/rest-dao'), + InvitationDAO = require('../../src/js/dao/invitation-dao'); - describe('Invitation DAO unit tests', function() { - var restDaoStub, invitationDao, - alice = 'zuhause@aol.com', - bob = 'manfred.mustermann@musterdomain.com', - expectedUri = '/invitation/recipient/' + alice + '/sender/' + bob; +describe('Invitation DAO unit tests', function() { + var restDaoStub, invitationDao, + alice = 'zuhause@aol.com', + bob = 'manfred.mustermann@musterdomain.com', + expectedUri = '/invitation/recipient/' + alice + '/sender/' + bob; - beforeEach(function() { - restDaoStub = sinon.createStubInstance(RestDAO); - invitationDao = new InvitationDAO(restDaoStub); + beforeEach(function() { + restDaoStub = sinon.createStubInstance(RestDAO); + invitationDao = new InvitationDAO(restDaoStub); + }); + + describe('initialization', function() { + it('should wire up correctly', function() { + expect(invitationDao._restDao).to.equal(restDaoStub); + expect(invitationDao.invite).to.exist; + expect(InvitationDAO.INVITE_MISSING).to.equal(1); + expect(InvitationDAO.INVITE_PENDING).to.equal(2); + expect(InvitationDAO.INVITE_SUCCESS).to.equal(4); }); + }); - describe('initialization', function() { - it('should wire up correctly', function() { - expect(invitationDao._restDao).to.equal(restDaoStub); - expect(invitationDao.invite).to.exist; - expect(InvitationDAO.INVITE_MISSING).to.equal(1); - expect(InvitationDAO.INVITE_PENDING).to.equal(2); - expect(InvitationDAO.INVITE_SUCCESS).to.equal(4); + describe('invite', function() { + it('should invite the recipient', function(done) { + restDaoStub.put.yieldsAsync(null, undefined, 201); + + invitationDao.invite({ + recipient: alice, + sender: bob + }, function(err, status) { + expect(err).to.not.exist; + expect(status).to.equal(InvitationDAO.INVITE_SUCCESS); + expect(restDaoStub.put.calledWith({}, expectedUri)).to.be.true; + done(); }); }); - describe('invite', function() { - it('should invite the recipient', function(done) { - restDaoStub.put.yieldsAsync(null, undefined, 201); + it('should point out already invited recipient', function(done) { + restDaoStub.put.yieldsAsync(null, undefined, 304); - invitationDao.invite({ - recipient: alice, - sender: bob - }, function(err, status) { - expect(err).to.not.exist; - expect(status).to.equal(InvitationDAO.INVITE_SUCCESS); - expect(restDaoStub.put.calledWith({}, expectedUri)).to.be.true; - done(); - }); + invitationDao.invite({ + recipient: alice, + sender: bob + }, function(err, status) { + expect(err).to.not.exist; + expect(status).to.equal(InvitationDAO.INVITE_PENDING); + done(); + }); + }); + + it('should not work for http error', function(done) { + restDaoStub.put.yieldsAsync({ + errMsg: 'jawollja.' }); - it('should point out already invited recipient', function(done) { - restDaoStub.put.yieldsAsync(null, undefined, 304); - - invitationDao.invite({ - recipient: alice, - sender: bob - }, function(err, status) { - expect(err).to.not.exist; - expect(status).to.equal(InvitationDAO.INVITE_PENDING); - done(); - }); + invitationDao.invite({ + recipient: alice, + sender: bob + }, function(err, status) { + expect(err).to.exist; + expect(status).to.not.exist; + done(); }); + }); - it('should not work for http error', function(done) { - restDaoStub.put.yieldsAsync({ - errMsg: 'jawollja.' - }); + it('should not work for unexpected response', function(done) { + restDaoStub.put.yieldsAsync(null, undefined, 1337); - invitationDao.invite({ - recipient: alice, - sender: bob - }, function(err, status) { - expect(err).to.exist; - expect(status).to.not.exist; - done(); - }); + invitationDao.invite({ + recipient: alice, + sender: bob + }, function(err, status) { + expect(err).to.exist; + expect(status).to.not.exist; + done(); }); + }); - it('should not work for unexpected response', function(done) { - restDaoStub.put.yieldsAsync(null, undefined, 1337); + it('should report erroneous usage', function() { + invitationDao.invite({ + sender: bob + }, expectError); - invitationDao.invite({ - recipient: alice, - sender: bob - }, function(err, status) { - expect(err).to.exist; - expect(status).to.not.exist; - done(); - }); - }); + invitationDao.invite({ + recipient: alice, + }, expectError); - it('should report erroneous usage', function() { - invitationDao.invite({ - sender: bob - }, expectError); + invitationDao.invite({ + recipient: 123, + sender: 123 + }, expectError); - invitationDao.invite({ - recipient: alice, - }, expectError); + invitationDao.invite('asd', expectError); - invitationDao.invite({ - recipient: 123, - sender: 123 - }, expectError); - - invitationDao.invite('asd', expectError); - - function expectError(err, status) { - expect(err).to.exist; - expect(status).to.not.exist; - } - }); + function expectError(err, status) { + expect(err).to.exist; + expect(status).to.not.exist; + } }); }); }); \ No newline at end of file diff --git a/test/unit/keychain-dao-test.js b/test/unit/keychain-dao-test.js index c05cef1..34f5b5f 100644 --- a/test/unit/keychain-dao-test.js +++ b/test/unit/keychain-dao-test.js @@ -1,1386 +1,1382 @@ -define(function(require) { - 'use strict'; +'use strict'; - var LawnchairDAO = require('js/dao/lawnchair-dao'), - PublicKeyDAO = require('js/dao/publickey-dao'), - KeychainDAO = require('js/dao/keychain-dao'), - PrivateKeyDAO = require('js/dao/privatekey-dao'), - Crypto = require('js/crypto/crypto'), - PGP = require('js/crypto/pgp'), - expect = chai.expect; +var LawnchairDAO = require('../../src/js/dao/lawnchair-dao'), + PublicKeyDAO = require('../../src/js/dao/publickey-dao'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + PrivateKeyDAO = require('../../src/js/dao/privatekey-dao'), + Crypto = require('../../src/js/crypto/crypto'), + PGP = require('../../src/js/crypto/pgp'); - var testUser = 'test@example.com'; +var testUser = 'test@example.com'; - describe('Keychain DAO unit tests', function() { +describe('Keychain DAO unit tests', function() { - var keychainDao, lawnchairDaoStub, pubkeyDaoStub, privkeyDaoStub, cryptoStub, pgpStub; + var keychainDao, lawnchairDaoStub, pubkeyDaoStub, privkeyDaoStub, cryptoStub, pgpStub; + + beforeEach(function() { + lawnchairDaoStub = sinon.createStubInstance(LawnchairDAO); + pubkeyDaoStub = sinon.createStubInstance(PublicKeyDAO); + privkeyDaoStub = sinon.createStubInstance(PrivateKeyDAO); + cryptoStub = sinon.createStubInstance(Crypto); + pgpStub = sinon.createStubInstance(PGP); + keychainDao = new KeychainDAO(lawnchairDaoStub, pubkeyDaoStub, privkeyDaoStub, cryptoStub, pgpStub); + }); + + afterEach(function() {}); + + describe('verify public key', function() { + it('should verify public key', function(done) { + var uuid = 'asdfasdfasdfasdf'; + pubkeyDaoStub.verify.yields(); + + keychainDao.verifyPublicKey(uuid, function() { + expect(pubkeyDaoStub.verify.calledWith(uuid)).to.be.true; + done(); + }); + }); + }); + + describe('listLocalPublicKeys', function() { + it('should work', function(done) { + lawnchairDaoStub.list.withArgs('publickey', 0, null).yields(); + + keychainDao.listLocalPublicKeys(function() { + expect(lawnchairDaoStub.list.callCount).to.equal(1); + done(); + }); + }); + }); + + describe('removeLocalPublicKey', function() { + it('should work', function(done) { + var id = 'asdf'; + + lawnchairDaoStub.remove.withArgs('publickey_' + id).yields(); + + keychainDao.removeLocalPublicKey(id, function() { + expect(lawnchairDaoStub.remove.callCount).to.equal(1); + done(); + }); + }); + }); + + describe('refreshKeyForUserId', function() { + var getPubKeyStub, + oldKey = { + _id: 123 + }, + newKey = { + _id: 456 + }, + importedKey = { + _id: 789, + imported: true + }; beforeEach(function() { - lawnchairDaoStub = sinon.createStubInstance(LawnchairDAO); - pubkeyDaoStub = sinon.createStubInstance(PublicKeyDAO); - privkeyDaoStub = sinon.createStubInstance(PrivateKeyDAO); - cryptoStub = sinon.createStubInstance(Crypto); - pgpStub = sinon.createStubInstance(PGP); - keychainDao = new KeychainDAO(lawnchairDaoStub, pubkeyDaoStub, privkeyDaoStub, cryptoStub, pgpStub); + getPubKeyStub = sinon.stub(keychainDao, 'getReceiverPublicKey'); }); - afterEach(function() {}); + afterEach(function() { + keychainDao.getReceiverPublicKey.restore(); + delete keychainDao.requestPermissionForKeyUpdate; + }); - describe('verify public key', function() { - it('should verify public key', function(done) { - var uuid = 'asdfasdfasdfasdf'; - pubkeyDaoStub.verify.yields(); + it('should not find a key', function(done) { + getPubKeyStub.yields(); - keychainDao.verifyPublicKey(uuid, function() { - expect(pubkeyDaoStub.verify.calledWith(uuid)).to.be.true; - done(); - }); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.not.exist; + + done(); }); }); - describe('listLocalPublicKeys', function() { - it('should work', function(done) { - lawnchairDaoStub.list.withArgs('publickey', 0, null).yields(); + it('should not update the key when up to date', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields(null, oldKey); - keychainDao.listLocalPublicKeys(function() { - expect(lawnchairDaoStub.list.callCount).to.equal(1); - done(); - }); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.to.equal(oldKey); + + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + + + done(); }); }); - describe('removeLocalPublicKey', function() { - it('should work', function(done) { - var id = 'asdf'; + it('should update key', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields(); + pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey); + keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { + expect(opts.userId).to.equal(testUser); + expect(opts.newKey).to.equal(newKey); + cb(true); + }; + lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields(); + lawnchairDaoStub.persist.withArgs('publickey_' + newKey._id, newKey).yields(); - lawnchairDaoStub.remove.withArgs('publickey_' + id).yields(); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.equal(newKey); - keychainDao.removeLocalPublicKey(id, function() { - expect(lawnchairDaoStub.remove.callCount).to.equal(1); - done(); - }); + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + expect(lawnchairDaoStub.remove.calledOnce).to.be.true; + expect(lawnchairDaoStub.persist.calledOnce).to.be.true; + + done(); }); }); - describe('refreshKeyForUserId', function() { - var getPubKeyStub, - oldKey = { - _id: 123 - }, - newKey = { - _id: 456 - }, - importedKey = { - _id: 789, - imported: true - }; + it('should remove key', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields(); + pubkeyDaoStub.getByUserId.withArgs(testUser).yields(); + keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { + expect(opts.userId).to.equal(testUser); + expect(opts.newKey).to.not.exist; + cb(true); + }; + lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields(); - beforeEach(function() { - getPubKeyStub = sinon.stub(keychainDao, 'getReceiverPublicKey'); - }); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.not.exist; - afterEach(function() { - keychainDao.getReceiverPublicKey.restore(); - delete keychainDao.requestPermissionForKeyUpdate; - }); + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + expect(lawnchairDaoStub.remove.calledOnce).to.be.true; + expect(lawnchairDaoStub.persist.called).to.be.false; - it('should not find a key', function(done) { - getPubKeyStub.yields(); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.not.exist; - - done(); - }); - }); - - it('should not update the key when up to date', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields(null, oldKey); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.to.equal(oldKey); - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - - - done(); - }); - }); - - it('should update key', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields(); - pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey); - keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { - expect(opts.userId).to.equal(testUser); - expect(opts.newKey).to.equal(newKey); - cb(true); - }; - lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields(); - lawnchairDaoStub.persist.withArgs('publickey_' + newKey._id, newKey).yields(); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.equal(newKey); - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - expect(lawnchairDaoStub.remove.calledOnce).to.be.true; - expect(lawnchairDaoStub.persist.calledOnce).to.be.true; - - done(); - }); - }); - - it('should remove key', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields(); - pubkeyDaoStub.getByUserId.withArgs(testUser).yields(); - keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { - expect(opts.userId).to.equal(testUser); - expect(opts.newKey).to.not.exist; - cb(true); - }; - lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields(); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.not.exist; - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - expect(lawnchairDaoStub.remove.calledOnce).to.be.true; - expect(lawnchairDaoStub.persist.called).to.be.false; - - done(); - }); - }); - - it('should go offline while fetching new key', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields(); - pubkeyDaoStub.getByUserId.withArgs(testUser).yields({ - code: 42 - }); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.to.equal(oldKey); - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - expect(lawnchairDaoStub.remove.called).to.be.false; - expect(lawnchairDaoStub.persist.called).to.be.false; - - done(); - }); - }); - - it('should not remove old key on user rejection', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields(); - pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey); - keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { - expect(opts.userId).to.equal(testUser); - expect(opts.newKey).to.exist; - cb(false); - }; - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.equal(oldKey); - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - expect(lawnchairDaoStub.remove.called).to.be.false; - expect(lawnchairDaoStub.persist.called).to.be.false; - - done(); - }); - }); - - it('should not remove manually imported key', function(done) { - getPubKeyStub.yields(null, importedKey); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.equal(importedKey); - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.false; - - done(); - }); - }); - - it('should update not the key when offline', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields({ - code: 42 - }); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.to.equal(oldKey); - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.called).to.be.false; - expect(lawnchairDaoStub.remove.called).to.be.false; - expect(lawnchairDaoStub.persist.called).to.be.false; - - done(); - }); - }); - - it('should error while persisting new key', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields(); - pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey); - keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { - expect(opts.userId).to.equal(testUser); - expect(opts.newKey).to.equal(newKey); - cb(true); - }; - lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields(); - lawnchairDaoStub.persist.yields({}); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - expect(lawnchairDaoStub.remove.calledOnce).to.be.true; - expect(lawnchairDaoStub.persist.calledOnce).to.be.true; - - done(); - }); - }); - - it('should error while deleting old key', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields(); - pubkeyDaoStub.getByUserId.withArgs(testUser).yields(); - keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { - expect(opts.userId).to.equal(testUser); - cb(true); - }; - lawnchairDaoStub.remove.yields({}); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(lawnchairDaoStub.remove.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - expect(lawnchairDaoStub.persist.called).to.be.false; - - done(); - }); - }); - - it('should error while persisting new key', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields(); - pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey); - keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { - expect(opts.userId).to.equal(testUser); - expect(opts.newKey).to.equal(newKey); - cb(true); - }; - lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields(); - lawnchairDaoStub.persist.yields({}); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - - expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - expect(lawnchairDaoStub.remove.calledOnce).to.be.true; - expect(lawnchairDaoStub.persist.calledOnce).to.be.true; - - done(); - }); - }); - - it('should error when get failed', function(done) { - getPubKeyStub.yields(null, oldKey); - pubkeyDaoStub.get.withArgs(oldKey._id).yields({}); - - keychainDao.refreshKeyForUserId(testUser, function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - - done(); - }); + done(); }); }); - describe('lookup public key', function() { - it('should fail', function(done) { - keychainDao.lookupPublicKey(undefined, function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - done(); - }); + it('should go offline while fetching new key', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields(); + pubkeyDaoStub.getByUserId.withArgs(testUser).yields({ + code: 42 }); - it('should fail', function(done) { - lawnchairDaoStub.read.yields(42); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.to.equal(oldKey); - keychainDao.lookupPublicKey('12345', function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - expect(lawnchairDaoStub.read.calledOnce).to.be.true; - done(); - }); - }); + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + expect(lawnchairDaoStub.remove.called).to.be.false; + expect(lawnchairDaoStub.persist.called).to.be.false; - it('should work from local storage', function(done) { - lawnchairDaoStub.read.yields(null, { - _id: '12345', - publicKey: 'asdf' - }); - - keychainDao.lookupPublicKey('12345', function(err, key) { - expect(err).to.not.exist; - expect(key).to.exist; - expect(lawnchairDaoStub.read.calledOnce).to.be.true; - done(); - }); - }); - - it('should work from cloud', function(done) { - lawnchairDaoStub.read.yields(); - pubkeyDaoStub.get.yields(null, { - _id: '12345', - publicKey: 'asdf' - }); - lawnchairDaoStub.persist.yields(); - - keychainDao.lookupPublicKey('12345', function(err, key) { - expect(err).to.not.exist; - expect(key).to.exist; - expect(key._id).to.equal('12345'); - expect(lawnchairDaoStub.read.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(lawnchairDaoStub.persist.calledOnce).to.be.true; - done(); - }); + done(); }); }); - describe('get public keys by id', function() { - it('should fail', function(done) { - keychainDao.getPublicKeys([], function(err, keys) { - expect(err).to.not.exist; - expect(keys.length).to.equal(0); - done(); - }); - }); + it('should not remove old key on user rejection', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields(); + pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey); + keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { + expect(opts.userId).to.equal(testUser); + expect(opts.newKey).to.exist; + cb(false); + }; - it('should fail', function(done) { - lawnchairDaoStub.read.yields(42); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.equal(oldKey); - var ids = [{ - _id: '12345' - }]; - keychainDao.getPublicKeys(ids, function(err, keys) { - expect(err).to.exist; - expect(keys).to.not.exist; - expect(lawnchairDaoStub.read.calledOnce).to.be.true; - done(); - }); - }); + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + expect(lawnchairDaoStub.remove.called).to.be.false; + expect(lawnchairDaoStub.persist.called).to.be.false; - it('should work from local storage', function(done) { - lawnchairDaoStub.read.yields(null, { - _id: '12345', - publicKey: 'asdf' - }); - - var ids = [{ - _id: '12345' - }]; - keychainDao.getPublicKeys(ids, function(err, keys) { - expect(err).to.not.exist; - expect(keys.length).to.equal(1); - expect(keys[0]._id).to.equal('12345'); - expect(lawnchairDaoStub.read.calledOnce).to.be.true; - done(); - }); + done(); }); }); - describe('get receiver public key', function() { - it('should fail due to error in lawnchair list', function(done) { - lawnchairDaoStub.list.yields(42); + it('should not remove manually imported key', function(done) { + getPubKeyStub.yields(null, importedKey); - keychainDao.getReceiverPublicKey(testUser, function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - done(); - }); - }); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.equal(importedKey); - it('should work from lawnchair list', function(done) { - lawnchairDaoStub.list.yields(null, [{ - _id: '12345', - userId: testUser, - publicKey: 'asdf' - }]); + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.false; - keychainDao.getReceiverPublicKey(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.exist; - expect(key._id).to.equal('12345'); - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - done(); - }); - }); - - it('should work for keys with secondary userIds', function(done) { - lawnchairDaoStub.list.yields(null, [{ - _id: '12345', - userId: 'not testUser', - userIds: [{ - emailAddress: testUser - }], - publicKey: 'asdf' - }]); - - keychainDao.getReceiverPublicKey(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.exist; - expect(key._id).to.equal('12345'); - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to error in pubkey dao', function(done) { - lawnchairDaoStub.list.yields(null, []); - pubkeyDaoStub.getByUserId.yields({}); - - keychainDao.getReceiverPublicKey(testUser, function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - done(); - }); - }); - - it('should work from pubkey dao with empty result', function(done) { - lawnchairDaoStub.list.yields(null, []); - pubkeyDaoStub.getByUserId.yields(); - - keychainDao.getReceiverPublicKey(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.not.exist; - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - done(); - }); - }); - - it('should work from pubkey dao', function(done) { - lawnchairDaoStub.list.yields(null, []); - pubkeyDaoStub.getByUserId.yields(null, { - _id: '12345', - publicKey: 'asdf' - }); - lawnchairDaoStub.persist.yields(); - - keychainDao.getReceiverPublicKey(testUser, function(err, key) { - expect(err).to.not.exist; - expect(key).to.exist; - expect(key._id).to.equal('12345'); - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - expect(lawnchairDaoStub.persist.calledOnce).to.be.true; - done(); - }); + done(); }); }); - describe('get user key pair', function() { - it('should work if local keys are already present', function(done) { - lawnchairDaoStub.list.yields(null, [{ - _id: '12345', - userId: testUser, - publicKey: 'asdf' - }]); - lawnchairDaoStub.read.yields(null, { - _id: '12345', - publicKey: 'asdf', - encryptedKey: 'qwer' - }); - - keychainDao.getUserKeyPair(testUser, function(err, keys) { - expect(err).to.not.exist; - expect(keys).to.exist; - expect(keys.publicKey).to.exist; - expect(keys.privateKey).to.exist; - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - expect(lawnchairDaoStub.read.calledTwice).to.be.true; - done(); - }); + it('should update not the key when offline', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields({ + code: 42 }); - it('should work if local keys are not already present', function(done) { - lawnchairDaoStub.list.yields(); - pubkeyDaoStub.getByUserId.yields(); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.to.equal(oldKey); - keychainDao.getUserKeyPair(testUser, function(err, keys) { - expect(err).to.not.exist; - expect(keys).to.not.exist; - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; - done(); - }); - }); + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.called).to.be.false; + expect(lawnchairDaoStub.remove.called).to.be.false; + expect(lawnchairDaoStub.persist.called).to.be.false; - it('should work if local keys are not already present', function(done) { - lawnchairDaoStub.list.yields(); - pubkeyDaoStub.getByUserId.yields(null, { - _id: '12345', - publicKey: 'asdf' - }); - lawnchairDaoStub.read.yields(null, { - _id: '12345', - publicKey: 'asdf', - encryptedKey: 'qwer' - }); - - keychainDao.getUserKeyPair(testUser, function(err, keys) { - expect(err).to.not.exist; - expect(keys).to.exist; - expect(keys.publicKey).to.exist; - expect(keys.privateKey).to.exist; - expect(lawnchairDaoStub.list.calledOnce).to.be.true; - expect(lawnchairDaoStub.read.calledTwice).to.be.true; - done(); - }); + done(); }); }); - describe('setDeviceName', function() { - it('should work', function(done) { - lawnchairDaoStub.persist.yields(); + it('should error while persisting new key', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields(); + pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey); + keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { + expect(opts.userId).to.equal(testUser); + expect(opts.newKey).to.equal(newKey); + cb(true); + }; + lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields(); + lawnchairDaoStub.persist.yields({}); - keychainDao.setDeviceName('iPhone', done); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; + + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + expect(lawnchairDaoStub.remove.calledOnce).to.be.true; + expect(lawnchairDaoStub.persist.calledOnce).to.be.true; + + done(); }); }); - describe('getDeviceName', function() { - it('should fail when device name is not set', function(done) { - lawnchairDaoStub.read.withArgs('devicename').yields(); + it('should error while deleting old key', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields(); + pubkeyDaoStub.getByUserId.withArgs(testUser).yields(); + keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { + expect(opts.userId).to.equal(testUser); + cb(true); + }; + lawnchairDaoStub.remove.yields({}); - keychainDao.getDeviceName(function(err, deviceName) { - expect(err.message).to.equal('Device name not set!'); - expect(deviceName).to.not.exist; - done(); - }); - }); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; - it('should fail due to error when reading device name', function(done) { - lawnchairDaoStub.read.withArgs('devicename').yields(42); + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(lawnchairDaoStub.remove.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + expect(lawnchairDaoStub.persist.called).to.be.false; - keychainDao.getDeviceName(function(err, deviceName) { - expect(err).to.equal(42); - expect(deviceName).to.not.exist; - done(); - }); - }); - - it('should work', function(done) { - lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); - - keychainDao.getDeviceName(function(err, deviceName) { - expect(err).to.not.exist; - expect(deviceName).to.equal('iPhone'); - done(); - }); + done(); }); }); - describe('getDeviceSecret', function() { - it('should fail due to error when reading device secret', function(done) { - lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); - lawnchairDaoStub.read.withArgs('devicesecret').yields(42); + it('should error while persisting new key', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields(); + pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey); + keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { + expect(opts.userId).to.equal(testUser); + expect(opts.newKey).to.equal(newKey); + cb(true); + }; + lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields(); + lawnchairDaoStub.persist.yields({}); - keychainDao.getDeviceSecret(function(err, deviceSecret) { - expect(err).to.equal(42); - expect(deviceSecret).to.not.exist; - done(); - }); - }); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; - it('should fail due to error when storing device secret', function(done) { - lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); - lawnchairDaoStub.read.withArgs('devicesecret').yields(); - lawnchairDaoStub.persist.withArgs('devicesecret').yields(42); + expect(getPubKeyStub.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + expect(lawnchairDaoStub.remove.calledOnce).to.be.true; + expect(lawnchairDaoStub.persist.calledOnce).to.be.true; - keychainDao.getDeviceSecret(function(err, deviceSecret) { - expect(err).to.equal(42); - expect(deviceSecret).to.not.exist; - done(); - }); - }); - - it('should work when device secret is not set', function(done) { - lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); - lawnchairDaoStub.read.withArgs('devicesecret').yields(); - lawnchairDaoStub.persist.withArgs('devicesecret').yields(); - - keychainDao.getDeviceSecret(function(err, deviceSecret) { - expect(err).to.not.exist; - expect(deviceSecret).to.exist; - done(); - }); - }); - - it('should work when device secret is set', function(done) { - lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); - lawnchairDaoStub.read.withArgs('devicesecret').yields(null, 'secret'); - - keychainDao.getDeviceSecret(function(err, deviceSecret) { - expect(err).to.not.exist; - expect(deviceSecret).to.equal('secret'); - done(); - }); + done(); }); }); - describe('registerDevice', function() { - var getDeviceNameStub, lookupPublicKeyStub, getDeviceSecretStub; + it('should error when get failed', function(done) { + getPubKeyStub.yields(null, oldKey); + pubkeyDaoStub.get.withArgs(oldKey._id).yields({}); - beforeEach(function() { - getDeviceNameStub = sinon.stub(keychainDao, 'getDeviceName'); - lookupPublicKeyStub = sinon.stub(keychainDao, 'lookupPublicKey'); - getDeviceSecretStub = sinon.stub(keychainDao, 'getDeviceSecret'); - }); - afterEach(function() { - getDeviceNameStub.restore(); - lookupPublicKeyStub.restore(); - getDeviceSecretStub.restore(); + keychainDao.refreshKeyForUserId(testUser, function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; + + done(); }); + }); + }); - it('should fail when reading devicename', function(done) { - getDeviceNameStub.yields(42); - - keychainDao.registerDevice({}, function(err) { - expect(err).to.equal(42); - done(); - }); - }); - - it('should fail in requestDeviceRegistration', function(done) { - getDeviceNameStub.yields(null, 'iPhone'); - - privkeyDaoStub.requestDeviceRegistration.withArgs({ - userId: testUser, - deviceName: 'iPhone' - }).yields(42); - - keychainDao.registerDevice({ - userId: testUser - }, function(err) { - expect(err).to.equal(42); - done(); - }); - }); - - it('should fail due to invalid requestDeviceRegistration return value', function(done) { - getDeviceNameStub.yields(null, 'iPhone'); - - privkeyDaoStub.requestDeviceRegistration.withArgs({ - userId: testUser, - deviceName: 'iPhone' - }).yields(null, {}); - - keychainDao.registerDevice({ - userId: testUser - }, function(err) { - expect(err.message).to.equal('Invalid format for session key!'); - done(); - }); - }); - - it('should fail in lookupPublicKey', function(done) { - getDeviceNameStub.yields(null, 'iPhone'); - - privkeyDaoStub.requestDeviceRegistration.withArgs({ - userId: testUser, - deviceName: 'iPhone' - }).yields(null, { - encryptedRegSessionKey: 'asdf' - }); - - lookupPublicKeyStub.yields(42); - - keychainDao.registerDevice({ - userId: testUser - }, function(err) { - expect(err).to.equal(42); - done(); - }); - }); - - it('should fail when server public key not found', function(done) { - getDeviceNameStub.yields(null, 'iPhone'); - - privkeyDaoStub.requestDeviceRegistration.withArgs({ - userId: testUser, - deviceName: 'iPhone' - }).yields(null, { - encryptedRegSessionKey: 'asdf' - }); - - lookupPublicKeyStub.yields(); - - keychainDao.registerDevice({ - userId: testUser - }, function(err) { - expect(err).to.exist; - done(); - }); - }); - - it('should fail in decrypt', function(done) { - getDeviceNameStub.yields(null, 'iPhone'); - - privkeyDaoStub.requestDeviceRegistration.withArgs({ - userId: testUser, - deviceName: 'iPhone' - }).yields(null, { - encryptedRegSessionKey: 'asdf' - }); - - lookupPublicKeyStub.yields(null, { - publicKey: 'pubkey' - }); - pgpStub.decrypt.withArgs('asdf', 'pubkey').yields(42); - - keychainDao.registerDevice({ - userId: testUser - }, function(err) { - expect(err).to.equal(42); - done(); - }); - }); - - it('should fail in getDeviceSecret', function(done) { - getDeviceNameStub.yields(null, 'iPhone'); - - privkeyDaoStub.requestDeviceRegistration.withArgs({ - userId: testUser, - deviceName: 'iPhone' - }).yields(null, { - encryptedRegSessionKey: 'asdf' - }); - - lookupPublicKeyStub.yields(null, { - publicKey: 'pubkey' - }); - pgpStub.decrypt.withArgs('asdf', 'pubkey').yields(null, 'decrypted', true, true); - getDeviceSecretStub.yields(42); - - keychainDao.registerDevice({ - userId: testUser - }, function(err) { - expect(err).to.equal(42); - done(); - }); - }); - - it('should fail in encrypt', function(done) { - getDeviceNameStub.yields(null, 'iPhone'); - - privkeyDaoStub.requestDeviceRegistration.withArgs({ - userId: testUser, - deviceName: 'iPhone' - }).yields(null, { - encryptedRegSessionKey: 'asdf' - }); - - lookupPublicKeyStub.yields(null, { - publicKey: 'pubkey' - }); - pgpStub.decrypt.withArgs('asdf', 'pubkey').yields(null, 'decrypted', true, true); - getDeviceSecretStub.yields(null, 'secret'); - cryptoStub.encrypt.withArgs('secret', 'decrypted').yields(42); - - keychainDao.registerDevice({ - userId: testUser - }, function(err) { - expect(err).to.equal(42); - done(); - }); - }); - - it('should work', function(done) { - getDeviceNameStub.yields(null, 'iPhone'); - - privkeyDaoStub.requestDeviceRegistration.withArgs({ - userId: testUser, - deviceName: 'iPhone' - }).yields(null, { - encryptedRegSessionKey: 'asdf' - }); - - lookupPublicKeyStub.yields(null, { - publicKey: 'pubkey' - }); - pgpStub.decrypt.withArgs('asdf', 'pubkey').yields(null, 'decrypted', true, true); - getDeviceSecretStub.yields(null, 'secret'); - cryptoStub.encrypt.withArgs('secret', 'decrypted').yields(null, 'encryptedDeviceSecret'); - privkeyDaoStub.uploadDeviceSecret.yields(); - - keychainDao.registerDevice({ - userId: testUser - }, function(err) { - expect(err).not.exist; - expect(privkeyDaoStub.uploadDeviceSecret.calledOnce).to.be.true; - done(); - }); + describe('lookup public key', function() { + it('should fail', function(done) { + keychainDao.lookupPublicKey(undefined, function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; + done(); }); }); - describe('_authenticateToPrivateKeyServer', function() { - var lookupPublicKeyStub, getDeviceSecretStub; + it('should fail', function(done) { + lawnchairDaoStub.read.yields(42); - beforeEach(function() { - lookupPublicKeyStub = sinon.stub(keychainDao, 'lookupPublicKey'); - getDeviceSecretStub = sinon.stub(keychainDao, 'getDeviceSecret'); + keychainDao.lookupPublicKey('12345', function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; + expect(lawnchairDaoStub.read.calledOnce).to.be.true; + done(); }); - afterEach(function() { - lookupPublicKeyStub.restore(); - getDeviceSecretStub.restore(); + }); + + it('should work from local storage', function(done) { + lawnchairDaoStub.read.yields(null, { + _id: '12345', + publicKey: 'asdf' }); - it('should fail due to privkeyDao.requestAuthSessionKey', function(done) { - privkeyDaoStub.requestAuthSessionKey.withArgs({ - userId: testUser - }).yields(42); + keychainDao.lookupPublicKey('12345', function(err, key) { + expect(err).to.not.exist; + expect(key).to.exist; + expect(lawnchairDaoStub.read.calledOnce).to.be.true; + done(); + }); + }); - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.equal(42); - expect(authSessionKey).to.not.exist; - done(); - }); + it('should work from cloud', function(done) { + lawnchairDaoStub.read.yields(); + pubkeyDaoStub.get.yields(null, { + _id: '12345', + publicKey: 'asdf' + }); + lawnchairDaoStub.persist.yields(); + + keychainDao.lookupPublicKey('12345', function(err, key) { + expect(err).to.not.exist; + expect(key).to.exist; + expect(key._id).to.equal('12345'); + expect(lawnchairDaoStub.read.calledOnce).to.be.true; + expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(lawnchairDaoStub.persist.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('get public keys by id', function() { + it('should fail', function(done) { + keychainDao.getPublicKeys([], function(err, keys) { + expect(err).to.not.exist; + expect(keys.length).to.equal(0); + done(); + }); + }); + + it('should fail', function(done) { + lawnchairDaoStub.read.yields(42); + + var ids = [{ + _id: '12345' + }]; + keychainDao.getPublicKeys(ids, function(err, keys) { + expect(err).to.exist; + expect(keys).to.not.exist; + expect(lawnchairDaoStub.read.calledOnce).to.be.true; + done(); + }); + }); + + it('should work from local storage', function(done) { + lawnchairDaoStub.read.yields(null, { + _id: '12345', + publicKey: 'asdf' }); - it('should fail due to privkeyDao.requestAuthSessionKey response', function(done) { - privkeyDaoStub.requestAuthSessionKey.yields(null, {}); + var ids = [{ + _id: '12345' + }]; + keychainDao.getPublicKeys(ids, function(err, keys) { + expect(err).to.not.exist; + expect(keys.length).to.equal(1); + expect(keys[0]._id).to.equal('12345'); + expect(lawnchairDaoStub.read.calledOnce).to.be.true; + done(); + }); + }); + }); - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.exist; - expect(authSessionKey).to.not.exist; - done(); - }); + describe('get receiver public key', function() { + it('should fail due to error in lawnchair list', function(done) { + lawnchairDaoStub.list.yields(42); + + keychainDao.getReceiverPublicKey(testUser, function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + done(); + }); + }); + + it('should work from lawnchair list', function(done) { + lawnchairDaoStub.list.yields(null, [{ + _id: '12345', + userId: testUser, + publicKey: 'asdf' + }]); + + keychainDao.getReceiverPublicKey(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.exist; + expect(key._id).to.equal('12345'); + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + done(); + }); + }); + + it('should work for keys with secondary userIds', function(done) { + lawnchairDaoStub.list.yields(null, [{ + _id: '12345', + userId: 'not testUser', + userIds: [{ + emailAddress: testUser + }], + publicKey: 'asdf' + }]); + + keychainDao.getReceiverPublicKey(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.exist; + expect(key._id).to.equal('12345'); + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + done(); + }); + }); + + it('should fail due to error in pubkey dao', function(done) { + lawnchairDaoStub.list.yields(null, []); + pubkeyDaoStub.getByUserId.yields({}); + + keychainDao.getReceiverPublicKey(testUser, function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + done(); + }); + }); + + it('should work from pubkey dao with empty result', function(done) { + lawnchairDaoStub.list.yields(null, []); + pubkeyDaoStub.getByUserId.yields(); + + keychainDao.getReceiverPublicKey(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.not.exist; + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + done(); + }); + }); + + it('should work from pubkey dao', function(done) { + lawnchairDaoStub.list.yields(null, []); + pubkeyDaoStub.getByUserId.yields(null, { + _id: '12345', + publicKey: 'asdf' + }); + lawnchairDaoStub.persist.yields(); + + keychainDao.getReceiverPublicKey(testUser, function(err, key) { + expect(err).to.not.exist; + expect(key).to.exist; + expect(key._id).to.equal('12345'); + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + expect(lawnchairDaoStub.persist.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('get user key pair', function() { + it('should work if local keys are already present', function(done) { + lawnchairDaoStub.list.yields(null, [{ + _id: '12345', + userId: testUser, + publicKey: 'asdf' + }]); + lawnchairDaoStub.read.yields(null, { + _id: '12345', + publicKey: 'asdf', + encryptedKey: 'qwer' }); - it('should fail due to lookupPublicKey', function(done) { - privkeyDaoStub.requestAuthSessionKey.yields(null, { - encryptedAuthSessionKey: 'encryptedAuthSessionKey', - encryptedChallenge: 'encryptedChallenge', + keychainDao.getUserKeyPair(testUser, function(err, keys) { + expect(err).to.not.exist; + expect(keys).to.exist; + expect(keys.publicKey).to.exist; + expect(keys.privateKey).to.exist; + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + expect(lawnchairDaoStub.read.calledTwice).to.be.true; + done(); + }); + }); + + it('should work if local keys are not already present', function(done) { + lawnchairDaoStub.list.yields(); + pubkeyDaoStub.getByUserId.yields(); + + keychainDao.getUserKeyPair(testUser, function(err, keys) { + expect(err).to.not.exist; + expect(keys).to.not.exist; + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; + done(); + }); + }); + + it('should work if local keys are not already present', function(done) { + lawnchairDaoStub.list.yields(); + pubkeyDaoStub.getByUserId.yields(null, { + _id: '12345', + publicKey: 'asdf' + }); + lawnchairDaoStub.read.yields(null, { + _id: '12345', + publicKey: 'asdf', + encryptedKey: 'qwer' + }); + + keychainDao.getUserKeyPair(testUser, function(err, keys) { + expect(err).to.not.exist; + expect(keys).to.exist; + expect(keys.publicKey).to.exist; + expect(keys.privateKey).to.exist; + expect(lawnchairDaoStub.list.calledOnce).to.be.true; + expect(lawnchairDaoStub.read.calledTwice).to.be.true; + done(); + }); + }); + }); + + describe('setDeviceName', function() { + it('should work', function(done) { + lawnchairDaoStub.persist.yields(); + + keychainDao.setDeviceName('iPhone', done); + }); + }); + + describe('getDeviceName', function() { + it('should fail when device name is not set', function(done) { + lawnchairDaoStub.read.withArgs('devicename').yields(); + + keychainDao.getDeviceName(function(err, deviceName) { + expect(err.message).to.equal('Device name not set!'); + expect(deviceName).to.not.exist; + done(); + }); + }); + + it('should fail due to error when reading device name', function(done) { + lawnchairDaoStub.read.withArgs('devicename').yields(42); + + keychainDao.getDeviceName(function(err, deviceName) { + expect(err).to.equal(42); + expect(deviceName).to.not.exist; + done(); + }); + }); + + it('should work', function(done) { + lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); + + keychainDao.getDeviceName(function(err, deviceName) { + expect(err).to.not.exist; + expect(deviceName).to.equal('iPhone'); + done(); + }); + }); + }); + + describe('getDeviceSecret', function() { + it('should fail due to error when reading device secret', function(done) { + lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); + lawnchairDaoStub.read.withArgs('devicesecret').yields(42); + + keychainDao.getDeviceSecret(function(err, deviceSecret) { + expect(err).to.equal(42); + expect(deviceSecret).to.not.exist; + done(); + }); + }); + + it('should fail due to error when storing device secret', function(done) { + lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); + lawnchairDaoStub.read.withArgs('devicesecret').yields(); + lawnchairDaoStub.persist.withArgs('devicesecret').yields(42); + + keychainDao.getDeviceSecret(function(err, deviceSecret) { + expect(err).to.equal(42); + expect(deviceSecret).to.not.exist; + done(); + }); + }); + + it('should work when device secret is not set', function(done) { + lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); + lawnchairDaoStub.read.withArgs('devicesecret').yields(); + lawnchairDaoStub.persist.withArgs('devicesecret').yields(); + + keychainDao.getDeviceSecret(function(err, deviceSecret) { + expect(err).to.not.exist; + expect(deviceSecret).to.exist; + done(); + }); + }); + + it('should work when device secret is set', function(done) { + lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone'); + lawnchairDaoStub.read.withArgs('devicesecret').yields(null, 'secret'); + + keychainDao.getDeviceSecret(function(err, deviceSecret) { + expect(err).to.not.exist; + expect(deviceSecret).to.equal('secret'); + done(); + }); + }); + }); + + describe('registerDevice', function() { + var getDeviceNameStub, lookupPublicKeyStub, getDeviceSecretStub; + + beforeEach(function() { + getDeviceNameStub = sinon.stub(keychainDao, 'getDeviceName'); + lookupPublicKeyStub = sinon.stub(keychainDao, 'lookupPublicKey'); + getDeviceSecretStub = sinon.stub(keychainDao, 'getDeviceSecret'); + }); + afterEach(function() { + getDeviceNameStub.restore(); + lookupPublicKeyStub.restore(); + getDeviceSecretStub.restore(); + }); + + it('should fail when reading devicename', function(done) { + getDeviceNameStub.yields(42); + + keychainDao.registerDevice({}, function(err) { + expect(err).to.equal(42); + done(); + }); + }); + + it('should fail in requestDeviceRegistration', function(done) { + getDeviceNameStub.yields(null, 'iPhone'); + + privkeyDaoStub.requestDeviceRegistration.withArgs({ + userId: testUser, + deviceName: 'iPhone' + }).yields(42); + + keychainDao.registerDevice({ + userId: testUser + }, function(err) { + expect(err).to.equal(42); + done(); + }); + }); + + it('should fail due to invalid requestDeviceRegistration return value', function(done) { + getDeviceNameStub.yields(null, 'iPhone'); + + privkeyDaoStub.requestDeviceRegistration.withArgs({ + userId: testUser, + deviceName: 'iPhone' + }).yields(null, {}); + + keychainDao.registerDevice({ + userId: testUser + }, function(err) { + expect(err.message).to.equal('Invalid format for session key!'); + done(); + }); + }); + + it('should fail in lookupPublicKey', function(done) { + getDeviceNameStub.yields(null, 'iPhone'); + + privkeyDaoStub.requestDeviceRegistration.withArgs({ + userId: testUser, + deviceName: 'iPhone' + }).yields(null, { + encryptedRegSessionKey: 'asdf' + }); + + lookupPublicKeyStub.yields(42); + + keychainDao.registerDevice({ + userId: testUser + }, function(err) { + expect(err).to.equal(42); + done(); + }); + }); + + it('should fail when server public key not found', function(done) { + getDeviceNameStub.yields(null, 'iPhone'); + + privkeyDaoStub.requestDeviceRegistration.withArgs({ + userId: testUser, + deviceName: 'iPhone' + }).yields(null, { + encryptedRegSessionKey: 'asdf' + }); + + lookupPublicKeyStub.yields(); + + keychainDao.registerDevice({ + userId: testUser + }, function(err) { + expect(err).to.exist; + done(); + }); + }); + + it('should fail in decrypt', function(done) { + getDeviceNameStub.yields(null, 'iPhone'); + + privkeyDaoStub.requestDeviceRegistration.withArgs({ + userId: testUser, + deviceName: 'iPhone' + }).yields(null, { + encryptedRegSessionKey: 'asdf' + }); + + lookupPublicKeyStub.yields(null, { + publicKey: 'pubkey' + }); + pgpStub.decrypt.withArgs('asdf', 'pubkey').yields(42); + + keychainDao.registerDevice({ + userId: testUser + }, function(err) { + expect(err).to.equal(42); + done(); + }); + }); + + it('should fail in getDeviceSecret', function(done) { + getDeviceNameStub.yields(null, 'iPhone'); + + privkeyDaoStub.requestDeviceRegistration.withArgs({ + userId: testUser, + deviceName: 'iPhone' + }).yields(null, { + encryptedRegSessionKey: 'asdf' + }); + + lookupPublicKeyStub.yields(null, { + publicKey: 'pubkey' + }); + pgpStub.decrypt.withArgs('asdf', 'pubkey').yields(null, 'decrypted', true, true); + getDeviceSecretStub.yields(42); + + keychainDao.registerDevice({ + userId: testUser + }, function(err) { + expect(err).to.equal(42); + done(); + }); + }); + + it('should fail in encrypt', function(done) { + getDeviceNameStub.yields(null, 'iPhone'); + + privkeyDaoStub.requestDeviceRegistration.withArgs({ + userId: testUser, + deviceName: 'iPhone' + }).yields(null, { + encryptedRegSessionKey: 'asdf' + }); + + lookupPublicKeyStub.yields(null, { + publicKey: 'pubkey' + }); + pgpStub.decrypt.withArgs('asdf', 'pubkey').yields(null, 'decrypted', true, true); + getDeviceSecretStub.yields(null, 'secret'); + cryptoStub.encrypt.withArgs('secret', 'decrypted').yields(42); + + keychainDao.registerDevice({ + userId: testUser + }, function(err) { + expect(err).to.equal(42); + done(); + }); + }); + + it('should work', function(done) { + getDeviceNameStub.yields(null, 'iPhone'); + + privkeyDaoStub.requestDeviceRegistration.withArgs({ + userId: testUser, + deviceName: 'iPhone' + }).yields(null, { + encryptedRegSessionKey: 'asdf' + }); + + lookupPublicKeyStub.yields(null, { + publicKey: 'pubkey' + }); + pgpStub.decrypt.withArgs('asdf', 'pubkey').yields(null, 'decrypted', true, true); + getDeviceSecretStub.yields(null, 'secret'); + cryptoStub.encrypt.withArgs('secret', 'decrypted').yields(null, 'encryptedDeviceSecret'); + privkeyDaoStub.uploadDeviceSecret.yields(); + + keychainDao.registerDevice({ + userId: testUser + }, function(err) { + expect(err).not.exist; + expect(privkeyDaoStub.uploadDeviceSecret.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('_authenticateToPrivateKeyServer', function() { + var lookupPublicKeyStub, getDeviceSecretStub; + + beforeEach(function() { + lookupPublicKeyStub = sinon.stub(keychainDao, 'lookupPublicKey'); + getDeviceSecretStub = sinon.stub(keychainDao, 'getDeviceSecret'); + }); + afterEach(function() { + lookupPublicKeyStub.restore(); + getDeviceSecretStub.restore(); + }); + + it('should fail due to privkeyDao.requestAuthSessionKey', function(done) { + privkeyDaoStub.requestAuthSessionKey.withArgs({ + userId: testUser + }).yields(42); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.equal(42); + expect(authSessionKey).to.not.exist; + done(); + }); + }); + + it('should fail due to privkeyDao.requestAuthSessionKey response', function(done) { + privkeyDaoStub.requestAuthSessionKey.yields(null, {}); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.exist; + expect(authSessionKey).to.not.exist; + done(); + }); + }); + + it('should fail due to lookupPublicKey', function(done) { + privkeyDaoStub.requestAuthSessionKey.yields(null, { + encryptedAuthSessionKey: 'encryptedAuthSessionKey', + encryptedChallenge: 'encryptedChallenge', + sessionId: 'sessionId' + }); + + lookupPublicKeyStub.yields(42); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.exist; + expect(authSessionKey).to.not.exist; + done(); + }); + }); + + it('should fail due to pgp.decrypt', function(done) { + privkeyDaoStub.requestAuthSessionKey.yields(null, { + encryptedAuthSessionKey: 'encryptedAuthSessionKey', + encryptedChallenge: 'encryptedChallenge', + sessionId: 'sessionId' + }); + + lookupPublicKeyStub.yields(null, { + publickKey: 'publicKey' + }); + + pgpStub.decrypt.yields(42); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.exist; + expect(authSessionKey).to.not.exist; + done(); + }); + }); + + it('should fail due to getDeviceSecret', function(done) { + privkeyDaoStub.requestAuthSessionKey.yields(null, { + encryptedAuthSessionKey: 'encryptedAuthSessionKey', + encryptedChallenge: 'encryptedChallenge', + sessionId: 'sessionId' + }); + + lookupPublicKeyStub.yields(null, { + publickKey: 'publicKey' + }); + + pgpStub.decrypt.yields(null, 'decryptedStuff'); + getDeviceSecretStub.yields(42); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.exist; + expect(authSessionKey).to.not.exist; + done(); + }); + }); + + it('should fail due to crypto.encrypt', function(done) { + privkeyDaoStub.requestAuthSessionKey.yields(null, { + encryptedAuthSessionKey: 'encryptedAuthSessionKey', + encryptedChallenge: 'encryptedChallenge', + sessionId: 'sessionId' + }); + + lookupPublicKeyStub.yields(null, { + publickKey: 'publicKey' + }); + + pgpStub.decrypt.yields(null, 'decryptedStuff'); + getDeviceSecretStub.yields(null, 'deviceSecret'); + cryptoStub.encrypt.yields(42); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.exist; + expect(authSessionKey).to.not.exist; + done(); + }); + }); + + it('should fail due to privkeyDao.verifyAuthentication', function(done) { + privkeyDaoStub.requestAuthSessionKey.yields(null, { + encryptedAuthSessionKey: 'encryptedAuthSessionKey', + encryptedChallenge: 'encryptedChallenge', + sessionId: 'sessionId' + }); + + lookupPublicKeyStub.yields(null, { + publickKey: 'publicKey' + }); + + pgpStub.decrypt.yields(null, 'decryptedStuff', true, true); + getDeviceSecretStub.yields(null, 'deviceSecret'); + cryptoStub.encrypt.yields(null, 'encryptedStuff'); + privkeyDaoStub.verifyAuthentication.yields(42); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.exist; + expect(authSessionKey).to.not.exist; + done(); + }); + }); + + it('should fail due to server public key nto found', function(done) { + privkeyDaoStub.requestAuthSessionKey.yields(null, { + encryptedAuthSessionKey: 'encryptedAuthSessionKey', + encryptedChallenge: 'encryptedChallenge', + sessionId: 'sessionId' + }); + + lookupPublicKeyStub.yields(); + + pgpStub.decrypt.yields(null, 'decryptedStuff', true, true); + getDeviceSecretStub.yields(null, 'deviceSecret'); + cryptoStub.encrypt.yields(null, 'encryptedStuff'); + privkeyDaoStub.verifyAuthentication.yields(); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.exist; + expect(authSessionKey).to.not.exist; + done(); + }); + }); + + it('should work', function(done) { + privkeyDaoStub.requestAuthSessionKey.yields(null, { + encryptedAuthSessionKey: 'encryptedAuthSessionKey', + encryptedChallenge: 'encryptedChallenge', + sessionId: 'sessionId' + }); + + lookupPublicKeyStub.yields(null, { + publicKey: 'publicKey' + }); + + pgpStub.decrypt.yields(null, 'decryptedStuff', true, true); + getDeviceSecretStub.yields(null, 'deviceSecret'); + cryptoStub.encrypt.yields(null, 'encryptedStuff'); + privkeyDaoStub.verifyAuthentication.yields(); + + keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { + expect(err).to.not.exist; + expect(authSessionKey).to.deep.equal({ + sessionKey: 'decryptedStuff', sessionId: 'sessionId' }); - - lookupPublicKeyStub.yields(42); - - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.exist; - expect(authSessionKey).to.not.exist; - done(); - }); + done(); }); + }); + }); - it('should fail due to pgp.decrypt', function(done) { - privkeyDaoStub.requestAuthSessionKey.yields(null, { - encryptedAuthSessionKey: 'encryptedAuthSessionKey', - encryptedChallenge: 'encryptedChallenge', - sessionId: 'sessionId' - }); + describe('uploadPrivateKey', function() { + var getUserKeyPairStub, _authenticateToPrivateKeyServerStub; - lookupPublicKeyStub.yields(null, { - publickKey: 'publicKey' - }); + beforeEach(function() { + getUserKeyPairStub = sinon.stub(keychainDao, 'getUserKeyPair'); + _authenticateToPrivateKeyServerStub = sinon.stub(keychainDao, '_authenticateToPrivateKeyServer'); + }); + afterEach(function() { + getUserKeyPairStub.restore(); + _authenticateToPrivateKeyServerStub.restore(); + }); - pgpStub.decrypt.yields(42); - - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.exist; - expect(authSessionKey).to.not.exist; - done(); - }); - }); - - it('should fail due to getDeviceSecret', function(done) { - privkeyDaoStub.requestAuthSessionKey.yields(null, { - encryptedAuthSessionKey: 'encryptedAuthSessionKey', - encryptedChallenge: 'encryptedChallenge', - sessionId: 'sessionId' - }); - - lookupPublicKeyStub.yields(null, { - publickKey: 'publicKey' - }); - - pgpStub.decrypt.yields(null, 'decryptedStuff'); - getDeviceSecretStub.yields(42); - - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.exist; - expect(authSessionKey).to.not.exist; - done(); - }); - }); - - it('should fail due to crypto.encrypt', function(done) { - privkeyDaoStub.requestAuthSessionKey.yields(null, { - encryptedAuthSessionKey: 'encryptedAuthSessionKey', - encryptedChallenge: 'encryptedChallenge', - sessionId: 'sessionId' - }); - - lookupPublicKeyStub.yields(null, { - publickKey: 'publicKey' - }); - - pgpStub.decrypt.yields(null, 'decryptedStuff'); - getDeviceSecretStub.yields(null, 'deviceSecret'); - cryptoStub.encrypt.yields(42); - - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.exist; - expect(authSessionKey).to.not.exist; - done(); - }); - }); - - it('should fail due to privkeyDao.verifyAuthentication', function(done) { - privkeyDaoStub.requestAuthSessionKey.yields(null, { - encryptedAuthSessionKey: 'encryptedAuthSessionKey', - encryptedChallenge: 'encryptedChallenge', - sessionId: 'sessionId' - }); - - lookupPublicKeyStub.yields(null, { - publickKey: 'publicKey' - }); - - pgpStub.decrypt.yields(null, 'decryptedStuff', true, true); - getDeviceSecretStub.yields(null, 'deviceSecret'); - cryptoStub.encrypt.yields(null, 'encryptedStuff'); - privkeyDaoStub.verifyAuthentication.yields(42); - - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.exist; - expect(authSessionKey).to.not.exist; - done(); - }); - }); - - it('should fail due to server public key nto found', function(done) { - privkeyDaoStub.requestAuthSessionKey.yields(null, { - encryptedAuthSessionKey: 'encryptedAuthSessionKey', - encryptedChallenge: 'encryptedChallenge', - sessionId: 'sessionId' - }); - - lookupPublicKeyStub.yields(); - - pgpStub.decrypt.yields(null, 'decryptedStuff', true, true); - getDeviceSecretStub.yields(null, 'deviceSecret'); - cryptoStub.encrypt.yields(null, 'encryptedStuff'); - privkeyDaoStub.verifyAuthentication.yields(); - - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.exist; - expect(authSessionKey).to.not.exist; - done(); - }); - }); - - it('should work', function(done) { - privkeyDaoStub.requestAuthSessionKey.yields(null, { - encryptedAuthSessionKey: 'encryptedAuthSessionKey', - encryptedChallenge: 'encryptedChallenge', - sessionId: 'sessionId' - }); - - lookupPublicKeyStub.yields(null, { - publicKey: 'publicKey' - }); - - pgpStub.decrypt.yields(null, 'decryptedStuff', true, true); - getDeviceSecretStub.yields(null, 'deviceSecret'); - cryptoStub.encrypt.yields(null, 'encryptedStuff'); - privkeyDaoStub.verifyAuthentication.yields(); - - keychainDao._authenticateToPrivateKeyServer(testUser, function(err, authSessionKey) { - expect(err).to.not.exist; - expect(authSessionKey).to.deep.equal({ - sessionKey: 'decryptedStuff', - sessionId: 'sessionId' - }); - done(); - }); + it('should fail due to missing args', function(done) { + keychainDao.uploadPrivateKey({}, function(err) { + expect(err).to.exist; + done(); }); }); - describe('uploadPrivateKey', function() { - var getUserKeyPairStub, _authenticateToPrivateKeyServerStub; + it('should fail due to error in derive key', function(done) { + cryptoStub.deriveKey.yields(42); - beforeEach(function() { - getUserKeyPairStub = sinon.stub(keychainDao, 'getUserKeyPair'); - _authenticateToPrivateKeyServerStub = sinon.stub(keychainDao, '_authenticateToPrivateKeyServer'); - }); - afterEach(function() { - getUserKeyPairStub.restore(); - _authenticateToPrivateKeyServerStub.restore(); - }); - - it('should fail due to missing args', function(done) { - keychainDao.uploadPrivateKey({}, function(err) { - expect(err).to.exist; - done(); - }); - }); - - it('should fail due to error in derive key', function(done) { - cryptoStub.deriveKey.yields(42); - - keychainDao.uploadPrivateKey({ - code: 'code', - userId: testUser - }, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to error in getUserKeyPair', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - getUserKeyPairStub.yields(42); - - keychainDao.uploadPrivateKey({ - code: 'code', - userId: testUser - }, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(getUserKeyPairStub.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to error in crypto.encrypt', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - getUserKeyPairStub.yields(null, { - privateKey: { - _id: 'pgpKeyId', - encryptedKey: 'pgpKey' - } - }); - cryptoStub.encrypt.yields(42); - - keychainDao.uploadPrivateKey({ - code: 'code', - userId: testUser - }, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(getUserKeyPairStub.calledOnce).to.be.true; - expect(cryptoStub.encrypt.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to error in _authenticateToPrivateKeyServer', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - getUserKeyPairStub.yields(null, { - privateKey: { - _id: 'pgpKeyId', - encryptedKey: 'pgpKey' - } - }); - cryptoStub.encrypt.yields(null, 'encryptedPgpKey'); - _authenticateToPrivateKeyServerStub.yields(42); - - keychainDao.uploadPrivateKey({ - code: 'code', - userId: testUser - }, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(getUserKeyPairStub.calledOnce).to.be.true; - expect(cryptoStub.encrypt.calledOnce).to.be.true; - expect(_authenticateToPrivateKeyServerStub.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to error in cryptoStub.encrypt', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - getUserKeyPairStub.yields(null, { - privateKey: { - _id: 'pgpKeyId', - encryptedKey: 'pgpKey' - } - }); - cryptoStub.encrypt.withArgs('pgpKey').yields(null, 'encryptedPgpKey'); - _authenticateToPrivateKeyServerStub.yields(null, { - sessionId: 'sessionId', - sessionKey: 'sessionKey' - }); - cryptoStub.encrypt.withArgs('encryptedPgpKey').yields(42); - - keychainDao.uploadPrivateKey({ - code: 'code', - userId: testUser - }, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(getUserKeyPairStub.calledOnce).to.be.true; - expect(cryptoStub.encrypt.calledTwice).to.be.true; - expect(_authenticateToPrivateKeyServerStub.calledOnce).to.be.true; - done(); - }); - }); - - it('should work', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - getUserKeyPairStub.yields(null, { - privateKey: { - _id: 'pgpKeyId', - encryptedKey: 'pgpKey' - } - }); - cryptoStub.encrypt.withArgs('pgpKey').yields(null, 'encryptedPgpKey'); - _authenticateToPrivateKeyServerStub.yields(null, { - sessionId: 'sessionId', - sessionKey: 'sessionKey' - }); - cryptoStub.encrypt.withArgs('encryptedPgpKey').yields(null, 'doubleEncryptedPgpKey'); - privkeyDaoStub.upload.yields(); - - keychainDao.uploadPrivateKey({ - code: 'code', - userId: testUser - }, function(err) { - expect(err).to.not.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(getUserKeyPairStub.calledOnce).to.be.true; - expect(cryptoStub.encrypt.calledTwice).to.be.true; - expect(_authenticateToPrivateKeyServerStub.calledOnce).to.be.true; - expect(privkeyDaoStub.upload.calledOnce).to.be.true; - done(); - }); + keychainDao.uploadPrivateKey({ + code: 'code', + userId: testUser + }, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + done(); }); }); - describe('requestPrivateKeyDownload', function() { - it('should work', function(done) { - var options = { - userId: testUser, - keyId: 'someId' - }; + it('should fail due to error in getUserKeyPair', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + getUserKeyPairStub.yields(42); - privkeyDaoStub.requestDownload.withArgs(options).yields(); - keychainDao.requestPrivateKeyDownload(options, done); + keychainDao.uploadPrivateKey({ + code: 'code', + userId: testUser + }, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(getUserKeyPairStub.calledOnce).to.be.true; + done(); }); }); - describe('hasPrivateKey', function() { - it('should work', function(done) { - var options = { - userId: testUser, - keyId: 'someId' - }; + it('should fail due to error in crypto.encrypt', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + getUserKeyPairStub.yields(null, { + privateKey: { + _id: 'pgpKeyId', + encryptedKey: 'pgpKey' + } + }); + cryptoStub.encrypt.yields(42); - privkeyDaoStub.hasPrivateKey.withArgs(options).yields(); - keychainDao.hasPrivateKey(options, done); + keychainDao.uploadPrivateKey({ + code: 'code', + userId: testUser + }, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(getUserKeyPairStub.calledOnce).to.be.true; + expect(cryptoStub.encrypt.calledOnce).to.be.true; + done(); }); }); - describe('downloadPrivateKey', function() { - it('should work', function(done) { - var options = { - recoveryToken: 'token' - }; + it('should fail due to error in _authenticateToPrivateKeyServer', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + getUserKeyPairStub.yields(null, { + privateKey: { + _id: 'pgpKeyId', + encryptedKey: 'pgpKey' + } + }); + cryptoStub.encrypt.yields(null, 'encryptedPgpKey'); + _authenticateToPrivateKeyServerStub.yields(42); - privkeyDaoStub.download.withArgs(options).yields(); - keychainDao.downloadPrivateKey(options, done); + keychainDao.uploadPrivateKey({ + code: 'code', + userId: testUser + }, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(getUserKeyPairStub.calledOnce).to.be.true; + expect(cryptoStub.encrypt.calledOnce).to.be.true; + expect(_authenticateToPrivateKeyServerStub.calledOnce).to.be.true; + done(); }); }); - describe('decryptAndStorePrivateKeyLocally', function() { - var saveLocalPrivateKeyStub, testData; + it('should fail due to error in cryptoStub.encrypt', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + getUserKeyPairStub.yields(null, { + privateKey: { + _id: 'pgpKeyId', + encryptedKey: 'pgpKey' + } + }); + cryptoStub.encrypt.withArgs('pgpKey').yields(null, 'encryptedPgpKey'); + _authenticateToPrivateKeyServerStub.yields(null, { + sessionId: 'sessionId', + sessionKey: 'sessionKey' + }); + cryptoStub.encrypt.withArgs('encryptedPgpKey').yields(42); - beforeEach(function() { - testData = { + keychainDao.uploadPrivateKey({ + code: 'code', + userId: testUser + }, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(getUserKeyPairStub.calledOnce).to.be.true; + expect(cryptoStub.encrypt.calledTwice).to.be.true; + expect(_authenticateToPrivateKeyServerStub.calledOnce).to.be.true; + done(); + }); + }); + + it('should work', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + getUserKeyPairStub.yields(null, { + privateKey: { + _id: 'pgpKeyId', + encryptedKey: 'pgpKey' + } + }); + cryptoStub.encrypt.withArgs('pgpKey').yields(null, 'encryptedPgpKey'); + _authenticateToPrivateKeyServerStub.yields(null, { + sessionId: 'sessionId', + sessionKey: 'sessionKey' + }); + cryptoStub.encrypt.withArgs('encryptedPgpKey').yields(null, 'doubleEncryptedPgpKey'); + privkeyDaoStub.upload.yields(); + + keychainDao.uploadPrivateKey({ + code: 'code', + userId: testUser + }, function(err) { + expect(err).to.not.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(getUserKeyPairStub.calledOnce).to.be.true; + expect(cryptoStub.encrypt.calledTwice).to.be.true; + expect(_authenticateToPrivateKeyServerStub.calledOnce).to.be.true; + expect(privkeyDaoStub.upload.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('requestPrivateKeyDownload', function() { + it('should work', function(done) { + var options = { + userId: testUser, + keyId: 'someId' + }; + + privkeyDaoStub.requestDownload.withArgs(options).yields(); + keychainDao.requestPrivateKeyDownload(options, done); + }); + }); + + describe('hasPrivateKey', function() { + it('should work', function(done) { + var options = { + userId: testUser, + keyId: 'someId' + }; + + privkeyDaoStub.hasPrivateKey.withArgs(options).yields(); + keychainDao.hasPrivateKey(options, done); + }); + }); + + describe('downloadPrivateKey', function() { + it('should work', function(done) { + var options = { + recoveryToken: 'token' + }; + + privkeyDaoStub.download.withArgs(options).yields(); + keychainDao.downloadPrivateKey(options, done); + }); + }); + + describe('decryptAndStorePrivateKeyLocally', function() { + var saveLocalPrivateKeyStub, testData; + + beforeEach(function() { + testData = { + _id: 'keyId', + userId: testUser, + encryptedPrivateKey: 'encryptedPrivateKey', + code: 'code', + salt: 'salt', + iv: 'iv' + }; + + saveLocalPrivateKeyStub = sinon.stub(keychainDao, 'saveLocalPrivateKey'); + }); + afterEach(function() { + saveLocalPrivateKeyStub.restore(); + }); + + it('should fail due to invlaid args', function(done) { + keychainDao.decryptAndStorePrivateKeyLocally({}, function(err) { + expect(err).to.exist; + done(); + }); + }); + + it('should fail due to crypto.deriveKey', function(done) { + cryptoStub.deriveKey.yields(42); + + keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + done(); + }); + }); + + it('should fail due to crypto.decrypt', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + cryptoStub.decrypt.yields(42); + + keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(cryptoStub.decrypt.calledOnce).to.be.true; + done(); + }); + }); + + it('should fail due to pgp.getKeyParams', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + cryptoStub.decrypt.yields(null, 'privateKeyArmored'); + pgpStub.getKeyParams.throws(new Error()); + + keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(cryptoStub.decrypt.calledOnce).to.be.true; + expect(pgpStub.getKeyParams.calledOnce).to.be.true; + done(); + }); + }); + + it('should fail due to saveLocalPrivateKey', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + cryptoStub.decrypt.yields(null, 'privateKeyArmored'); + pgpStub.getKeyParams.returns(testData); + saveLocalPrivateKeyStub.yields(42); + + keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err) { + expect(err).to.exist; + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(cryptoStub.decrypt.calledOnce).to.be.true; + expect(pgpStub.getKeyParams.calledOnce).to.be.true; + expect(saveLocalPrivateKeyStub.calledOnce).to.be.true; + done(); + }); + }); + + it('should work', function(done) { + cryptoStub.deriveKey.yields(null, 'derivedKey'); + cryptoStub.decrypt.yields(null, 'privateKeyArmored'); + pgpStub.getKeyParams.returns(testData); + saveLocalPrivateKeyStub.yields(); + + keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err, keyObject) { + expect(err).to.not.exist; + expect(keyObject).to.deep.equal({ _id: 'keyId', userId: testUser, - encryptedPrivateKey: 'encryptedPrivateKey', - code: 'code', - salt: 'salt', - iv: 'iv' - }; - - saveLocalPrivateKeyStub = sinon.stub(keychainDao, 'saveLocalPrivateKey'); - }); - afterEach(function() { - saveLocalPrivateKeyStub.restore(); - }); - - it('should fail due to invlaid args', function(done) { - keychainDao.decryptAndStorePrivateKeyLocally({}, function(err) { - expect(err).to.exist; - done(); + encryptedKey: 'privateKeyArmored' }); + expect(cryptoStub.deriveKey.calledOnce).to.be.true; + expect(cryptoStub.decrypt.calledOnce).to.be.true; + expect(pgpStub.getKeyParams.calledOnce).to.be.true; + expect(saveLocalPrivateKeyStub.calledOnce).to.be.true; + + done(); }); + }); + }); - it('should fail due to crypto.deriveKey', function(done) { - cryptoStub.deriveKey.yields(42); + describe('put user keypair', function() { + it('should fail', function(done) { + var keypair = { + publicKey: { + _id: '12345', + userId: testUser, + publicKey: 'asdf' + }, + privateKey: { + _id: '12345', + encryptedKey: 'qwer' + } + }; - keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to crypto.decrypt', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - cryptoStub.decrypt.yields(42); - - keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(cryptoStub.decrypt.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to pgp.getKeyParams', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - cryptoStub.decrypt.yields(null, 'privateKeyArmored'); - pgpStub.getKeyParams.throws(new Error()); - - keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(cryptoStub.decrypt.calledOnce).to.be.true; - expect(pgpStub.getKeyParams.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail due to saveLocalPrivateKey', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - cryptoStub.decrypt.yields(null, 'privateKeyArmored'); - pgpStub.getKeyParams.returns(testData); - saveLocalPrivateKeyStub.yields(42); - - keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err) { - expect(err).to.exist; - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(cryptoStub.decrypt.calledOnce).to.be.true; - expect(pgpStub.getKeyParams.calledOnce).to.be.true; - expect(saveLocalPrivateKeyStub.calledOnce).to.be.true; - done(); - }); - }); - - it('should work', function(done) { - cryptoStub.deriveKey.yields(null, 'derivedKey'); - cryptoStub.decrypt.yields(null, 'privateKeyArmored'); - pgpStub.getKeyParams.returns(testData); - saveLocalPrivateKeyStub.yields(); - - keychainDao.decryptAndStorePrivateKeyLocally(testData, function(err, keyObject) { - expect(err).to.not.exist; - expect(keyObject).to.deep.equal({ - _id: 'keyId', - userId: testUser, - encryptedKey: 'privateKeyArmored' - }); - expect(cryptoStub.deriveKey.calledOnce).to.be.true; - expect(cryptoStub.decrypt.calledOnce).to.be.true; - expect(pgpStub.getKeyParams.calledOnce).to.be.true; - expect(saveLocalPrivateKeyStub.calledOnce).to.be.true; - - done(); - }); + keychainDao.putUserKeyPair(keypair, function(err) { + expect(err).to.exist; + done(); }); }); - describe('put user keypair', function() { - it('should fail', function(done) { - var keypair = { - publicKey: { - _id: '12345', - userId: testUser, - publicKey: 'asdf' - }, - privateKey: { - _id: '12345', - encryptedKey: 'qwer' - } - }; + it('should work', function(done) { + var keypair = { + publicKey: { + _id: '12345', + userId: testUser, + publicKey: 'asdf' + }, + privateKey: { + _id: '12345', + userId: testUser, + encryptedKey: 'qwer' + } + }; - keychainDao.putUserKeyPair(keypair, function(err) { - expect(err).to.exist; - done(); - }); - }); + lawnchairDaoStub.persist.yields(); + pubkeyDaoStub.put.yields(); - it('should work', function(done) { - var keypair = { - publicKey: { - _id: '12345', - userId: testUser, - publicKey: 'asdf' - }, - privateKey: { - _id: '12345', - userId: testUser, - encryptedKey: 'qwer' - } - }; - - lawnchairDaoStub.persist.yields(); - pubkeyDaoStub.put.yields(); - - keychainDao.putUserKeyPair(keypair, function(err) { - expect(err).to.not.exist; - expect(lawnchairDaoStub.persist.calledTwice).to.be.true; - expect(pubkeyDaoStub.put.calledOnce).to.be.true; - done(); - }); + keychainDao.putUserKeyPair(keypair, function(err) { + expect(err).to.not.exist; + expect(lawnchairDaoStub.persist.calledTwice).to.be.true; + expect(pubkeyDaoStub.put.calledOnce).to.be.true; + done(); }); }); - }); }); \ No newline at end of file diff --git a/test/unit/lawnchair-dao-test.js b/test/unit/lawnchair-dao-test.js index fd59c46..5eb3d5f 100644 --- a/test/unit/lawnchair-dao-test.js +++ b/test/unit/lawnchair-dao-test.js @@ -1,152 +1,148 @@ -define(function(require) { - 'use strict'; +'use strict'; - var LawnchairDAO = require('js/dao/lawnchair-dao'), - expect = chai.expect; +var LawnchairDAO = require('../../src/js/dao/lawnchair-dao'); - var dbName = 'lawnchair@test.com'; +var dbName = 'lawnchair@test.com'; - var key = 'type_1'; - var data = { - name: 'testName1', - type: 'testType1' - }; +var key = 'type_1'; +var data = { + name: 'testName1', + type: 'testType1' +}; - var key2 = 'type_2'; - var data2 = { - name: 'testName2', - type: 'testType2' - }; +var key2 = 'type_2'; +var data2 = { + name: 'testName2', + type: 'testType2' +}; - describe('Lawnchair DAO unit tests', function() { - var lawnchairDao; +describe('Lawnchair DAO unit tests', function() { + var lawnchairDao; - beforeEach(function(done) { - lawnchairDao = new LawnchairDAO(); - lawnchairDao.init(dbName, function(err) { - expect(err).to.not.exist; - expect(lawnchairDao._db).to.exist; + beforeEach(function(done) { + lawnchairDao = new LawnchairDAO(); + lawnchairDao.init(dbName, function(err) { + expect(err).to.not.exist; + expect(lawnchairDao._db).to.exist; + done(); + }); + }); + + afterEach(function(done) { + lawnchairDao.clear(function(err) { + expect(err).to.not.exist; + done(); + }); + }); + + describe('read', function() { + it('should fail', function(done) { + lawnchairDao.read(undefined, function(err) { + expect(err).to.exist; + done(); + }); + }); + }); + + describe('list', function() { + it('should fail', function(done) { + lawnchairDao.list(undefined, 0, null, function(err) { + expect(err).to.exist; + done(); + }); + }); + }); + + describe('remove list', function() { + it('should fail', function(done) { + lawnchairDao.removeList(undefined, function(err) { + expect(err).to.exist; + done(); + }); + }); + }); + + describe('persist/read/remove', function() { + it('should fail', function(done) { + lawnchairDao.persist(undefined, data, function(err) { + expect(err).to.exist; + done(); + }); + }); + it('should fail', function(done) { + lawnchairDao.persist('1234', undefined, function(err) { + expect(err).to.exist; done(); }); }); - afterEach(function(done) { - lawnchairDao.clear(function(err) { + it('should work', function(done) { + lawnchairDao.persist(key, data, function(err) { expect(err).to.not.exist; + lawnchairDao.read(key, onRead); + }); + + function onRead(err, fetched) { + expect(err).to.not.exist; + expect(fetched).to.deep.equal(data); + lawnchairDao.remove(key, onRemove); + } + + function onRemove(err) { + expect(err).to.not.exist; + lawnchairDao.read(key, onReadAgain); + } + + function onReadAgain(err, fetched) { + expect(err).to.not.exist; + expect(fetched).to.not.exist; + done(); + } + }); + }); + + describe('batch/list/removeList', function() { + it('should fails', function(done) { + lawnchairDao.batch({}, function(err) { + expect(err).to.exist; done(); }); }); - describe('read', function() { - it('should fail', function(done) { - lawnchairDao.read(undefined, function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + var list = [{ + key: key, + object: data + }, { + key: key2, + object: data2 + }]; + + lawnchairDao.batch(list, function(err) { + expect(err).to.not.exist; + lawnchairDao.list('type', 0, null, onList); }); + + function onList(err, fetched) { + expect(err).to.not.exist; + expect(fetched.length).to.equal(2); + expect(fetched[0]).to.deep.equal(list[0].object); + lawnchairDao.removeList('type', onRemoveList); + } + + function onRemoveList(err) { + expect(err).to.not.exist; + lawnchairDao.list('type', 0, null, onListAgain); + } + + function onListAgain(err, fetched) { + expect(err).to.not.exist; + expect(fetched).to.exist; + expect(fetched.length).to.equal(0); + done(); + } }); - - describe('list', function() { - it('should fail', function(done) { - lawnchairDao.list(undefined, 0, null, function(err) { - expect(err).to.exist; - done(); - }); - }); - }); - - describe('remove list', function() { - it('should fail', function(done) { - lawnchairDao.removeList(undefined, function(err) { - expect(err).to.exist; - done(); - }); - }); - }); - - describe('persist/read/remove', function() { - it('should fail', function(done) { - lawnchairDao.persist(undefined, data, function(err) { - expect(err).to.exist; - done(); - }); - }); - it('should fail', function(done) { - lawnchairDao.persist('1234', undefined, function(err) { - expect(err).to.exist; - done(); - }); - }); - - it('should work', function(done) { - lawnchairDao.persist(key, data, function(err) { - expect(err).to.not.exist; - lawnchairDao.read(key, onRead); - }); - - function onRead(err, fetched) { - expect(err).to.not.exist; - expect(fetched).to.deep.equal(data); - lawnchairDao.remove(key, onRemove); - } - - function onRemove(err) { - expect(err).to.not.exist; - lawnchairDao.read(key, onReadAgain); - } - - function onReadAgain(err, fetched) { - expect(err).to.not.exist; - expect(fetched).to.not.exist; - done(); - } - }); - }); - - describe('batch/list/removeList', function() { - it('should fails', function(done) { - lawnchairDao.batch({}, function(err) { - expect(err).to.exist; - done(); - }); - }); - - it('should work', function(done) { - var list = [{ - key: key, - object: data - }, { - key: key2, - object: data2 - }]; - - lawnchairDao.batch(list, function(err) { - expect(err).to.not.exist; - lawnchairDao.list('type', 0, null, onList); - }); - - function onList(err, fetched) { - expect(err).to.not.exist; - expect(fetched.length).to.equal(2); - expect(fetched[0]).to.deep.equal(list[0].object); - lawnchairDao.removeList('type', onRemoveList); - } - - function onRemoveList(err) { - expect(err).to.not.exist; - lawnchairDao.list('type', 0, null, onListAgain); - } - - function onListAgain(err, fetched) { - expect(err).to.not.exist; - expect(fetched).to.exist; - expect(fetched.length).to.equal(0); - done(); - } - }); - }); - }); }); \ No newline at end of file diff --git a/test/unit/login-ctrl-test.js b/test/unit/login-ctrl-test.js index 1a790de..65ad8aa 100644 --- a/test/unit/login-ctrl-test.js +++ b/test/unit/login-ctrl-test.js @@ -1,236 +1,232 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - LoginCtrl = require('js/controller/login'), - EmailDAO = require('js/dao/email-dao'), - Auth = require('js/bo/auth'), - appController = require('js/app-controller'), - KeychainDAO = require('js/dao/keychain-dao'); +var mocks = angular.mocks, + LoginCtrl = require('../../src/js/controller/login'), + EmailDAO = require('../../src/js/dao/email-dao'), + Auth = require('../../src/js/bo/auth'), + appController = require('../../src/js/app-controller'), + KeychainDAO = require('../../src/js/dao/keychain-dao'); - describe('Login Controller unit test', function() { - var scope, location, ctrl, - origEmailDao, emailDaoMock, - origKeychain, keychainMock, - origAuth, authStub, - emailAddress = 'fred@foo.com', - startAppStub, - checkForUpdateStub, - initStub; +describe('Login Controller unit test', function() { + var scope, location, ctrl, + origEmailDao, emailDaoMock, + origKeychain, keychainMock, + origAuth, authStub, + emailAddress = 'fred@foo.com', + startAppStub, + checkForUpdateStub, + initStub; - describe('initialization', function() { - var hasChrome, hasIdentity; + describe('initialization', function() { + var hasChrome, hasIdentity; - beforeEach(function() { - hasChrome = !!window.chrome; - hasIdentity = !!window.chrome.identity; - window.chrome = window.chrome || {}; - window.chrome.identity = window.chrome.identity || {}; + beforeEach(function() { + hasChrome = !!window.chrome; + hasIdentity = !!window.chrome.identity; + window.chrome = window.chrome || {}; + window.chrome.identity = window.chrome.identity || {}; - // remember original module to restore later, then replace it - origEmailDao = appController._emailDao; - origKeychain = appController._keychain; - origAuth = appController._auth; - appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO); - appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); - appController._auth = authStub = sinon.createStubInstance(Auth); + // remember original module to restore later, then replace it + origEmailDao = appController._emailDao; + origKeychain = appController._keychain; + origAuth = appController._auth; + appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO); + appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); + appController._auth = authStub = sinon.createStubInstance(Auth); - startAppStub = sinon.stub(appController, 'start'); - checkForUpdateStub = sinon.stub(appController, 'checkForUpdate'); - initStub = sinon.stub(appController, 'init'); + startAppStub = sinon.stub(appController, 'start'); + checkForUpdateStub = sinon.stub(appController, 'checkForUpdate'); + initStub = sinon.stub(appController, 'init'); + }); + + afterEach(function() { + // restore the browser + if (!hasIdentity) { + delete window.chrome.identity; + } + + if (!hasChrome) { + delete window.chrome; + } + + // restore the app controller module + appController._emailDao = origEmailDao; + appController._keychain = origKeychain; + appController._auth = origAuth; + appController.start.restore && appController.start.restore(); + appController.checkForUpdate.restore && appController.checkForUpdate.restore(); + appController.init.restore && appController.init.restore(); + location.path.restore && location.path.restore(); + + startAppStub.restore(); + checkForUpdateStub.restore(); + initStub.restore(); + }); + + it('should forward directly to desktop for empty passphrase', function(done) { + var testKeys = { + privateKey: 'a', + publicKey: 'b' + }; + + startAppStub.yields(); + authStub.getEmailAddress.yields(null, { + emailAddress: emailAddress, + realname: 'asd' }); + initStub.yields(null, testKeys); - afterEach(function() { - // restore the browser - if (!hasIdentity) { - delete window.chrome.identity; - } + emailDaoMock.unlock.withArgs({ + keypair: testKeys, + passphrase: undefined + }).yields(); - if (!hasChrome) { - delete window.chrome; - } - - // restore the app controller module - appController._emailDao = origEmailDao; - appController._keychain = origKeychain; - appController._auth = origAuth; - appController.start.restore && appController.start.restore(); - appController.checkForUpdate.restore && appController.checkForUpdate.restore(); - appController.init.restore && appController.init.restore(); - location.path.restore && location.path.restore(); - - startAppStub.restore(); - checkForUpdateStub.restore(); - initStub.restore(); - }); - - it('should forward directly to desktop for empty passphrase', function(done) { - var testKeys = { - privateKey: 'a', - publicKey: 'b' - }; - - startAppStub.yields(); - authStub.getEmailAddress.yields(null, { - emailAddress: emailAddress, - realname: 'asd' + angular.module('logintest', []); + mocks.module('logintest'); + mocks.inject(function($controller, $rootScope, $location) { + location = $location; + sinon.stub(location, 'path', function(path) { + expect(path).to.equal('/desktop'); + expect(startAppStub.calledOnce).to.be.true; + expect(checkForUpdateStub.calledOnce).to.be.true; + expect(authStub.getEmailAddress.calledOnce).to.be.true; + done(); }); - initStub.yields(null, testKeys); - - emailDaoMock.unlock.withArgs({ - keypair: testKeys, - passphrase: undefined - }).yields(); - - angular.module('logintest', []); - mocks.module('logintest'); - mocks.inject(function($controller, $rootScope, $location) { - location = $location; - sinon.stub(location, 'path', function(path) { - expect(path).to.equal('/desktop'); - expect(startAppStub.calledOnce).to.be.true; - expect(checkForUpdateStub.calledOnce).to.be.true; - expect(authStub.getEmailAddress.calledOnce).to.be.true; - done(); - }); - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(LoginCtrl, { - $location: location, - $scope: scope - }); + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(LoginCtrl, { + $location: location, + $scope: scope }); }); + }); - it('should forward to existing user login', function(done) { - var testKeys = { - privateKey: 'a', - publicKey: 'b' - }; + it('should forward to existing user login', function(done) { + var testKeys = { + privateKey: 'a', + publicKey: 'b' + }; - startAppStub.yields(); - authStub.getEmailAddress.yields(null, { - emailAddress: emailAddress, - realname: 'asd' + startAppStub.yields(); + authStub.getEmailAddress.yields(null, { + emailAddress: emailAddress, + realname: 'asd' + }); + initStub.yields(null, testKeys); + + emailDaoMock.unlock.withArgs({ + keypair: testKeys, + passphrase: undefined + }).yields({}); + + angular.module('logintest', []); + mocks.module('logintest'); + mocks.inject(function($controller, $rootScope, $location) { + location = $location; + sinon.stub(location, 'path', function(path) { + expect(path).to.equal('/login-existing'); + expect(startAppStub.calledOnce).to.be.true; + expect(checkForUpdateStub.calledOnce).to.be.true; + expect(authStub.getEmailAddress.calledOnce).to.be.true; + done(); }); - initStub.yields(null, testKeys); - - emailDaoMock.unlock.withArgs({ - keypair: testKeys, - passphrase: undefined - }).yields({}); - - angular.module('logintest', []); - mocks.module('logintest'); - mocks.inject(function($controller, $rootScope, $location) { - location = $location; - sinon.stub(location, 'path', function(path) { - expect(path).to.equal('/login-existing'); - expect(startAppStub.calledOnce).to.be.true; - expect(checkForUpdateStub.calledOnce).to.be.true; - expect(authStub.getEmailAddress.calledOnce).to.be.true; - done(); - }); - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(LoginCtrl, { - $location: location, - $scope: scope - }); + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(LoginCtrl, { + $location: location, + $scope: scope }); }); + }); - it('should forward to privatekey download login', function(done) { - startAppStub.yields(); - authStub.getEmailAddress.yields(null, { - emailAddress: emailAddress, - realname: 'asd' - }); - initStub.yields(null, { - publicKey: 'b' - }); - keychainMock.requestPrivateKeyDownload.yields(null, {}); + it('should forward to privatekey download login', function(done) { + startAppStub.yields(); + authStub.getEmailAddress.yields(null, { + emailAddress: emailAddress, + realname: 'asd' + }); + initStub.yields(null, { + publicKey: 'b' + }); + keychainMock.requestPrivateKeyDownload.yields(null, {}); - angular.module('logintest', []); - mocks.module('logintest'); - mocks.inject(function($controller, $rootScope, $location) { - location = $location; - sinon.stub(location, 'path', function(path) { - expect(path).to.equal('/login-privatekey-download'); - expect(startAppStub.calledOnce).to.be.true; - expect(checkForUpdateStub.calledOnce).to.be.true; - expect(authStub.getEmailAddress.calledOnce).to.be.true; - expect(keychainMock.requestPrivateKeyDownload.calledOnce).to.be.true; - done(); - }); - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(LoginCtrl, { - $location: location, - $scope: scope - }); + angular.module('logintest', []); + mocks.module('logintest'); + mocks.inject(function($controller, $rootScope, $location) { + location = $location; + sinon.stub(location, 'path', function(path) { + expect(path).to.equal('/login-privatekey-download'); + expect(startAppStub.calledOnce).to.be.true; + expect(checkForUpdateStub.calledOnce).to.be.true; + expect(authStub.getEmailAddress.calledOnce).to.be.true; + expect(keychainMock.requestPrivateKeyDownload.calledOnce).to.be.true; + done(); + }); + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(LoginCtrl, { + $location: location, + $scope: scope }); }); + }); - it('should forward to new device login', function(done) { - startAppStub.yields(); - authStub.getEmailAddress.yields(null, { - emailAddress: emailAddress, - realname: 'asd' - }); - initStub.yields(null, { - publicKey: 'b' - }); - keychainMock.requestPrivateKeyDownload.yields(); + it('should forward to new device login', function(done) { + startAppStub.yields(); + authStub.getEmailAddress.yields(null, { + emailAddress: emailAddress, + realname: 'asd' + }); + initStub.yields(null, { + publicKey: 'b' + }); + keychainMock.requestPrivateKeyDownload.yields(); - angular.module('logintest', []); - mocks.module('logintest'); - mocks.inject(function($controller, $rootScope, $location) { - location = $location; - sinon.stub(location, 'path', function(path) { - expect(path).to.equal('/login-new-device'); - expect(startAppStub.calledOnce).to.be.true; - expect(checkForUpdateStub.calledOnce).to.be.true; - expect(authStub.getEmailAddress.calledOnce).to.be.true; - expect(keychainMock.requestPrivateKeyDownload.calledOnce).to.be.true; - done(); - }); - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(LoginCtrl, { - $location: location, - $scope: scope - }); + angular.module('logintest', []); + mocks.module('logintest'); + mocks.inject(function($controller, $rootScope, $location) { + location = $location; + sinon.stub(location, 'path', function(path) { + expect(path).to.equal('/login-new-device'); + expect(startAppStub.calledOnce).to.be.true; + expect(checkForUpdateStub.calledOnce).to.be.true; + expect(authStub.getEmailAddress.calledOnce).to.be.true; + expect(keychainMock.requestPrivateKeyDownload.calledOnce).to.be.true; + done(); + }); + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(LoginCtrl, { + $location: location, + $scope: scope }); }); + }); - it('should forward to initial login', function(done) { - startAppStub.yields(); - authStub.getEmailAddress.yields(null, { - emailAddress: emailAddress, - realname: 'asd' + it('should forward to initial login', function(done) { + startAppStub.yields(); + authStub.getEmailAddress.yields(null, { + emailAddress: emailAddress, + realname: 'asd' + }); + initStub.yields(); + + angular.module('logintest', []); + mocks.module('logintest'); + mocks.inject(function($controller, $rootScope, $location) { + location = $location; + sinon.stub(location, 'path', function(path) { + expect(path).to.equal('/login-initial'); + expect(startAppStub.calledOnce).to.be.true; + expect(checkForUpdateStub.calledOnce).to.be.true; + expect(authStub.getEmailAddress.calledOnce).to.be.true; + done(); }); - initStub.yields(); - - angular.module('logintest', []); - mocks.module('logintest'); - mocks.inject(function($controller, $rootScope, $location) { - location = $location; - sinon.stub(location, 'path', function(path) { - expect(path).to.equal('/login-initial'); - expect(startAppStub.calledOnce).to.be.true; - expect(checkForUpdateStub.calledOnce).to.be.true; - expect(authStub.getEmailAddress.calledOnce).to.be.true; - done(); - }); - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(LoginCtrl, { - $location: location, - $scope: scope - }); + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(LoginCtrl, { + $location: location, + $scope: scope }); }); }); diff --git a/test/unit/login-existing-ctrl-test.js b/test/unit/login-existing-ctrl-test.js index baa16e0..70843cb 100644 --- a/test/unit/login-existing-ctrl-test.js +++ b/test/unit/login-existing-ctrl-test.js @@ -1,116 +1,112 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - Auth = require('js/bo/auth'), - mocks = require('angularMocks'), - LoginExistingCtrl = require('js/controller/login-existing'), - EmailDAO = require('js/dao/email-dao'), - KeychainDAO = require('js/dao/keychain-dao'), - appController = require('js/app-controller'); +var Auth = require('../../src/js/bo/auth'), + mocks = angular.mocks, + LoginExistingCtrl = require('../../src/js/controller/login-existing'), + EmailDAO = require('../../src/js/dao/email-dao'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + appController = require('../../src/js/app-controller'); - describe('Login (existing user) Controller unit test', function() { - var scope, location, ctrl, origEmailDao, emailDaoMock, - origAuth, authMock, - emailAddress = 'fred@foo.com', - passphrase = 'asd', - keychainMock; +describe('Login (existing user) Controller unit test', function() { + var scope, location, ctrl, origEmailDao, emailDaoMock, + origAuth, authMock, + emailAddress = 'fred@foo.com', + passphrase = 'asd', + keychainMock; - beforeEach(function() { - // remember original module to restore later - origEmailDao = appController._emailDao; - origAuth = appController._auth; + beforeEach(function() { + // remember original module to restore later + origEmailDao = appController._emailDao; + origAuth = appController._auth; - appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO); - appController._auth = authMock = sinon.createStubInstance(Auth); + appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO); + appController._auth = authMock = sinon.createStubInstance(Auth); - keychainMock = sinon.createStubInstance(KeychainDAO); - emailDaoMock._keychain = keychainMock; + keychainMock = sinon.createStubInstance(KeychainDAO); + emailDaoMock._keychain = keychainMock; - emailDaoMock._account = { - emailAddress: emailAddress, - }; + emailDaoMock._account = { + emailAddress: emailAddress, + }; - angular.module('loginexistingtest', []); - mocks.module('loginexistingtest'); - mocks.inject(function($rootScope, $controller, $location) { - location = $location; - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(LoginExistingCtrl, { - $scope: scope, - $routeParams: {} - }); + angular.module('loginexistingtest', []); + mocks.module('loginexistingtest'); + mocks.inject(function($rootScope, $controller, $location) { + location = $location; + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(LoginExistingCtrl, { + $scope: scope, + $routeParams: {} }); }); + }); - afterEach(function() { - // restore the module - appController._emailDao = origEmailDao; - appController._auth = origAuth; + afterEach(function() { + // restore the module + appController._emailDao = origEmailDao; + appController._auth = origAuth; + }); + + describe('initial state', function() { + it('should be well defined', function() { + expect(scope.buttonEnabled).to.be.true; + expect(scope.incorrect).to.be.false; + expect(scope.change).to.exist; + expect(scope.confirmPassphrase).to.exist; }); + }); - describe('initial state', function() { - it('should be well defined', function() { - expect(scope.buttonEnabled).to.be.true; + describe('functionality', function() { + describe('change', function() { + it('should set incorrect to false', function() { + scope.incorrect = true; + + scope.change(); expect(scope.incorrect).to.be.false; - expect(scope.change).to.exist; - expect(scope.confirmPassphrase).to.exist; }); }); - describe('functionality', function() { - describe('change', function() { - it('should set incorrect to false', function() { - scope.incorrect = true; + describe('confirm passphrase', function() { + it('should unlock crypto and start', function() { + var keypair = {}, + pathSpy = sinon.spy(location, 'path'); + scope.passphrase = passphrase; + keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, keypair); + emailDaoMock.unlock.withArgs({ + keypair: keypair, + passphrase: passphrase + }).yields(); + authMock.storeCredentials.yields(); - scope.change(); - expect(scope.incorrect).to.be.false; - }); + + scope.confirmPassphrase(); + + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + expect(emailDaoMock.unlock.calledOnce).to.be.true; + expect(pathSpy.calledOnce).to.be.true; + expect(pathSpy.calledWith('/desktop')).to.be.true; }); - describe('confirm passphrase', function() { - it('should unlock crypto and start', function() { - var keypair = {}, - pathSpy = sinon.spy(location, 'path'); - scope.passphrase = passphrase; - keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, keypair); - emailDaoMock.unlock.withArgs({ - keypair: keypair, - passphrase: passphrase - }).yields(); - authMock.storeCredentials.yields(); + it('should not do anything without passphrase', function() { + var pathSpy = sinon.spy(location, 'path'); + scope.passphrase = ''; + scope.confirmPassphrase(); + expect(pathSpy.callCount).to.equal(0); + }); - scope.confirmPassphrase(); + it('should not work when keypair unavailable', function(done) { + scope.passphrase = passphrase; + keychainMock.getUserKeyPair.withArgs(emailAddress).yields(new Error('asd')); + scope.onError = function(err) { + expect(err.message).to.equal('asd'); expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - expect(emailDaoMock.unlock.calledOnce).to.be.true; - expect(pathSpy.calledOnce).to.be.true; - expect(pathSpy.calledWith('/desktop')).to.be.true; - }); + done(); + }; - it('should not do anything without passphrase', function() { - var pathSpy = sinon.spy(location, 'path'); - scope.passphrase = ''; - - scope.confirmPassphrase(); - expect(pathSpy.callCount).to.equal(0); - }); - - it('should not work when keypair unavailable', function(done) { - scope.passphrase = passphrase; - keychainMock.getUserKeyPair.withArgs(emailAddress).yields(new Error('asd')); - - scope.onError = function(err) { - expect(err.message).to.equal('asd'); - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - done(); - }; - - scope.confirmPassphrase(); - }); + scope.confirmPassphrase(); }); }); }); diff --git a/test/unit/login-initial-ctrl-test.js b/test/unit/login-initial-ctrl-test.js index 533a1f4..17fdbfe 100644 --- a/test/unit/login-initial-ctrl-test.js +++ b/test/unit/login-initial-ctrl-test.js @@ -1,202 +1,197 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - Auth = require('js/bo/auth'), - mocks = require('angularMocks'), - LoginInitialCtrl = require('js/controller/login-initial'), - PGP = require('js/crypto/pgp'), - EmailDAO = require('js/dao/email-dao'), - appController = require('js/app-controller'); +var Auth = require('../../src/js/bo/auth'), + mocks = angular.mocks, + LoginInitialCtrl = require('../../src/js/controller/login-initial'), + PGP = require('../../src/js/crypto/pgp'), + EmailDAO = require('../../src/js/dao/email-dao'), + appController = require('../../src/js/app-controller'); - describe('Login (initial user) Controller unit test', function() { - var scope, ctrl, location, origEmailDao, emailDaoMock, - origAuth, authMock, - emailAddress = 'fred@foo.com', - keyId, expectedKeyId, - cryptoMock; +describe('Login (initial user) Controller unit test', function() { + var scope, ctrl, location, origEmailDao, emailDaoMock, + origAuth, authMock, + emailAddress = 'fred@foo.com', + keyId, expectedKeyId, + cryptoMock; + + beforeEach(function() { + // remember original module to restore later + origEmailDao = appController._emailDao; + origAuth = appController._auth; + + appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO); + appController._auth = authMock = sinon.createStubInstance(Auth); + + keyId = '9FEB47936E712926'; + expectedKeyId = '6E712926'; + cryptoMock = sinon.createStubInstance(PGP); + emailDaoMock._crypto = cryptoMock; + + emailDaoMock._account = { + emailAddress: emailAddress, + }; + + angular.module('logininitialtest', []); + mocks.module('logininitialtest'); + mocks.inject(function($rootScope, $controller, $location) { + scope = $rootScope.$new(); + location = $location; + scope.state = { + ui: {} + }; + ctrl = $controller(LoginInitialCtrl, { + $scope: scope, + $routeParams: {} + }); + }); + }); + + afterEach(function() { + // restore the module + appController._emailDao = origEmailDao; + appController._auth = origAuth; + }); + + describe('initial state', function() { + it('should be well defined', function() { + expect(scope.state.ui).to.equal(1); + }); + }); + + describe('signUpToNewsletter', function() { + var xhrMock, requests; beforeEach(function() { - // remember original module to restore later - origEmailDao = appController._emailDao; - origAuth = appController._auth; + xhrMock = sinon.useFakeXMLHttpRequest(); + requests = []; - appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO); - appController._auth = authMock = sinon.createStubInstance(Auth); - - keyId = '9FEB47936E712926'; - expectedKeyId = '6E712926'; - cryptoMock = sinon.createStubInstance(PGP); - emailDaoMock._crypto = cryptoMock; - - emailDaoMock._account = { - emailAddress: emailAddress, + xhrMock.onCreate = function(xhr) { + requests.push(xhr); }; - - angular.module('logininitialtest', []); - mocks.module('logininitialtest'); - mocks.inject(function($rootScope, $controller, $location) { - scope = $rootScope.$new(); - location = $location; - scope.state = { - ui: {} - }; - ctrl = $controller(LoginInitialCtrl, { - $scope: scope, - $routeParams: {} - }); - }); }); afterEach(function() { - // restore the module - appController._emailDao = origEmailDao; - appController._auth = origAuth; + xhrMock.restore(); }); - describe('initial state', function() { - it('should be well defined', function() { + it('should not signup', function() { + scope.state.newsletter = false; + + scope.signUpToNewsletter(); + expect(requests.length).to.equal(0); + }); + + it('should fail', function(done) { + scope.state.newsletter = true; + + scope.signUpToNewsletter(function(err, xhr) { + expect(err).to.exist; + expect(xhr).to.not.exist; + done(); + }); + + expect(requests.length).to.equal(1); + requests[0].onerror('err'); + }); + + it('should work without callback', function() { + scope.state.newsletter = true; + + scope.signUpToNewsletter(); + + expect(requests.length).to.equal(1); + requests[0].respond(200, { + "Content-Type": "text/plain" + }, 'foobar!'); + }); + }); + + describe('go to import key', function() { + var signUpToNewsletterStub; + beforeEach(function() { + signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter'); + }); + afterEach(function() { + signUpToNewsletterStub.restore(); + }); + + it('should not continue if terms are not accepted', function(done) { + scope.state.agree = undefined; + + scope.onError = function(err) { + expect(err.message).to.contain('Terms'); + expect(signUpToNewsletterStub.called).to.be.false; + done(); + }; + + scope.importKey(); + }); + + it('should work', function() { + scope.state.agree = true; + scope.importKey(); + expect(signUpToNewsletterStub.calledOnce).to.be.true; + expect(location.$$path).to.equal('/login-new-device'); + }); + }); + + describe('generate key', function() { + var signUpToNewsletterStub; + beforeEach(function() { + signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter'); + }); + afterEach(function() { + signUpToNewsletterStub.restore(); + }); + + it('should not continue if terms are not accepted', function(done) { + scope.state.agree = undefined; + + scope.onError = function(err) { + expect(err.message).to.contain('Terms'); expect(scope.state.ui).to.equal(1); - }); + expect(signUpToNewsletterStub.called).to.be.false; + done(); + }; + + scope.generateKey(); }); - describe('signUpToNewsletter', function() { - var xhrMock, requests; + it('should fail due to error in emailDao.unlock', function(done) { + scope.state.agree = true; - beforeEach(function() { - xhrMock = sinon.useFakeXMLHttpRequest(); - requests = []; + emailDaoMock.unlock.withArgs({ + passphrase: undefined + }).yields(new Error()); + authMock.storeCredentials.yields(); - xhrMock.onCreate = function(xhr) { - requests.push(xhr); - }; - }); + scope.onError = function(err) { + expect(err).to.exist; + expect(scope.state.ui).to.equal(1); + expect(signUpToNewsletterStub.called).to.be.true; + done(); + }; - afterEach(function() { - xhrMock.restore(); - }); - - it('should not signup', function() { - scope.state.newsletter = false; - - scope.signUpToNewsletter(); - expect(requests.length).to.equal(0); - }); - - it('should fail', function(done) { - scope.state.newsletter = true; - - scope.signUpToNewsletter(function(err, xhr) { - expect(err).to.exist; - expect(xhr).to.not.exist; - done(); - }); - - expect(requests.length).to.equal(1); - requests[0].onerror('err'); - }); - - it('should work without callback', function() { - scope.state.newsletter = true; - - scope.signUpToNewsletter(); - - expect(requests.length).to.equal(1); - requests[0].respond(200, { - "Content-Type": "text/plain" - }, 'foobar!'); - }); + scope.generateKey(); + expect(scope.state.ui).to.equal(2); }); - describe('go to import key', function() { - var signUpToNewsletterStub; - beforeEach(function() { - signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter'); - }); - afterEach(function() { - signUpToNewsletterStub.restore(); - }); + it('should unlock crypto', function(done) { + scope.state.agree = true; - it('should not continue if terms are not accepted', function(done) { - scope.state.agree = undefined; + emailDaoMock.unlock.withArgs({ + passphrase: undefined + }).yields(); + authMock.storeCredentials.yields(); - scope.onError = function(err) { - expect(err.message).to.contain('Terms'); - expect(signUpToNewsletterStub.called).to.be.false; - done(); - }; - - scope.importKey(); - }); - - it('should work', function() { - scope.state.agree = true; - scope.importKey(); - expect(signUpToNewsletterStub.calledOnce).to.be.true; - expect(location.$$path).to.equal('/login-new-device'); - }); - }); - - describe('generate key', function() { - var signUpToNewsletterStub; - beforeEach(function() { - signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter'); - }); - afterEach(function() { - signUpToNewsletterStub.restore(); - }); - - it('should not continue if terms are not accepted', function(done) { - scope.state.agree = undefined; - - scope.onError = function(err) { - expect(err.message).to.contain('Terms'); - expect(scope.state.ui).to.equal(1); - expect(signUpToNewsletterStub.called).to.be.false; - done(); - }; - - scope.generateKey(); - }); - - it('should fail due to error in emailDao.unlock', function(done) { - scope.state.agree = true; - - emailDaoMock.unlock.withArgs({ - passphrase: undefined - }).yields(new Error()); - authMock.storeCredentials.yields(); - - scope.onError = function(err) { - expect(err).to.exist; - expect(scope.state.ui).to.equal(1); - expect(signUpToNewsletterStub.called).to.be.true; - done(); - }; - - scope.generateKey(); + scope.$apply = function() { expect(scope.state.ui).to.equal(2); - }); + expect(location.$$path).to.equal('/desktop'); + expect(emailDaoMock.unlock.calledOnce).to.be.true; + done(); + }; - it('should unlock crypto', function(done) { - scope.state.agree = true; - - emailDaoMock.unlock.withArgs({ - passphrase: undefined - }).yields(); - authMock.storeCredentials.yields(); - - scope.$apply = function() { - expect(scope.state.ui).to.equal(2); - expect(location.$$path).to.equal('/desktop'); - expect(emailDaoMock.unlock.calledOnce).to.be.true; - done(); - }; - - scope.generateKey(); - }); + scope.generateKey(); }); - }); }); \ No newline at end of file diff --git a/test/unit/login-new-device-ctrl-test.js b/test/unit/login-new-device-ctrl-test.js index 977bedd..3577949 100644 --- a/test/unit/login-new-device-ctrl-test.js +++ b/test/unit/login-new-device-ctrl-test.js @@ -1,190 +1,186 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - PGP = require('js/crypto/pgp'), - LoginNewDeviceCtrl = require('js/controller/login-new-device'), - KeychainDAO = require('js/dao/keychain-dao'), - EmailDAO = require('js/dao/email-dao'), - appController = require('js/app-controller'); +var mocks = angular.mocks, + PGP = require('../../src/js/crypto/pgp'), + LoginNewDeviceCtrl = require('../../src/js/controller/login-new-device'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + EmailDAO = require('../../src/js/dao/email-dao'), + appController = require('../../src/js/app-controller'); - describe('Login (new device) Controller unit test', function() { - var scope, ctrl, origEmailDao, emailDaoMock, pgpMock, - emailAddress = 'fred@foo.com', - passphrase = 'asd', - keyId, - keychainMock; +describe('Login (new device) Controller unit test', function() { + var scope, ctrl, origEmailDao, emailDaoMock, pgpMock, + emailAddress = 'fred@foo.com', + passphrase = 'asd', + keyId, + keychainMock; - beforeEach(function() { - // remember original module to restore later - origEmailDao = appController._emailDao; + beforeEach(function() { + // remember original module to restore later + origEmailDao = appController._emailDao; - emailDaoMock = sinon.createStubInstance(EmailDAO); - appController._emailDao = emailDaoMock; + emailDaoMock = sinon.createStubInstance(EmailDAO); + appController._emailDao = emailDaoMock; - keyId = '9FEB47936E712926'; - emailDaoMock._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); - appController._pgp = pgpMock = sinon.createStubInstance(PGP); - pgpMock.extractPublicKey.returns('publicKeyArmored'); + keyId = '9FEB47936E712926'; + emailDaoMock._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); + appController._pgp = pgpMock = sinon.createStubInstance(PGP); + pgpMock.extractPublicKey.returns('publicKeyArmored'); - emailDaoMock._account = { - emailAddress: emailAddress, + emailDaoMock._account = { + emailAddress: emailAddress, + }; + + angular.module('loginnewdevicetest', []); + mocks.module('loginnewdevicetest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = { + ui: {} }; - - angular.module('loginnewdevicetest', []); - mocks.module('loginnewdevicetest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = { - ui: {} - }; - ctrl = $controller(LoginNewDeviceCtrl, { - $scope: scope, - $routeParams: {} - }); - }); - }); - - afterEach(function() { - // restore the module - appController._emailDao = origEmailDao; - }); - - describe('initial state', function() { - it('should be well defined', function() { - expect(scope.incorrect).to.be.false; - expect(scope.confirmPassphrase).to.exist; - }); - }); - - describe('confirm passphrase', function() { - it('should unlock crypto with a public key on the server', function() { - scope.passphrase = passphrase; - scope.key = { - privateKeyArmored: 'b' - }; - - pgpMock.getKeyParams.returns({ - _id: 'id', - userIds: [] - }); - - keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, { - _id: keyId, - publicKey: 'a' - }); - emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields(); - keychainMock.putUserKeyPair.yields(); - - scope.confirmPassphrase(); - - expect(emailDaoMock.unlock.calledOnce).to.be.true; - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - }); - - it('should unlock crypto with no key on the server', function() { - scope.passphrase = passphrase; - scope.key = { - privateKeyArmored: 'b', - publicKeyArmored: 'a' - }; - - pgpMock.getKeyParams.returns({ - _id: 'id', - userIds: [] - }); - - keychainMock.getUserKeyPair.withArgs(emailAddress).yields(); - emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields(); - keychainMock.putUserKeyPair.yields(); - - scope.confirmPassphrase(); - - expect(emailDaoMock.unlock.calledOnce).to.be.true; - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - }); - - it('should not work when keypair upload fails', function(done) { - scope.passphrase = passphrase; - scope.key = { - privateKeyArmored: 'b' - }; - - pgpMock.getKeyParams.returns({ - _id: 'id', - userIds: [] - }); - - keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, { - _id: keyId, - publicKey: 'a' - }); - emailDaoMock.unlock.yields(); - keychainMock.putUserKeyPair.yields({ - errMsg: 'yo mamma.' - }); - - scope.onError = function(err) { - expect(err.errMsg).to.equal('yo mamma.'); - done(); - }; - - scope.confirmPassphrase(); - - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - expect(emailDaoMock.unlock.calledOnce).to.be.true; - expect(keychainMock.putUserKeyPair.calledOnce).to.be.true; - }); - - it('should not work when unlock fails', function(done) { - scope.passphrase = passphrase; - scope.key = { - privateKeyArmored: 'b' - }; - - pgpMock.getKeyParams.returns({ - _id: 'id', - userIds: [] - }); - - keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, { - _id: keyId, - publicKey: 'a' - }); - emailDaoMock.unlock.yields({ - errMsg: 'yo mamma.' - }); - - scope.onError = function(err) { - expect(err.errMsg).to.equal('yo mamma.'); - done(); - }; - - scope.confirmPassphrase(); - - expect(scope.incorrect).to.be.true; - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - expect(emailDaoMock.unlock.calledOnce).to.be.true; - }); - - it('should not work when keypair retrieval', function(done) { - scope.passphrase = passphrase; - - keychainMock.getUserKeyPair.withArgs(emailAddress).yields({ - errMsg: 'yo mamma.' - }); - - scope.onError = function(err) { - expect(err.errMsg).to.equal('yo mamma.'); - done(); - }; - - scope.confirmPassphrase(); - - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + ctrl = $controller(LoginNewDeviceCtrl, { + $scope: scope, + $routeParams: {} }); }); }); + + afterEach(function() { + // restore the module + appController._emailDao = origEmailDao; + }); + + describe('initial state', function() { + it('should be well defined', function() { + expect(scope.incorrect).to.be.false; + expect(scope.confirmPassphrase).to.exist; + }); + }); + + describe('confirm passphrase', function() { + it('should unlock crypto with a public key on the server', function() { + scope.passphrase = passphrase; + scope.key = { + privateKeyArmored: 'b' + }; + + pgpMock.getKeyParams.returns({ + _id: 'id', + userIds: [] + }); + + keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, { + _id: keyId, + publicKey: 'a' + }); + emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields(); + keychainMock.putUserKeyPair.yields(); + + scope.confirmPassphrase(); + + expect(emailDaoMock.unlock.calledOnce).to.be.true; + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + }); + + it('should unlock crypto with no key on the server', function() { + scope.passphrase = passphrase; + scope.key = { + privateKeyArmored: 'b', + publicKeyArmored: 'a' + }; + + pgpMock.getKeyParams.returns({ + _id: 'id', + userIds: [] + }); + + keychainMock.getUserKeyPair.withArgs(emailAddress).yields(); + emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields(); + keychainMock.putUserKeyPair.yields(); + + scope.confirmPassphrase(); + + expect(emailDaoMock.unlock.calledOnce).to.be.true; + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + }); + + it('should not work when keypair upload fails', function(done) { + scope.passphrase = passphrase; + scope.key = { + privateKeyArmored: 'b' + }; + + pgpMock.getKeyParams.returns({ + _id: 'id', + userIds: [] + }); + + keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, { + _id: keyId, + publicKey: 'a' + }); + emailDaoMock.unlock.yields(); + keychainMock.putUserKeyPair.yields({ + errMsg: 'yo mamma.' + }); + + scope.onError = function(err) { + expect(err.errMsg).to.equal('yo mamma.'); + done(); + }; + + scope.confirmPassphrase(); + + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + expect(emailDaoMock.unlock.calledOnce).to.be.true; + expect(keychainMock.putUserKeyPair.calledOnce).to.be.true; + }); + + it('should not work when unlock fails', function(done) { + scope.passphrase = passphrase; + scope.key = { + privateKeyArmored: 'b' + }; + + pgpMock.getKeyParams.returns({ + _id: 'id', + userIds: [] + }); + + keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, { + _id: keyId, + publicKey: 'a' + }); + emailDaoMock.unlock.yields({ + errMsg: 'yo mamma.' + }); + + scope.onError = function(err) { + expect(err.errMsg).to.equal('yo mamma.'); + done(); + }; + + scope.confirmPassphrase(); + + expect(scope.incorrect).to.be.true; + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + expect(emailDaoMock.unlock.calledOnce).to.be.true; + }); + + it('should not work when keypair retrieval', function(done) { + scope.passphrase = passphrase; + + keychainMock.getUserKeyPair.withArgs(emailAddress).yields({ + errMsg: 'yo mamma.' + }); + + scope.onError = function(err) { + expect(err.errMsg).to.equal('yo mamma.'); + done(); + }; + + scope.confirmPassphrase(); + + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + }); + }); }); \ No newline at end of file diff --git a/test/unit/login-privatekey-download-ctrl-test.js b/test/unit/login-privatekey-download-ctrl-test.js index 532dbf1..2c6d62d 100644 --- a/test/unit/login-privatekey-download-ctrl-test.js +++ b/test/unit/login-privatekey-download-ctrl-test.js @@ -1,39 +1,250 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - Auth = require('js/bo/auth'), - LoginPrivateKeyDownloadCtrl = require('js/controller/login-privatekey-download'), - EmailDAO = require('js/dao/email-dao'), - appController = require('js/app-controller'), - KeychainDAO = require('js/dao/keychain-dao'); +var mocks = angular.mocks, + Auth = require('../../src/js/bo/auth'), + LoginPrivateKeyDownloadCtrl = require('../../src/js/controller/login-privatekey-download'), + EmailDAO = require('../../src/js/dao/email-dao'), + appController = require('../../src/js/app-controller'), + KeychainDAO = require('../../src/js/dao/keychain-dao'); - describe('Login Private Key Download Controller unit test', function() { - var scope, location, ctrl, - origEmailDao, emailDaoMock, - origAuth, authMock, - origKeychain, keychainMock, - emailAddress = 'fred@foo.com'; +describe('Login Private Key Download Controller unit test', function() { + var scope, location, ctrl, + origEmailDao, emailDaoMock, + origAuth, authMock, + origKeychain, keychainMock, + emailAddress = 'fred@foo.com'; - beforeEach(function(done) { - // remember original module to restore later, then replace it - origEmailDao = appController._emailDao; - origKeychain = appController._keychain; - origAuth = appController._auth; + beforeEach(function(done) { + // remember original module to restore later, then replace it + origEmailDao = appController._emailDao; + origKeychain = appController._keychain; + origAuth = appController._auth; - appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO); - appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); - appController._auth = authMock = sinon.createStubInstance(Auth); + appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO); + appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); + appController._auth = authMock = sinon.createStubInstance(Auth); - emailDaoMock._account = { - emailAddress: emailAddress + emailDaoMock._account = { + emailAddress: emailAddress + }; + + angular.module('login-privatekey-download-test', []); + mocks.module('login-privatekey-download-test'); + mocks.inject(function($controller, $rootScope) { + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(LoginPrivateKeyDownloadCtrl, { + $location: location, + $scope: scope, + $routeParams: {} + }); + done(); + }); + }); + + afterEach(function() { + // restore the app controller module + appController._emailDao = origEmailDao; + appController._keychain = origKeychain; + appController._auth = origAuth; + }); + + describe('initialization', function() { + it('should work', function() { + expect(scope.step).to.equal(1); + }); + }); + + describe('verifyRecoveryToken', function() { + var testKeypair = { + publicKey: { + _id: 'id' + } + }; + + it('should fail for empty recovery token', function(done) { + scope.onError = function(err) { + expect(err).to.exist; + done(); }; - angular.module('login-privatekey-download-test', []); - mocks.module('login-privatekey-download-test'); - mocks.inject(function($controller, $rootScope) { + scope.recoveryToken = undefined; + scope.verifyRecoveryToken(); + }); + + it('should fail in keychain.getUserKeyPair', function(done) { + keychainMock.getUserKeyPair.yields(42); + + scope.onError = function(err) { + expect(err).to.exist; + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + done(); + }; + + scope.recoveryToken = 'token'; + scope.verifyRecoveryToken(); + }); + + it('should fail in keychain.downloadPrivateKey', function(done) { + keychainMock.getUserKeyPair.yields(null, testKeypair); + keychainMock.downloadPrivateKey.yields(42); + + scope.onError = function(err) { + expect(err).to.exist; + expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; + expect(keychainMock.downloadPrivateKey.calledOnce).to.be.true; + done(); + }; + + scope.recoveryToken = 'token'; + scope.verifyRecoveryToken(); + }); + + it('should work', function(done) { + keychainMock.getUserKeyPair.yields(null, testKeypair); + keychainMock.downloadPrivateKey.yields(null, 'encryptedPrivateKey'); + + scope.recoveryToken = 'token'; + scope.verifyRecoveryToken(function() { + expect(scope.encryptedPrivateKey).to.equal('encryptedPrivateKey'); + done(); + }); + }); + }); + + describe('handlePaste', function() { + it('should work', function() { + scope.handlePaste({ + clipboardData: { + getData: function(val) { + expect(val).to.equal('text/plain'); + return '1qaz-2wsx-3edc-4rfv-5tgb-6yhn'; + } + } + }); + + expect(scope.code0).to.equal('1qaz'); + expect(scope.code1).to.equal('2wsx'); + expect(scope.code2).to.equal('3edc'); + expect(scope.code3).to.equal('4rfv'); + expect(scope.code4).to.equal('5tgb'); + expect(scope.code5).to.equal('6yhn'); + }); + }); + + describe('decryptAndStorePrivateKeyLocally', function() { + beforeEach(function() { + scope.code0 = '0'; + scope.code1 = '1'; + scope.code2 = '2'; + scope.code3 = '3'; + scope.code4 = '4'; + scope.code5 = '5'; + + scope.encryptedPrivateKey = { + encryptedPrivateKey: 'encryptedPrivateKey' + }; + scope.cachedKeypair = { + publicKey: { + _id: 'keyId' + } + }; + }); + + it('should fail on empty code', function(done) { + scope.code0 = ''; + scope.code1 = ''; + scope.code2 = ''; + scope.code3 = ''; + scope.code4 = ''; + scope.code5 = ''; + + scope.onError = function(err) { + expect(err).to.exist; + done(); + }; + + scope.decryptAndStorePrivateKeyLocally(); + }); + + it('should fail on decryptAndStorePrivateKeyLocally', function(done) { + keychainMock.decryptAndStorePrivateKeyLocally.yields(42); + + scope.onError = function(err) { + expect(err).to.exist; + expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true; + done(); + }; + + scope.decryptAndStorePrivateKeyLocally(); + }); + + it('should goto /login-existing on emailDao.unlock fail', function(done) { + keychainMock.decryptAndStorePrivateKeyLocally.yields(null, { + encryptedKey: 'keyArmored' + }); + emailDaoMock.unlock.yields(42); + + scope.goTo = function(location) { + expect(location).to.equal('/login-existing'); + expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true; + expect(emailDaoMock.unlock.calledOnce).to.be.true; + done(); + }; + + scope.decryptAndStorePrivateKeyLocally(); + }); + + it('should goto /desktop on emailDao.unlock success', function(done) { + keychainMock.decryptAndStorePrivateKeyLocally.yields(null, { + encryptedKey: 'keyArmored' + }); + emailDaoMock.unlock.yields(); + authMock.storeCredentials.yields(); + + scope.goTo = function(location) { + expect(location).to.equal('/desktop'); + expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true; + expect(emailDaoMock.unlock.calledOnce).to.be.true; + done(); + }; + + scope.decryptAndStorePrivateKeyLocally(); + }); + }); + + describe('goForward', function() { + it('should work in step 1', function() { + var verifyRecoveryTokenStub = sinon.stub(scope, 'verifyRecoveryToken'); + verifyRecoveryTokenStub.yields(); + scope.step = 1; + + scope.goForward(); + + expect(verifyRecoveryTokenStub.calledOnce).to.be.true; + expect(scope.step).to.equal(2); + verifyRecoveryTokenStub.restore(); + }); + it('should work in step 2', function() { + var decryptAndStorePrivateKeyLocallyStub = sinon.stub(scope, 'decryptAndStorePrivateKeyLocally'); + decryptAndStorePrivateKeyLocallyStub.returns(); + scope.step = 2; + + scope.goForward(); + + expect(decryptAndStorePrivateKeyLocallyStub.calledOnce).to.be.true; + decryptAndStorePrivateKeyLocallyStub.restore(); + }); + }); + + describe('goTo', function() { + it('should work', function(done) { + mocks.inject(function($controller, $rootScope, $location) { + location = $location; + sinon.stub(location, 'path', function(path) { + expect(path).to.equal('/desktop'); + done(); + }); scope = $rootScope.$new(); scope.state = {}; ctrl = $controller(LoginPrivateKeyDownloadCtrl, { @@ -41,224 +252,9 @@ define(function(require) { $scope: scope, $routeParams: {} }); - done(); - }); - }); - - afterEach(function() { - // restore the app controller module - appController._emailDao = origEmailDao; - appController._keychain = origKeychain; - appController._auth = origAuth; - }); - - describe('initialization', function() { - it('should work', function() { - expect(scope.step).to.equal(1); - }); - }); - - describe('verifyRecoveryToken', function() { - var testKeypair = { - publicKey: { - _id: 'id' - } - }; - - it('should fail for empty recovery token', function(done) { - scope.onError = function(err) { - expect(err).to.exist; - done(); - }; - - scope.recoveryToken = undefined; - scope.verifyRecoveryToken(); }); - it('should fail in keychain.getUserKeyPair', function(done) { - keychainMock.getUserKeyPair.yields(42); - - scope.onError = function(err) { - expect(err).to.exist; - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - done(); - }; - - scope.recoveryToken = 'token'; - scope.verifyRecoveryToken(); - }); - - it('should fail in keychain.downloadPrivateKey', function(done) { - keychainMock.getUserKeyPair.yields(null, testKeypair); - keychainMock.downloadPrivateKey.yields(42); - - scope.onError = function(err) { - expect(err).to.exist; - expect(keychainMock.getUserKeyPair.calledOnce).to.be.true; - expect(keychainMock.downloadPrivateKey.calledOnce).to.be.true; - done(); - }; - - scope.recoveryToken = 'token'; - scope.verifyRecoveryToken(); - }); - - it('should work', function(done) { - keychainMock.getUserKeyPair.yields(null, testKeypair); - keychainMock.downloadPrivateKey.yields(null, 'encryptedPrivateKey'); - - scope.recoveryToken = 'token'; - scope.verifyRecoveryToken(function() { - expect(scope.encryptedPrivateKey).to.equal('encryptedPrivateKey'); - done(); - }); - }); - }); - - describe('handlePaste', function() { - it('should work', function() { - scope.handlePaste({ - clipboardData: { - getData: function(val) { - expect(val).to.equal('text/plain'); - return '1qaz-2wsx-3edc-4rfv-5tgb-6yhn'; - } - } - }); - - expect(scope.code0).to.equal('1qaz'); - expect(scope.code1).to.equal('2wsx'); - expect(scope.code2).to.equal('3edc'); - expect(scope.code3).to.equal('4rfv'); - expect(scope.code4).to.equal('5tgb'); - expect(scope.code5).to.equal('6yhn'); - }); - }); - - describe('decryptAndStorePrivateKeyLocally', function() { - beforeEach(function() { - scope.code0 = '0'; - scope.code1 = '1'; - scope.code2 = '2'; - scope.code3 = '3'; - scope.code4 = '4'; - scope.code5 = '5'; - - scope.encryptedPrivateKey = { - encryptedPrivateKey: 'encryptedPrivateKey' - }; - scope.cachedKeypair = { - publicKey: { - _id: 'keyId' - } - }; - }); - - it('should fail on empty code', function(done) { - scope.code0 = ''; - scope.code1 = ''; - scope.code2 = ''; - scope.code3 = ''; - scope.code4 = ''; - scope.code5 = ''; - - scope.onError = function(err) { - expect(err).to.exist; - done(); - }; - - scope.decryptAndStorePrivateKeyLocally(); - }); - - it('should fail on decryptAndStorePrivateKeyLocally', function(done) { - keychainMock.decryptAndStorePrivateKeyLocally.yields(42); - - scope.onError = function(err) { - expect(err).to.exist; - expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true; - done(); - }; - - scope.decryptAndStorePrivateKeyLocally(); - }); - - it('should goto /login-existing on emailDao.unlock fail', function(done) { - keychainMock.decryptAndStorePrivateKeyLocally.yields(null, { - encryptedKey: 'keyArmored' - }); - emailDaoMock.unlock.yields(42); - - scope.goTo = function(location) { - expect(location).to.equal('/login-existing'); - expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true; - expect(emailDaoMock.unlock.calledOnce).to.be.true; - done(); - }; - - scope.decryptAndStorePrivateKeyLocally(); - }); - - it('should goto /desktop on emailDao.unlock success', function(done) { - keychainMock.decryptAndStorePrivateKeyLocally.yields(null, { - encryptedKey: 'keyArmored' - }); - emailDaoMock.unlock.yields(); - authMock.storeCredentials.yields(); - - scope.goTo = function(location) { - expect(location).to.equal('/desktop'); - expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true; - expect(emailDaoMock.unlock.calledOnce).to.be.true; - done(); - }; - - scope.decryptAndStorePrivateKeyLocally(); - }); - }); - - describe('goForward', function() { - it('should work in step 1', function() { - var verifyRecoveryTokenStub = sinon.stub(scope, 'verifyRecoveryToken'); - verifyRecoveryTokenStub.yields(); - scope.step = 1; - - scope.goForward(); - - expect(verifyRecoveryTokenStub.calledOnce).to.be.true; - expect(scope.step).to.equal(2); - verifyRecoveryTokenStub.restore(); - }); - it('should work in step 2', function() { - var decryptAndStorePrivateKeyLocallyStub = sinon.stub(scope, 'decryptAndStorePrivateKeyLocally'); - decryptAndStorePrivateKeyLocallyStub.returns(); - scope.step = 2; - - scope.goForward(); - - expect(decryptAndStorePrivateKeyLocallyStub.calledOnce).to.be.true; - decryptAndStorePrivateKeyLocallyStub.restore(); - }); - }); - - describe('goTo', function() { - it('should work', function(done) { - mocks.inject(function($controller, $rootScope, $location) { - location = $location; - sinon.stub(location, 'path', function(path) { - expect(path).to.equal('/desktop'); - done(); - }); - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(LoginPrivateKeyDownloadCtrl, { - $location: location, - $scope: scope, - $routeParams: {} - }); - }); - - scope.goTo('/desktop'); - }); + scope.goTo('/desktop'); }); }); }); \ No newline at end of file diff --git a/test/unit/login-set-credentials-ctrl-test.js b/test/unit/login-set-credentials-ctrl-test.js index 41c1398..4b54066 100644 --- a/test/unit/login-set-credentials-ctrl-test.js +++ b/test/unit/login-set-credentials-ctrl-test.js @@ -1,101 +1,97 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - Auth = require('js/bo/auth'), - ConnectionDoctor = require('js/util/connection-doctor'), - SetCredentialsCtrl = require('js/controller/login-set-credentials'), - appController = require('js/app-controller'); +var mocks = angular.mocks, + Auth = require('../../src/js/bo/auth'), + ConnectionDoctor = require('../../src/js/util/connection-doctor'), + SetCredentialsCtrl = require('../../src/js/controller/login-set-credentials'), + appController = require('../../src/js/app-controller'); - describe('Login (Set Credentials) Controller unit test', function() { - // Angular parameters - var scope, location, provider; +describe('Login (Set Credentials) Controller unit test', function() { + // Angular parameters + var scope, location, provider; - // Stubs - var auth, origAuth, doctor, origDoctor; + // Stubs + var auth, origAuth, doctor, origDoctor; - // SUT - var setCredentialsCtrl; + // SUT + var setCredentialsCtrl; - beforeEach(function() { - // remeber pre-test state to restore later - origAuth = appController._auth; - origDoctor = appController._doctor; - auth = appController._auth = sinon.createStubInstance(Auth); - doctor = appController._doctor = sinon.createStubInstance(ConnectionDoctor); + beforeEach(function() { + // remeber pre-test state to restore later + origAuth = appController._auth; + origDoctor = appController._doctor; + auth = appController._auth = sinon.createStubInstance(Auth); + doctor = appController._doctor = sinon.createStubInstance(ConnectionDoctor); - // setup the controller - angular.module('setcredentialstest', []); - mocks.module('setcredentialstest'); - mocks.inject(function($rootScope, $controller, $location) { - scope = $rootScope.$new(); - location = $location; - location.search({ - provider: provider - }); - - scope.state = {}; - setCredentialsCtrl = $controller(SetCredentialsCtrl, { - $scope: scope, - $routeParams: {} - }); + // setup the controller + angular.module('setcredentialstest', []); + mocks.module('setcredentialstest'); + mocks.inject(function($rootScope, $controller, $location) { + scope = $rootScope.$new(); + location = $location; + location.search({ + provider: provider }); - }); - afterEach(function() { - // restore pre-test state - appController._auth = origAuth; - appController._doctor = origDoctor; - }); - - describe('set credentials', function() { - it('should work', function() { - scope.emailAddress = 'emailemailemailemail'; - scope.password = 'passwdpasswdpasswdpasswd'; - scope.smtpHost = 'hosthosthost'; - scope.smtpPort = 1337; - scope.smtpEncryption = '1'; // STARTTLS - scope.imapHost = 'hosthosthost'; - scope.imapPort = 1337; - scope.imapEncryption = '2'; // TLS - scope.realname = 'peter pan'; - - var expectedCredentials = { - provider: provider, - emailAddress: scope.emailAddress, - username: scope.username || scope.emailAddress, - realname: scope.realname, - password: scope.password, - xoauth2: undefined, - imap: { - host: scope.imapHost.toLowerCase(), - port: scope.imapPort, - secure: true, - ignoreTLS: false, - ca: undefined, - pinned: false - }, - smtp: { - host: scope.smtpHost.toLowerCase(), - port: scope.smtpPort, - secure: false, - ignoreTLS: false, - ca: undefined, - pinned: false - } - }; - - doctor.check.yields(); // synchronous yields! - - scope.test(); - - expect(doctor.check.calledOnce).to.be.true; - expect(doctor.configure.calledOnce).to.be.true; - expect(doctor.configure.calledWith(expectedCredentials)).to.be.true; - expect(auth.setCredentials.calledOnce).to.be.true; + scope.state = {}; + setCredentialsCtrl = $controller(SetCredentialsCtrl, { + $scope: scope, + $routeParams: {} }); }); }); + + afterEach(function() { + // restore pre-test state + appController._auth = origAuth; + appController._doctor = origDoctor; + }); + + describe('set credentials', function() { + it('should work', function() { + scope.emailAddress = 'emailemailemailemail'; + scope.password = 'passwdpasswdpasswdpasswd'; + scope.smtpHost = 'hosthosthost'; + scope.smtpPort = 1337; + scope.smtpEncryption = '1'; // STARTTLS + scope.imapHost = 'hosthosthost'; + scope.imapPort = 1337; + scope.imapEncryption = '2'; // TLS + scope.realname = 'peter pan'; + + var expectedCredentials = { + provider: provider, + emailAddress: scope.emailAddress, + username: scope.username || scope.emailAddress, + realname: scope.realname, + password: scope.password, + xoauth2: undefined, + imap: { + host: scope.imapHost.toLowerCase(), + port: scope.imapPort, + secure: true, + ignoreTLS: false, + ca: undefined, + pinned: false + }, + smtp: { + host: scope.smtpHost.toLowerCase(), + port: scope.smtpPort, + secure: false, + ignoreTLS: false, + ca: undefined, + pinned: false + } + }; + + doctor.check.yields(); // synchronous yields! + + scope.test(); + + expect(doctor.check.calledOnce).to.be.true; + expect(doctor.configure.calledOnce).to.be.true; + expect(doctor.configure.calledWith(expectedCredentials)).to.be.true; + expect(auth.setCredentials.calledOnce).to.be.true; + }); + }); }); \ No newline at end of file diff --git a/test/unit/mail-list-ctrl-test.js b/test/unit/mail-list-ctrl-test.js index 7dab559..7fe4e98 100644 --- a/test/unit/mail-list-ctrl-test.js +++ b/test/unit/mail-list-ctrl-test.js @@ -1,451 +1,447 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - MailListCtrl = require('js/controller/mail-list'), - EmailDAO = require('js/dao/email-dao'), - DeviceStorageDAO = require('js/dao/devicestorage-dao'), - KeychainDAO = require('js/dao/keychain-dao'), - appController = require('js/app-controller'), - notification = require('js/util/notification'); +var mocks = angular.mocks, + MailListCtrl = require('../../src/js/controller/mail-list'), + EmailDAO = require('../../src/js/dao/email-dao'), + DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + appController = require('../../src/js/app-controller'), + notification = require('../../src/js/util/notification'); - chai.Assertion.includeStack = true; +chai.Assertion.includeStack = true; - describe('Mail List controller unit test', function() { - var scope, ctrl, origEmailDao, emailDaoMock, keychainMock, deviceStorageMock, - emailAddress, emails, - hasChrome, hasSocket, hasRuntime, hasIdentity; +describe('Mail List controller unit test', function() { + var scope, ctrl, origEmailDao, emailDaoMock, keychainMock, deviceStorageMock, + emailAddress, emails, + hasChrome, hasSocket, hasRuntime, hasIdentity; - beforeEach(function() { - hasChrome = !!window.chrome; - hasSocket = !!window.chrome.socket; - hasIdentity = !!window.chrome.identity; - if (!hasChrome) { - window.chrome = {}; - } - if (!hasSocket) { - window.chrome.socket = {}; - } - if (!hasRuntime) { - window.chrome.runtime = { - getURL: function() {} - }; - } - if (!hasIdentity) { - window.chrome.identity = {}; - } + beforeEach(function() { + hasChrome = !!window.chrome; + hasSocket = !!window.chrome.socket; + hasIdentity = !!window.chrome.identity; + if (!hasChrome) { + window.chrome = {}; + } + if (!hasSocket) { + window.chrome.socket = {}; + } + if (!hasRuntime) { + window.chrome.runtime = { + getURL: function() {} + }; + } + if (!hasIdentity) { + window.chrome.identity = {}; + } - emails = [{ - unread: true - }, { - unread: true - }, { - unread: true - }]; - appController._outboxBo = { - pendingEmails: emails + emails = [{ + unread: true + }, { + unread: true + }, { + unread: true + }]; + appController._outboxBo = { + pendingEmails: emails + }; + + origEmailDao = appController._emailDao; + emailDaoMock = sinon.createStubInstance(EmailDAO); + appController._emailDao = emailDaoMock; + emailAddress = 'fred@foo.com'; + emailDaoMock._account = { + emailAddress: emailAddress, + }; + + + keychainMock = sinon.createStubInstance(KeychainDAO); + appController._keychain = keychainMock; + + deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO); + emailDaoMock._devicestorage = deviceStorageMock; + + angular.module('maillisttest', []); + mocks.module('maillisttest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = { + read: { + toggle: function() {} + } }; - origEmailDao = appController._emailDao; - emailDaoMock = sinon.createStubInstance(EmailDAO); - appController._emailDao = emailDaoMock; - emailAddress = 'fred@foo.com'; - emailDaoMock._account = { - emailAddress: emailAddress, - }; - - - keychainMock = sinon.createStubInstance(KeychainDAO); - appController._keychain = keychainMock; - - deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO); - emailDaoMock._devicestorage = deviceStorageMock; - - angular.module('maillisttest', []); - mocks.module('maillisttest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = { - read: { - toggle: function() {} - } - }; - - scope.loadVisibleBodies = function() {}; - ctrl = $controller(MailListCtrl, { - $scope: scope, - $routeParams: {} - }); - }); - }); - - afterEach(function() { - if (!hasSocket) { - delete window.chrome.socket; - } - if (!hasRuntime) { - delete window.chrome.runtime; - } - if (!hasChrome) { - delete window.chrome; - } - if (!hasIdentity) { - delete window.chrome.identity; - } - - // restore the module - appController._emailDao = origEmailDao; - }); - - describe('displayMore', function() { - beforeEach(function() { - scope.state.nav = { - currentFolder: { - messages: ['a', 'b'] - } - }; - }); - it('should not do anything when display length equals messages length', function() { - scope.displayMessages = ['a', 'b']; - - scope.displayMore(); - expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length); - }); - it('should append next message interval', function() { - scope.displayMessages = ['a']; - - scope.displayMore(); - expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length); - }); - }); - - describe('displaySearchResults', function() { - var clock; - - beforeEach(function() { - scope.state.nav = { - currentFolder: { - messages: ['a', 'b'] - } - }; - scope.watchMessages(); - scope.watchOnline(); - clock = sinon.useFakeTimers(); - }); - afterEach(function() { - clock.restore(); - }); - - it('should show initial message on empty', function() { - scope.displaySearchResults(); - expect(scope.searching).to.be.false; - expect(scope.lastUpdateLbl).to.equal('Online'); - expect(scope.displayMessages.length).to.equal(2); - }); - it('should show initial message on empty', function() { - var searchStub = sinon.stub(scope, 'search'); - searchStub.returns(['a']); - - - scope.displaySearchResults('query'); - expect(scope.searching).to.be.true; - expect(scope.lastUpdateLbl).to.equal('Searching ...'); - clock.tick(500); - - expect(scope.displayMessages).to.deep.equal(['a']); - expect(scope.searching).to.be.false; - expect(scope.lastUpdateLbl).to.equal('Matches in this folder'); - - }); - }); - - describe('search', function() { - var message1 = { - to: [{ - name: 'name1', - address: 'address1' - }], - subject: 'subject1', - body: 'body1', - html: 'html1' - }, - message2 = { - to: [{ - name: 'name2', - address: 'address2' - }], - subject: 'subject2', - body: 'body2', - html: 'html2' - }, - message3 = { - to: [{ - name: 'name3', - address: 'address3' - }], - subject: 'subject3', - body: 'body1', - html: 'html1', - encrypted: true - }, - message4 = { - to: [{ - name: 'name4', - address: 'address4' - }], - subject: 'subject4', - body: 'body1', - html: 'html1', - encrypted: true, - decrypted: true - }, - testMessages = [message1, message2, message3, message4]; - - it('return same messages array on empty query string', function() { - var result = scope.search(testMessages, ''); - expect(result).to.equal(testMessages); - }); - - it('return message1 on matching subject', function() { - var result = scope.search(testMessages, 'subject1'); - expect(result.length).to.equal(1); - expect(result[0]).to.equal(message1); - }); - - it('return message1 on matching name', function() { - var result = scope.search(testMessages, 'name1'); - expect(result.length).to.equal(1); - expect(result[0]).to.equal(message1); - }); - - it('return message1 on matching address', function() { - var result = scope.search(testMessages, 'address1'); - expect(result.length).to.equal(1); - expect(result[0]).to.equal(message1); - }); - - it('return plaintext and decrypted messages on matching body', function() { - var result = scope.search(testMessages, 'body1'); - expect(result.length).to.equal(2); - expect(result[0]).to.equal(message1); - expect(result[1]).to.equal(message4); - }); - - it('return plaintext and decrypted messages on matching html', function() { - var result = scope.search(testMessages, 'html1'); - expect(result.length).to.equal(2); - expect(result[0]).to.equal(message1); - expect(result[1]).to.equal(message4); - }); - }); - - describe('scope variables', function() { - it('should be set correctly', function() { - expect(scope.select).to.exist; - expect(scope.remove).to.exist; - expect(scope.state.mailList).to.exist; - }); - }); - - describe('push notification', function() { - beforeEach(function() { - scope._stopWatchTask(); - }); - - afterEach(function() { - notification.create.restore(); - }); - - it('should succeed for single mail', function(done) { - var mail = { - uid: 123, - from: [{ - address: 'asd' - }], - subject: 'this is the subject!', - unread: true - }; - - sinon.stub(notification, 'create', function(opts) { - expect(opts.title).to.equal(mail.from[0].address); - expect(opts.message).to.equal(mail.subject); - - opts.onClick(); - expect(scope.state.mailList.selected).to.equal(mail); - done(); - }); - - scope.state.nav = { - currentFolder: { - type: 'asd', - messages: [mail] - } - }; - - emailDaoMock.onIncomingMessage([mail]); - }); - - it('should succeed for multiple mails', function(done) { - var mails = [{ - uid: 1, - from: [{ - address: 'asd' - }], - subject: 'this is the subject!', - unread: true - }, { - uid: 2, - from: [{ - address: 'qwe' - }], - subject: 'this is the other subject!', - unread: true - }, { - uid: 3, - from: [{ - address: 'qwe' - }], - subject: 'this is the other subject!', - unread: false - }]; - - sinon.stub(notification, 'create', function(opts) { - expect(opts.title).to.equal('2 new messages'); - expect(opts.message).to.equal(mails[0].subject + '\n' + mails[1].subject); - - opts.onClick(); - expect(scope.state.mailList.selected).to.equal(mails[0]); - done(); - }); - - scope.state.nav = { - currentFolder: { - type: 'asd', - messages: mails - } - }; - - emailDaoMock.onIncomingMessage(mails); - }); - }); - - describe('getBody', function() { - it('should get the mail content', function() { - scope.state.nav = { - currentFolder: { - type: 'asd', - } - }; - - scope.getBody(); - expect(emailDaoMock.getBody.calledOnce).to.be.true; - }); - }); - - describe('select', function() { - it('should decrypt, focus mark an unread mail as read', function() { - scope.pendingNotifications = ['asd']; - sinon.stub(notification, 'close'); - - var mail = { - from: [{ - address: 'asd' - }], - unread: true, - }; - scope.state = { - nav: { - currentFolder: { - type: 'Inbox' - } - }, - mailList: {}, - read: { - toggle: function() {} - } - }; - - keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields(); - - scope.select(mail); - - expect(emailDaoMock.decryptBody.calledOnce).to.be.true; - expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; - expect(scope.state.mailList.selected).to.equal(mail); - expect(notification.close.calledWith('asd')).to.be.true; - expect(notification.close.calledOnce).to.be.true; - - notification.close.restore(); - }); - - it('should decrypt and focus a read mail', function() { - var mail = { - from: [{ - address: 'asd' - }], - unread: false - }; - - scope.state = { - mailList: {}, - read: { - toggle: function() {} - }, - nav: { - currentFolder: { - type: 'asd' - } - } - }; - - keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields(); - - scope.select(mail); - - expect(emailDaoMock.decryptBody.calledOnce).to.be.true; - expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; - expect(scope.state.mailList.selected).to.equal(mail); - }); - }); - - describe('remove', function() { - it('should not delete without a selected mail', function() { - scope.remove(); - }); - - it('should delete the selected mail', function() { - var uid, mail, currentFolder; - - scope._stopWatchTask(); - - scope.account = {}; - uid = 123; - mail = { - uid: uid, - from: [{ - address: 'asd' - }], - subject: '[whiteout] asdasd', - unread: true - }; - currentFolder = { - type: 'Inbox', - path: 'INBOX', - messages: [mail] - }; - scope.account.folders = [currentFolder]; - scope.state.nav = { - currentFolder: currentFolder - }; - emailDaoMock.deleteMessage.yields(); - - scope.remove(mail); - - expect(emailDaoMock.deleteMessage.calledOnce).to.be.true; - expect(scope.state.mailList.selected).to.exist; + scope.loadVisibleBodies = function() {}; + ctrl = $controller(MailListCtrl, { + $scope: scope, + $routeParams: {} }); }); }); + + afterEach(function() { + if (!hasSocket) { + delete window.chrome.socket; + } + if (!hasRuntime) { + delete window.chrome.runtime; + } + if (!hasChrome) { + delete window.chrome; + } + if (!hasIdentity) { + delete window.chrome.identity; + } + + // restore the module + appController._emailDao = origEmailDao; + }); + + describe('displayMore', function() { + beforeEach(function() { + scope.state.nav = { + currentFolder: { + messages: ['a', 'b'] + } + }; + }); + it('should not do anything when display length equals messages length', function() { + scope.displayMessages = ['a', 'b']; + + scope.displayMore(); + expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length); + }); + it('should append next message interval', function() { + scope.displayMessages = ['a']; + + scope.displayMore(); + expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length); + }); + }); + + describe('displaySearchResults', function() { + var clock; + + beforeEach(function() { + scope.state.nav = { + currentFolder: { + messages: ['a', 'b'] + } + }; + scope.watchMessages(); + scope.watchOnline(); + clock = sinon.useFakeTimers(); + }); + afterEach(function() { + clock.restore(); + }); + + it('should show initial message on empty', function() { + scope.displaySearchResults(); + expect(scope.searching).to.be.false; + expect(scope.lastUpdateLbl).to.equal('Online'); + expect(scope.displayMessages.length).to.equal(2); + }); + it('should show initial message on empty', function() { + var searchStub = sinon.stub(scope, 'search'); + searchStub.returns(['a']); + + + scope.displaySearchResults('query'); + expect(scope.searching).to.be.true; + expect(scope.lastUpdateLbl).to.equal('Searching ...'); + clock.tick(500); + + expect(scope.displayMessages).to.deep.equal(['a']); + expect(scope.searching).to.be.false; + expect(scope.lastUpdateLbl).to.equal('Matches in this folder'); + + }); + }); + + describe('search', function() { + var message1 = { + to: [{ + name: 'name1', + address: 'address1' + }], + subject: 'subject1', + body: 'body1', + html: 'html1' + }, + message2 = { + to: [{ + name: 'name2', + address: 'address2' + }], + subject: 'subject2', + body: 'body2', + html: 'html2' + }, + message3 = { + to: [{ + name: 'name3', + address: 'address3' + }], + subject: 'subject3', + body: 'body1', + html: 'html1', + encrypted: true + }, + message4 = { + to: [{ + name: 'name4', + address: 'address4' + }], + subject: 'subject4', + body: 'body1', + html: 'html1', + encrypted: true, + decrypted: true + }, + testMessages = [message1, message2, message3, message4]; + + it('return same messages array on empty query string', function() { + var result = scope.search(testMessages, ''); + expect(result).to.equal(testMessages); + }); + + it('return message1 on matching subject', function() { + var result = scope.search(testMessages, 'subject1'); + expect(result.length).to.equal(1); + expect(result[0]).to.equal(message1); + }); + + it('return message1 on matching name', function() { + var result = scope.search(testMessages, 'name1'); + expect(result.length).to.equal(1); + expect(result[0]).to.equal(message1); + }); + + it('return message1 on matching address', function() { + var result = scope.search(testMessages, 'address1'); + expect(result.length).to.equal(1); + expect(result[0]).to.equal(message1); + }); + + it('return plaintext and decrypted messages on matching body', function() { + var result = scope.search(testMessages, 'body1'); + expect(result.length).to.equal(2); + expect(result[0]).to.equal(message1); + expect(result[1]).to.equal(message4); + }); + + it('return plaintext and decrypted messages on matching html', function() { + var result = scope.search(testMessages, 'html1'); + expect(result.length).to.equal(2); + expect(result[0]).to.equal(message1); + expect(result[1]).to.equal(message4); + }); + }); + + describe('scope variables', function() { + it('should be set correctly', function() { + expect(scope.select).to.exist; + expect(scope.remove).to.exist; + expect(scope.state.mailList).to.exist; + }); + }); + + describe('push notification', function() { + beforeEach(function() { + scope._stopWatchTask(); + }); + + afterEach(function() { + notification.create.restore(); + }); + + it('should succeed for single mail', function(done) { + var mail = { + uid: 123, + from: [{ + address: 'asd' + }], + subject: 'this is the subject!', + unread: true + }; + + sinon.stub(notification, 'create', function(opts) { + expect(opts.title).to.equal(mail.from[0].address); + expect(opts.message).to.equal(mail.subject); + + opts.onClick(); + expect(scope.state.mailList.selected).to.equal(mail); + done(); + }); + + scope.state.nav = { + currentFolder: { + type: 'asd', + messages: [mail] + } + }; + + emailDaoMock.onIncomingMessage([mail]); + }); + + it('should succeed for multiple mails', function(done) { + var mails = [{ + uid: 1, + from: [{ + address: 'asd' + }], + subject: 'this is the subject!', + unread: true + }, { + uid: 2, + from: [{ + address: 'qwe' + }], + subject: 'this is the other subject!', + unread: true + }, { + uid: 3, + from: [{ + address: 'qwe' + }], + subject: 'this is the other subject!', + unread: false + }]; + + sinon.stub(notification, 'create', function(opts) { + expect(opts.title).to.equal('2 new messages'); + expect(opts.message).to.equal(mails[0].subject + '\n' + mails[1].subject); + + opts.onClick(); + expect(scope.state.mailList.selected).to.equal(mails[0]); + done(); + }); + + scope.state.nav = { + currentFolder: { + type: 'asd', + messages: mails + } + }; + + emailDaoMock.onIncomingMessage(mails); + }); + }); + + describe('getBody', function() { + it('should get the mail content', function() { + scope.state.nav = { + currentFolder: { + type: 'asd', + } + }; + + scope.getBody(); + expect(emailDaoMock.getBody.calledOnce).to.be.true; + }); + }); + + describe('select', function() { + it('should decrypt, focus mark an unread mail as read', function() { + scope.pendingNotifications = ['asd']; + sinon.stub(notification, 'close'); + + var mail = { + from: [{ + address: 'asd' + }], + unread: true, + }; + scope.state = { + nav: { + currentFolder: { + type: 'Inbox' + } + }, + mailList: {}, + read: { + toggle: function() {} + } + }; + + keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields(); + + scope.select(mail); + + expect(emailDaoMock.decryptBody.calledOnce).to.be.true; + expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; + expect(scope.state.mailList.selected).to.equal(mail); + expect(notification.close.calledWith('asd')).to.be.true; + expect(notification.close.calledOnce).to.be.true; + + notification.close.restore(); + }); + + it('should decrypt and focus a read mail', function() { + var mail = { + from: [{ + address: 'asd' + }], + unread: false + }; + + scope.state = { + mailList: {}, + read: { + toggle: function() {} + }, + nav: { + currentFolder: { + type: 'asd' + } + } + }; + + keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields(); + + scope.select(mail); + + expect(emailDaoMock.decryptBody.calledOnce).to.be.true; + expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; + expect(scope.state.mailList.selected).to.equal(mail); + }); + }); + + describe('remove', function() { + it('should not delete without a selected mail', function() { + scope.remove(); + }); + + it('should delete the selected mail', function() { + var uid, mail, currentFolder; + + scope._stopWatchTask(); + + scope.account = {}; + uid = 123; + mail = { + uid: uid, + from: [{ + address: 'asd' + }], + subject: '[whiteout] asdasd', + unread: true + }; + currentFolder = { + type: 'Inbox', + path: 'INBOX', + messages: [mail] + }; + scope.account.folders = [currentFolder]; + scope.state.nav = { + currentFolder: currentFolder + }; + emailDaoMock.deleteMessage.yields(); + + scope.remove(mail); + + expect(emailDaoMock.deleteMessage.calledOnce).to.be.true; + expect(scope.state.mailList.selected).to.exist; + }); + }); }); \ No newline at end of file diff --git a/test/unit/main.js b/test/unit/main.js deleted file mode 100644 index b889aba..0000000 --- a/test/unit/main.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -// Mozilla bind polyfill because phantomjs is stupid -if (!Function.prototype.bind) { - Function.prototype.bind = function(oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - FNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof FNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - FNOP.prototype = this.prototype; - fBound.prototype = new FNOP(); - - return fBound; - }; -} - -// a warm round of applause for phantomjs for missing events -(function() { - function CustomEvent(event, params) { - params = params || { - bubbles: false, - cancelable: false, - detail: undefined - }; - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); - return evt; - } - - CustomEvent.prototype = window.Event.prototype; - - window.CustomEvent = CustomEvent; -})(); - -require(['../../src/require-config'], function() { - require.config({ - baseUrl: '../../src/lib', - paths: { - angularMocks: '../../test/lib/angular-mocks' - }, - shim: { - angularMocks: { - exports: 'angular.mock', - deps: ['angular'] - } - } - }); - - - // Start the main app logic. - require(['js/app-config', 'axe'], function(app, axe) { - app.config.workerPath = '../../src/js'; - - // turn off logging in the test - axe.removeAppender(axe.defaultAppender); - - startTests(); - }); -}); - -function startTests() { - mocha.setup('bdd'); - - require( - [ - 'test/unit/oauth-test', - 'test/unit/auth-test', - 'test/unit/email-dao-test', - 'test/unit/app-controller-test', - 'test/unit/pgp-test', - 'test/unit/crypto-test', - 'test/unit/backbutton-handler-test', - 'test/unit/rest-dao-test', - 'test/unit/admin-dao-test', - 'test/unit/publickey-dao-test', - 'test/unit/privatekey-dao-test', - 'test/unit/lawnchair-dao-test', - 'test/unit/keychain-dao-test', - 'test/unit/devicestorage-dao-test', - 'test/unit/dialog-ctrl-test', - 'test/unit/add-account-ctrl-test', - 'test/unit/account-ctrl-test', - 'test/unit/set-passphrase-ctrl-test', - 'test/unit/contacts-ctrl-test', - 'test/unit/login-existing-ctrl-test', - 'test/unit/login-initial-ctrl-test', - 'test/unit/login-new-device-ctrl-test', - 'test/unit/login-privatekey-download-ctrl-test', - 'test/unit/login-set-credentials-ctrl-test', - 'test/unit/privatekey-upload-ctrl-test', - 'test/unit/login-ctrl-test', - 'test/unit/read-ctrl-test', - 'test/unit/navigation-ctrl-test', - 'test/unit/mail-list-ctrl-test', - 'test/unit/write-ctrl-test', - 'test/unit/outbox-bo-test', - 'test/unit/invitation-dao-test', - 'test/unit/update-handler-test', - 'test/unit/connection-doctor-test' - ], function() { - //Tests loaded, run tests - mocha.run(); - } - ); -} \ No newline at end of file diff --git a/test/unit/navigation-ctrl-test.js b/test/unit/navigation-ctrl-test.js index 9d977af..56b27d6 100644 --- a/test/unit/navigation-ctrl-test.js +++ b/test/unit/navigation-ctrl-test.js @@ -1,101 +1,97 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - NavigationCtrl = require('js/controller/navigation'), - EmailDAO = require('js/dao/email-dao'), - OutboxBO = require('js/bo/outbox'), - appController = require('js/app-controller'); +var mocks = angular.mocks, + NavigationCtrl = require('../../src/js/controller/navigation'), + EmailDAO = require('../../src/js/dao/email-dao'), + OutboxBO = require('../../src/js/bo/outbox'), + appController = require('../../src/js/app-controller'); - describe('Navigation Controller unit test', function() { - var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, outboxFolder, onConnectStub; +describe('Navigation Controller unit test', function() { + var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, outboxFolder, onConnectStub; - beforeEach(function(done) { - // remember original module to restore later - origEmailDao = appController._emailDao; - emailDaoMock = sinon.createStubInstance(EmailDAO); - emailDaoMock._account = { - folders: [{ - type: 'Inbox', - count: 2, - path: 'INBOX' - }, { - type: 'Outbox', - count: 0, - path: 'OUTBOX' - }] - }; - outboxFolder = emailDaoMock._account.folders[1]; - appController._emailDao = emailDaoMock; - outboxBoMock = sinon.createStubInstance(OutboxBO); - appController._outboxBo = outboxBoMock; - outboxBoMock.startChecking.returns(); - onConnectStub = sinon.stub(appController, 'onConnect'); - onConnectStub.yields(); + beforeEach(function(done) { + // remember original module to restore later + origEmailDao = appController._emailDao; + emailDaoMock = sinon.createStubInstance(EmailDAO); + emailDaoMock._account = { + folders: [{ + type: 'Inbox', + count: 2, + path: 'INBOX' + }, { + type: 'Outbox', + count: 0, + path: 'OUTBOX' + }] + }; + outboxFolder = emailDaoMock._account.folders[1]; + appController._emailDao = emailDaoMock; + outboxBoMock = sinon.createStubInstance(OutboxBO); + appController._outboxBo = outboxBoMock; + outboxBoMock.startChecking.returns(); + onConnectStub = sinon.stub(appController, 'onConnect'); + onConnectStub.yields(); - angular.module('navigationtest', []); - mocks.module('navigationtest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(NavigationCtrl, { - $scope: scope, - $routeParams: {} - }); - done(); + angular.module('navigationtest', []); + mocks.module('navigationtest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(NavigationCtrl, { + $scope: scope, + $routeParams: {} }); + done(); }); + }); - afterEach(function() { - // restore the module - appController._emailDao = origEmailDao; - onConnectStub.restore(); + afterEach(function() { + // restore the module + appController._emailDao = origEmailDao; + onConnectStub.restore(); + }); + + describe('initial state', function() { + it('should be well defined', function() { + expect(scope.state).to.exist; + expect(scope.state.lightbox).to.be.undefined; + expect(scope.account.folders).to.not.be.empty; + expect(scope.openFolder).to.exist; }); + }); - describe('initial state', function() { - it('should be well defined', function() { - expect(scope.state).to.exist; - expect(scope.state.lightbox).to.be.undefined; - expect(scope.account.folders).to.not.be.empty; - expect(scope.openFolder).to.exist; - }); + describe('open/close nav view', function() { + it('should open/close', function() { + expect(scope.state.nav.open).to.be.false; + scope.state.nav.toggle(true); + expect(scope.state.nav.open).to.be.true; + scope.state.nav.toggle(false); + expect(scope.state.nav.open).to.be.false; }); + }); - describe('open/close nav view', function() { - it('should open/close', function() { - expect(scope.state.nav.open).to.be.false; - scope.state.nav.toggle(true); - expect(scope.state.nav.open).to.be.true; - scope.state.nav.toggle(false); - expect(scope.state.nav.open).to.be.false; - }); + describe('open folder', function() { + it('should work', function() { + scope.state.nav.open = true; + + scope.openFolder('asd'); + expect(scope.state.nav.currentFolder).to.equal('asd'); + expect(scope.state.nav.open).to.be.false; }); + }); - describe('open folder', function() { - it('should work', function() { - scope.state.nav.open = true; + describe('empty outbox', function() { + it('should work', function() { + var callback; - scope.openFolder('asd'); - expect(scope.state.nav.currentFolder).to.equal('asd'); - expect(scope.state.nav.open).to.be.false; - }); - }); + expect(outboxBoMock.startChecking.callCount).to.equal(1); - describe('empty outbox', function() { - it('should work', function() { - var callback; + outboxBoMock.startChecking.calledWith(sinon.match(function(cb) { + callback = cb; + })); - expect(outboxBoMock.startChecking.callCount).to.equal(1); - - outboxBoMock.startChecking.calledWith(sinon.match(function(cb) { - callback = cb; - })); - - callback(null, 5); - expect(outboxFolder.count).to.equal(5); - }); + callback(null, 5); + expect(outboxFolder.count).to.equal(5); }); }); }); \ No newline at end of file diff --git a/test/unit/oauth-test.js b/test/unit/oauth-test.js index 39267d5..5178c0f 100644 --- a/test/unit/oauth-test.js +++ b/test/unit/oauth-test.js @@ -1,201 +1,198 @@ -define(function(require) { - 'use strict'; +'use strict'; - var OAuth = require('js/util/oauth'), - RestDAO = require('js/dao/rest-dao'), - expect = chai.expect; +var OAuth = require('../../src/js/util/oauth'), + RestDAO = require('../../src/js/dao/rest-dao'); - describe('OAuth unit tests', function() { - var oauth, googleApiStub, identityStub, getPlatformInfoStub, removeCachedStub, - testEmail = 'test@example.com'; +describe('OAuth unit tests', function() { + var oauth, googleApiStub, identityStub, getPlatformInfoStub, removeCachedStub, + testEmail = 'test@example.com'; + + beforeEach(function() { + googleApiStub = sinon.createStubInstance(RestDAO); + oauth = new OAuth(googleApiStub); + + window.chrome = window.chrome || {}; + + window.chrome.identity = window.chrome.identity || {}; + if (typeof window.chrome.identity.getAuthToken !== 'function') { + window.chrome.identity.getAuthToken = function() {}; + } + identityStub = sinon.stub(window.chrome.identity, 'getAuthToken'); + + if (typeof window.chrome.identity.removeCachedAuthToken !== 'function') { + window.chrome.identity.removeCachedAuthToken = function() {}; + } + removeCachedStub = sinon.stub(window.chrome.identity, 'removeCachedAuthToken'); + + window.chrome.runtime = window.chrome.runtime || {}; + if (typeof window.chrome.runtime.getPlatformInfo !== 'function') { + window.chrome.runtime.getPlatformInfo = function() {}; + } + getPlatformInfoStub = sinon.stub(window.chrome.runtime, 'getPlatformInfo'); + }); + + afterEach(function() { + identityStub.restore(); + getPlatformInfoStub.restore(); + removeCachedStub.restore(); + }); + + describe('isSupported', function() { + it('should work', function() { + expect(oauth.isSupported()).to.be.true; + }); + }); + + describe('refreshToken', function() { + var getOAuthTokenStub; beforeEach(function() { - googleApiStub = sinon.createStubInstance(RestDAO); - oauth = new OAuth(googleApiStub); - - window.chrome = window.chrome || {}; - - window.chrome.identity = window.chrome.identity || {}; - if (typeof window.chrome.identity.getAuthToken !== 'function') { - window.chrome.identity.getAuthToken = function() {}; - } - identityStub = sinon.stub(window.chrome.identity, 'getAuthToken'); - - if (typeof window.chrome.identity.removeCachedAuthToken !== 'function') { - window.chrome.identity.removeCachedAuthToken = function() {}; - } - removeCachedStub = sinon.stub(window.chrome.identity, 'removeCachedAuthToken'); - - window.chrome.runtime = window.chrome.runtime || {}; - if (typeof window.chrome.runtime.getPlatformInfo !== 'function') { - window.chrome.runtime.getPlatformInfo = function() {}; - } - getPlatformInfoStub = sinon.stub(window.chrome.runtime, 'getPlatformInfo'); + getOAuthTokenStub = sinon.stub(oauth, 'getOAuthToken'); }); - afterEach(function() { - identityStub.restore(); - getPlatformInfoStub.restore(); - removeCachedStub.restore(); + getOAuthTokenStub.restore(); }); - describe('isSupported', function() { - it('should work', function() { - expect(oauth.isSupported()).to.be.true; + it('should work', function() { + removeCachedStub.withArgs({ + token: 'oldToken' + }).yields(); + + getOAuthTokenStub.withArgs(testEmail).yields(); + + oauth.refreshToken({ + oldToken: 'oldToken', + emailAddress: testEmail + }, function(err) { + expect(err).to.not.exist; + expect(removeCachedStub.calledOnce).to.be.true; + expect(getOAuthTokenStub.calledOnce).to.be.true; }); }); - describe('refreshToken', function() { - var getOAuthTokenStub; + it('should work without email', function() { + removeCachedStub.withArgs({ + token: 'oldToken' + }).yields(); - beforeEach(function() { - getOAuthTokenStub = sinon.stub(oauth, 'getOAuthToken'); - }); - afterEach(function() { - getOAuthTokenStub.restore(); - }); + getOAuthTokenStub.withArgs(undefined).yields(); - it('should work', function() { - removeCachedStub.withArgs({ - token: 'oldToken' - }).yields(); - - getOAuthTokenStub.withArgs(testEmail).yields(); - - oauth.refreshToken({ - oldToken: 'oldToken', - emailAddress: testEmail - }, function(err) { - expect(err).to.not.exist; - expect(removeCachedStub.calledOnce).to.be.true; - expect(getOAuthTokenStub.calledOnce).to.be.true; - }); - }); - - it('should work without email', function() { - removeCachedStub.withArgs({ - token: 'oldToken' - }).yields(); - - getOAuthTokenStub.withArgs(undefined).yields(); - - oauth.refreshToken({ - oldToken: 'oldToken', - }, function(err) { - expect(err).to.not.exist; - expect(removeCachedStub.calledOnce).to.be.true; - expect(getOAuthTokenStub.calledOnce).to.be.true; - expect(getOAuthTokenStub.calledWith(undefined)).to.be.true; - }); - }); - - it('should fail without all options', function() { - oauth.refreshToken({ - emailAddress: testEmail - }, function(err) { - expect(err).to.exist; - expect(removeCachedStub.called).to.be.false; - expect(getOAuthTokenStub.called).to.be.false; - }); + oauth.refreshToken({ + oldToken: 'oldToken', + }, function(err) { + expect(err).to.not.exist; + expect(removeCachedStub.calledOnce).to.be.true; + expect(getOAuthTokenStub.calledOnce).to.be.true; + expect(getOAuthTokenStub.calledWith(undefined)).to.be.true; }); }); - describe('getOAuthToken', function() { - it('should work for empty emailAddress', function(done) { - getPlatformInfoStub.yields({ - os: 'android' - }); - identityStub.withArgs({ - interactive: true - }).yields('token'); - - oauth.getOAuthToken(undefined, function(err, token) { - expect(err).to.not.exist; - expect(token).to.equal('token'); - done(); - }); - }); - - it('should work on android app', function(done) { - getPlatformInfoStub.yields({ - os: 'android' - }); - identityStub.withArgs({ - interactive: true, - accountHint: testEmail - }).yields('token'); - - oauth.getOAuthToken(testEmail, function(err, token) { - expect(err).to.not.exist; - expect(token).to.equal('token'); - done(); - }); - }); - - it('should work on desktop chrome', function(done) { - getPlatformInfoStub.yields({ - os: 'mac' - }); - identityStub.withArgs({ - interactive: true - }).yields('token'); - - oauth.getOAuthToken(testEmail, function(err, token) { - expect(err).to.not.exist; - expect(token).to.equal('token'); - done(); - }); - }); - - it('should fail', function(done) { - getPlatformInfoStub.yields({ - os: 'android' - }); - identityStub.yields(); - - oauth.getOAuthToken(testEmail, function(err, token) { - expect(err).to.exist; - expect(token).to.not.exist; - done(); - }); + it('should fail without all options', function() { + oauth.refreshToken({ + emailAddress: testEmail + }, function(err) { + expect(err).to.exist; + expect(removeCachedStub.called).to.be.false; + expect(getOAuthTokenStub.called).to.be.false; }); }); - - describe('queryEmailAddress', function() { - it('should work', function(done) { - googleApiStub.get.withArgs({ - uri: '/oauth2/v3/userinfo?access_token=token' - }).yields(null, { - email: 'asdf@example.com' - }); - - oauth.queryEmailAddress('token', function(err, emailAddress) { - expect(err).to.not.exist; - expect(emailAddress).to.equal('asdf@example.com'); - done(); - }); - }); - - it('should fail due to invalid token', function(done) { - oauth.queryEmailAddress('', function(err, emailAddress) { - expect(err).to.exist; - expect(emailAddress).to.not.exist; - done(); - }); - }); - - it('should fail due to error in rest api', function(done) { - googleApiStub.get.withArgs({ - uri: '/oauth2/v3/userinfo?access_token=token' - }).yields(new Error()); - - oauth.queryEmailAddress('token', function(err, emailAddress) { - expect(err).to.exist; - expect(emailAddress).to.not.exist; - done(); - }); - }); - }); - }); + + describe('getOAuthToken', function() { + it('should work for empty emailAddress', function(done) { + getPlatformInfoStub.yields({ + os: 'android' + }); + identityStub.withArgs({ + interactive: true + }).yields('token'); + + oauth.getOAuthToken(undefined, function(err, token) { + expect(err).to.not.exist; + expect(token).to.equal('token'); + done(); + }); + }); + + it('should work on android app', function(done) { + getPlatformInfoStub.yields({ + os: 'android' + }); + identityStub.withArgs({ + interactive: true, + accountHint: testEmail + }).yields('token'); + + oauth.getOAuthToken(testEmail, function(err, token) { + expect(err).to.not.exist; + expect(token).to.equal('token'); + done(); + }); + }); + + it('should work on desktop chrome', function(done) { + getPlatformInfoStub.yields({ + os: 'mac' + }); + identityStub.withArgs({ + interactive: true + }).yields('token'); + + oauth.getOAuthToken(testEmail, function(err, token) { + expect(err).to.not.exist; + expect(token).to.equal('token'); + done(); + }); + }); + + it('should fail', function(done) { + getPlatformInfoStub.yields({ + os: 'android' + }); + identityStub.yields(); + + oauth.getOAuthToken(testEmail, function(err, token) { + expect(err).to.exist; + expect(token).to.not.exist; + done(); + }); + }); + }); + + describe('queryEmailAddress', function() { + it('should work', function(done) { + googleApiStub.get.withArgs({ + uri: '/oauth2/v3/userinfo?access_token=token' + }).yields(null, { + email: 'asdf@example.com' + }); + + oauth.queryEmailAddress('token', function(err, emailAddress) { + expect(err).to.not.exist; + expect(emailAddress).to.equal('asdf@example.com'); + done(); + }); + }); + + it('should fail due to invalid token', function(done) { + oauth.queryEmailAddress('', function(err, emailAddress) { + expect(err).to.exist; + expect(emailAddress).to.not.exist; + done(); + }); + }); + + it('should fail due to error in rest api', function(done) { + googleApiStub.get.withArgs({ + uri: '/oauth2/v3/userinfo?access_token=token' + }).yields(new Error()); + + oauth.queryEmailAddress('token', function(err, emailAddress) { + expect(err).to.exist; + expect(emailAddress).to.not.exist; + done(); + }); + }); + }); + }); \ No newline at end of file diff --git a/test/unit/outbox-bo-test.js b/test/unit/outbox-bo-test.js index 4d98198..55cc2a5 100644 --- a/test/unit/outbox-bo-test.js +++ b/test/unit/outbox-bo-test.js @@ -1,279 +1,276 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - OutboxBO = require('js/bo/outbox'), - KeychainDAO = require('js/dao/keychain-dao'), - EmailDAO = require('js/dao/email-dao'), - DeviceStorageDAO = require('js/dao/devicestorage-dao'); +var OutboxBO = require('../../src/js/bo/outbox'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + EmailDAO = require('../../src/js/dao/email-dao'), + DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'); - chai.Assertion.includeStack = true; +chai.Assertion.includeStack = true; - describe('Outbox Business Object unit test', function() { - var outbox, emailDaoStub, devicestorageStub, keychainStub, - dummyUser = 'spiderpig@springfield.com'; +describe('Outbox Business Object unit test', function() { + var outbox, emailDaoStub, devicestorageStub, keychainStub, + dummyUser = 'spiderpig@springfield.com'; - beforeEach(function() { - emailDaoStub = sinon.createStubInstance(EmailDAO); - emailDaoStub._account = { - emailAddress: dummyUser, - folders: [{ - type: 'Outbox' - }], - online: true + beforeEach(function() { + emailDaoStub = sinon.createStubInstance(EmailDAO); + emailDaoStub._account = { + emailAddress: dummyUser, + folders: [{ + type: 'Outbox' + }], + online: true + }; + devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); + keychainStub = sinon.createStubInstance(KeychainDAO); + outbox = new OutboxBO(emailDaoStub, keychainStub, devicestorageStub); + }); + + afterEach(function() {}); + + describe('start/stop checking', function() { + it('should work', function() { + function onOutboxUpdate(err) { + expect(err).to.not.exist; + } + + outbox.startChecking(onOutboxUpdate); + expect(outbox._intervalId).to.exist; + + outbox.stopChecking(); + expect(outbox._intervalId).to.not.exist; + }); + }); + + describe('put', function() { + it('should not encrypt and store a mail', function(done) { + var mail, senderKey, receiverKey; + + senderKey = { + publicKey: 'SENDER PUBLIC KEY' }; - devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); - keychainStub = sinon.createStubInstance(KeychainDAO); - outbox = new OutboxBO(emailDaoStub, keychainStub, devicestorageStub); - }); - - afterEach(function() {}); - - describe('start/stop checking', function() { - it('should work', function() { - function onOutboxUpdate(err) { - expect(err).to.not.exist; - } - - outbox.startChecking(onOutboxUpdate); - expect(outbox._intervalId).to.exist; - - outbox.stopChecking(); - expect(outbox._intervalId).to.not.exist; - }); - }); - - describe('put', function() { - it('should not encrypt and store a mail', function(done) { - var mail, senderKey, receiverKey; - - senderKey = { - publicKey: 'SENDER PUBLIC KEY' - }; - receiverKey = { - publicKey: 'RECEIVER PUBLIC KEY' - }; - mail = { - from: [{ - name: 'member', - address: 'member@whiteout.io' - }], - to: [{ - name: 'member', - address: 'member' - }, { - name: 'notamember', - address: 'notamember' - }], - cc: [], - bcc: [] - }; - - keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey); - keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey); - keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(); - - devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); - - outbox.put(mail, function(error) { - expect(error).to.not.exist; - - expect(mail.publicKeysArmored.length).to.equal(2); - expect(emailDaoStub.encrypt.called).to.be.false; - expect(devicestorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - - it('should not encrypt a mail with bcc and store a mail', function(done) { - var mail; - - mail = { - from: [{ - name: 'member', - address: 'member@whiteout.io' - }], - to: [{ - name: 'member', - address: 'member@whiteout.io' - }], - cc: [], - bcc: [{ - name: 'member', - address: 'member@whiteout.io' - }] - }; - - devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); - - outbox.put(mail, function(error) { - expect(error).to.not.exist; - - expect(mail.publicKeysArmored.length).to.equal(0); - expect(keychainStub.getReceiverPublicKey.called).to.be.false; - expect(emailDaoStub.encrypt.called).to.be.false; - expect(devicestorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - - it('should encrypt and store a mail', function(done) { - var mail, senderKey, receiverKey; - - senderKey = { - publicKey: 'SENDER PUBLIC KEY' - }; - receiverKey = { - publicKey: 'RECEIVER PUBLIC KEY' - }; - mail = { - from: [{ - name: 'member', - address: 'member@whiteout.io' - }], - to: [{ - name: 'member', - address: 'member' - }, { - name: 'notamember', - address: 'notamember' - }], - cc: [], - bcc: [] - }; - - keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey); - keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey); - keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(null, receiverKey); - - emailDaoStub.encrypt.withArgs({ - mail: mail, - publicKeysArmored: [senderKey.publicKey, receiverKey.publicKey, receiverKey.publicKey] - }).yieldsAsync(); - - devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); - - outbox.put(mail, function(error) { - expect(error).to.not.exist; - - expect(mail.publicKeysArmored.length).to.equal(3); - expect(emailDaoStub.encrypt.calledOnce).to.be.true; - expect(devicestorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - }); - - describe('process outbox', function() { - it('should send to registered users and update pending mails', function(done) { - var from, member, invited, notinvited, newlyjoined, dummyMails, newlyjoinedKey; - - from = [{ + receiverKey = { + publicKey: 'RECEIVER PUBLIC KEY' + }; + mail = { + from: [{ name: 'member', address: 'member@whiteout.io' - }]; - member = { - id: '12', - from: from, - to: [{ - name: 'member', - address: 'member' - }], - encrypted: true, - publicKeysArmored: ['ARMORED KEY OF MEMBER'], - unregisteredUsers: [] - }; - invited = { - id: '34', - from: from, - to: [{ - name: 'invited', - address: 'invited' - }], - publicKeysArmored: [], - unregisteredUsers: [{ - name: 'invited', - address: 'invited' - }] - }; - notinvited = { - id: '56', - from: from, - to: [{ - name: 'notinvited', - address: 'notinvited' - }], - publicKeysArmored: [], - unregisteredUsers: [{ - name: 'notinvited', - address: 'notinvited' - }] - }; - newlyjoined = { - id: '78', - from: from, - to: [{ - name: 'newlyjoined', - address: 'newlyjoined' - }], - encrypted: true, - publicKeysArmored: [], - unregisteredUsers: [{ - name: 'newlyjoined', - address: 'newlyjoined' - }] - }; - newlyjoinedKey = { - publicKey: 'THIS IS THE NEWLY JOINED PUBLIC KEY!' - }; + }], + to: [{ + name: 'member', + address: 'member' + }, { + name: 'notamember', + address: 'notamember' + }], + cc: [], + bcc: [] + }; - dummyMails = [member, invited, notinvited, newlyjoined]; + keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey); + keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey); + keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(); - devicestorageStub.listItems.yieldsAsync(null, dummyMails); + devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); - emailDaoStub.sendPlaintext.yieldsAsync(); + outbox.put(mail, function(error) { + expect(error).to.not.exist; - emailDaoStub.sendEncrypted.withArgs({ - email: newlyjoined - }).yieldsAsync(); + expect(mail.publicKeysArmored.length).to.equal(2); + expect(emailDaoStub.encrypt.called).to.be.false; + expect(devicestorageStub.storeList.calledOnce).to.be.true; - emailDaoStub.sendEncrypted.withArgs({ - email: member - }).yieldsAsync(); - - devicestorageStub.removeList.yieldsAsync(); - - function onOutboxUpdate(err, count) { - expect(err).to.not.exist; - expect(count).to.equal(0); - - expect(outbox._outboxBusy).to.be.false; - expect(emailDaoStub.sendEncrypted.callCount).to.equal(2); - expect(emailDaoStub.sendPlaintext.callCount).to.equal(2); - expect(devicestorageStub.listItems.callCount).to.equal(1); - expect(devicestorageStub.removeList.callCount).to.equal(4); - expect(keychainStub.getReceiverPublicKey.callCount).to.equal(0); - - done(); - } - - outbox._processOutbox(onOutboxUpdate); + done(); }); + }); - it('should not process outbox in offline mode', function(done) { - emailDaoStub._account.online = false; - devicestorageStub.listItems.yieldsAsync(null, [{}]); + it('should not encrypt a mail with bcc and store a mail', function(done) { + var mail; - outbox._processOutbox(function(err, count) { - expect(err).to.not.exist; - expect(count).to.equal(1); - expect(devicestorageStub.listItems.callCount).to.equal(1); - expect(outbox._outboxBusy).to.be.false; - done(); - }); + mail = { + from: [{ + name: 'member', + address: 'member@whiteout.io' + }], + to: [{ + name: 'member', + address: 'member@whiteout.io' + }], + cc: [], + bcc: [{ + name: 'member', + address: 'member@whiteout.io' + }] + }; + + devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); + + outbox.put(mail, function(error) { + expect(error).to.not.exist; + + expect(mail.publicKeysArmored.length).to.equal(0); + expect(keychainStub.getReceiverPublicKey.called).to.be.false; + expect(emailDaoStub.encrypt.called).to.be.false; + expect(devicestorageStub.storeList.calledOnce).to.be.true; + + done(); + }); + }); + + it('should encrypt and store a mail', function(done) { + var mail, senderKey, receiverKey; + + senderKey = { + publicKey: 'SENDER PUBLIC KEY' + }; + receiverKey = { + publicKey: 'RECEIVER PUBLIC KEY' + }; + mail = { + from: [{ + name: 'member', + address: 'member@whiteout.io' + }], + to: [{ + name: 'member', + address: 'member' + }, { + name: 'notamember', + address: 'notamember' + }], + cc: [], + bcc: [] + }; + + keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey); + keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey); + keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(null, receiverKey); + + emailDaoStub.encrypt.withArgs({ + mail: mail, + publicKeysArmored: [senderKey.publicKey, receiverKey.publicKey, receiverKey.publicKey] + }).yieldsAsync(); + + devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); + + outbox.put(mail, function(error) { + expect(error).to.not.exist; + + expect(mail.publicKeysArmored.length).to.equal(3); + expect(emailDaoStub.encrypt.calledOnce).to.be.true; + expect(devicestorageStub.storeList.calledOnce).to.be.true; + + done(); + }); + }); + }); + + describe('process outbox', function() { + it('should send to registered users and update pending mails', function(done) { + var from, member, invited, notinvited, newlyjoined, dummyMails, newlyjoinedKey; + + from = [{ + name: 'member', + address: 'member@whiteout.io' + }]; + member = { + id: '12', + from: from, + to: [{ + name: 'member', + address: 'member' + }], + encrypted: true, + publicKeysArmored: ['ARMORED KEY OF MEMBER'], + unregisteredUsers: [] + }; + invited = { + id: '34', + from: from, + to: [{ + name: 'invited', + address: 'invited' + }], + publicKeysArmored: [], + unregisteredUsers: [{ + name: 'invited', + address: 'invited' + }] + }; + notinvited = { + id: '56', + from: from, + to: [{ + name: 'notinvited', + address: 'notinvited' + }], + publicKeysArmored: [], + unregisteredUsers: [{ + name: 'notinvited', + address: 'notinvited' + }] + }; + newlyjoined = { + id: '78', + from: from, + to: [{ + name: 'newlyjoined', + address: 'newlyjoined' + }], + encrypted: true, + publicKeysArmored: [], + unregisteredUsers: [{ + name: 'newlyjoined', + address: 'newlyjoined' + }] + }; + newlyjoinedKey = { + publicKey: 'THIS IS THE NEWLY JOINED PUBLIC KEY!' + }; + + dummyMails = [member, invited, notinvited, newlyjoined]; + + devicestorageStub.listItems.yieldsAsync(null, dummyMails); + + emailDaoStub.sendPlaintext.yieldsAsync(); + + emailDaoStub.sendEncrypted.withArgs({ + email: newlyjoined + }).yieldsAsync(); + + emailDaoStub.sendEncrypted.withArgs({ + email: member + }).yieldsAsync(); + + devicestorageStub.removeList.yieldsAsync(); + + function onOutboxUpdate(err, count) { + expect(err).to.not.exist; + expect(count).to.equal(0); + + expect(outbox._outboxBusy).to.be.false; + expect(emailDaoStub.sendEncrypted.callCount).to.equal(2); + expect(emailDaoStub.sendPlaintext.callCount).to.equal(2); + expect(devicestorageStub.listItems.callCount).to.equal(1); + expect(devicestorageStub.removeList.callCount).to.equal(4); + expect(keychainStub.getReceiverPublicKey.callCount).to.equal(0); + + done(); + } + + outbox._processOutbox(onOutboxUpdate); + }); + + it('should not process outbox in offline mode', function(done) { + emailDaoStub._account.online = false; + devicestorageStub.listItems.yieldsAsync(null, [{}]); + + outbox._processOutbox(function(err, count) { + expect(err).to.not.exist; + expect(count).to.equal(1); + expect(devicestorageStub.listItems.callCount).to.equal(1); + expect(outbox._outboxBusy).to.be.false; + done(); }); }); }); diff --git a/test/unit/pgp-test.js b/test/unit/pgp-test.js index 982eda7..e0a01f1 100644 --- a/test/unit/pgp-test.js +++ b/test/unit/pgp-test.js @@ -1,464 +1,460 @@ -define(function(require) { - 'use strict'; +'use strict'; - var PGP = require('js/crypto/pgp'), - openpgp = require('openpgp'), - expect = chai.expect; +var PGP = require('../../src/js/crypto/pgp'); - describe('PGP Crypto Api unit tests', function() { - this.timeout(20000); +describe('PGP Crypto Api unit tests', function() { + this.timeout(20000); - var pgp, - user = 'whiteout.test@t-online.de', - passphrase = 'asdf', - keySize = 512, - keyId = 'F6F60E9B42CDFF4C', - pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' + - 'Version: OpenPGP.js v0.7.2\r\n' + - 'Comment: Whiteout Mail - https://whiteout.io\r\n' + - '\r\n' + - 'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' + - 'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\r\n' + - 'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\r\n' + - 'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\r\n' + - 'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' + - '=6XMW\r\n' + - '-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n', - privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n' + - 'Version: OpenPGP.js v0.7.2\r\n' + - 'Comment: Whiteout Mail - https://whiteout.io\r\n' + - '\r\n' + - 'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\r\n' + - 'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\r\n' + - 'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\r\n' + - 'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\r\n' + - 'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\r\n' + - 'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\r\n' + - 'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\r\n' + - 'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\r\n' + - 'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\r\n' + - 'IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' + - '=ULta\r\n' + - '-----END PGP PRIVATE KEY BLOCK-----\r\n'; + var pgp, + user = 'whiteout.test@t-online.de', + passphrase = 'asdf', + keySize = 512, + keyId = 'F6F60E9B42CDFF4C', + pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' + + 'Version: OpenPGP.js v0.7.2\r\n' + + 'Comment: Whiteout Mail - https://whiteout.io\r\n' + + '\r\n' + + 'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' + + 'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\r\n' + + 'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\r\n' + + 'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\r\n' + + 'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' + + '=6XMW\r\n' + + '-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n', + privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n' + + 'Version: OpenPGP.js v0.7.2\r\n' + + 'Comment: Whiteout Mail - https://whiteout.io\r\n' + + '\r\n' + + 'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\r\n' + + 'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\r\n' + + 'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\r\n' + + 'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\r\n' + + 'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\r\n' + + 'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\r\n' + + 'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\r\n' + + 'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\r\n' + + 'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\r\n' + + 'IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' + + '=ULta\r\n' + + '-----END PGP PRIVATE KEY BLOCK-----\r\n'; - beforeEach(function() { - pgp = new PGP(); + beforeEach(function() { + pgp = new PGP(); + }); + + afterEach(function() {}); + + describe('Generate key pair', function() { + it('should fail', function(done) { + pgp.generateKeys({ + emailAddress: 'whiteout.test@t-onlinede', + keySize: keySize, + passphrase: passphrase + }, function(err, keys) { + expect(err).to.exist; + expect(keys).to.not.exist; + done(); + }); }); - - afterEach(function() {}); - - describe('Generate key pair', function() { - it('should fail', function(done) { - pgp.generateKeys({ - emailAddress: 'whiteout.test@t-onlinede', - keySize: keySize, - passphrase: passphrase - }, function(err, keys) { - expect(err).to.exist; - expect(keys).to.not.exist; - done(); - }); + it('should fail', function(done) { + pgp.generateKeys({ + emailAddress: 'whiteout.testt-online.de', + keySize: keySize, + passphrase: passphrase + }, function(err, keys) { + expect(err).to.exist; + expect(keys).to.not.exist; + done(); }); - it('should fail', function(done) { - pgp.generateKeys({ - emailAddress: 'whiteout.testt-online.de', - keySize: keySize, - passphrase: passphrase - }, function(err, keys) { - expect(err).to.exist; - expect(keys).to.not.exist; - done(); - }); - }); - it('should work with passphrase', function(done) { - pgp.generateKeys({ - emailAddress: user, - keySize: keySize, - passphrase: passphrase - }, function(err, keys) { + }); + it('should work with passphrase', function(done) { + pgp.generateKeys({ + emailAddress: user, + keySize: keySize, + passphrase: passphrase + }, function(err, keys) { + expect(err).to.not.exist; + expect(keys.keyId).to.exist; + expect(keys.privateKeyArmored).to.exist; + expect(keys.publicKeyArmored).to.exist; + + // test encrypt/decrypt + pgp.importKeys({ + passphrase: passphrase, + privateKeyArmored: keys.privateKeyArmored, + publicKeyArmored: keys.publicKeyArmored + }, function(err) { expect(err).to.not.exist; - expect(keys.keyId).to.exist; - expect(keys.privateKeyArmored).to.exist; - expect(keys.publicKeyArmored).to.exist; - // test encrypt/decrypt - pgp.importKeys({ - passphrase: passphrase, - privateKeyArmored: keys.privateKeyArmored, - publicKeyArmored: keys.publicKeyArmored - }, function(err) { + pgp.encrypt('secret', [keys.publicKeyArmored], function(err, ct) { expect(err).to.not.exist; + expect(ct).to.exist; - pgp.encrypt('secret', [keys.publicKeyArmored], function(err, ct) { + pgp.decrypt(ct, keys.publicKeyArmored, function(err, pt, signValid) { expect(err).to.not.exist; - expect(ct).to.exist; - - pgp.decrypt(ct, keys.publicKeyArmored, function(err, pt, signValid) { - expect(err).to.not.exist; - expect(pt).to.equal('secret'); - expect(signValid).to.be.true; - done(); - }); - }); - }); - }); - }); - it('should work without passphrase', function(done) { - pgp.generateKeys({ - emailAddress: user, - keySize: keySize, - passphrase: '' - }, function(err, keys) { - expect(err).to.not.exist; - expect(keys.keyId).to.exist; - expect(keys.privateKeyArmored).to.exist; - expect(keys.publicKeyArmored).to.exist; - - // test encrypt/decrypt - pgp.importKeys({ - passphrase: undefined, - privateKeyArmored: keys.privateKeyArmored, - publicKeyArmored: keys.publicKeyArmored - }, function(err) { - expect(err).to.not.exist; - - pgp.encrypt('secret', [keys.publicKeyArmored], function(err, ct) { - expect(err).to.not.exist; - expect(ct).to.exist; - - pgp.decrypt(ct, keys.publicKeyArmored, function(err, pt, signValid) { - expect(err).to.not.exist; - expect(pt).to.equal('secret'); - expect(signValid).to.be.true; - done(); - }); + expect(pt).to.equal('secret'); + expect(signValid).to.be.true; + done(); }); }); }); }); }); + it('should work without passphrase', function(done) { + pgp.generateKeys({ + emailAddress: user, + keySize: keySize, + passphrase: '' + }, function(err, keys) { + expect(err).to.not.exist; + expect(keys.keyId).to.exist; + expect(keys.privateKeyArmored).to.exist; + expect(keys.publicKeyArmored).to.exist; - describe('Import/Export key pair', function() { - it('should fail', function(done) { + // test encrypt/decrypt pgp.importKeys({ - passphrase: 'asd', - privateKeyArmored: privkey, - publicKeyArmored: pubkey - }, function(err) { - expect(err).to.exist; - expect(err.message).to.equal('Incorrect passphrase!'); - - pgp.exportKeys(function(err, keys) { - expect(err).to.exist; - expect(keys).to.not.exist; - done(); - }); - }); - }); - it('should work', function(done) { - pgp.importKeys({ - passphrase: passphrase, - privateKeyArmored: privkey, - publicKeyArmored: pubkey + passphrase: undefined, + privateKeyArmored: keys.privateKeyArmored, + publicKeyArmored: keys.publicKeyArmored }, function(err) { expect(err).to.not.exist; - pgp.exportKeys(function(err, keys) { - expect(err).to.not.exist; - expect(keys.keyId).to.equal(keyId); - expect(keys.privateKeyArmored.replace(/\r/g, '')).to.equal(privkey.replace(/\r/g, '')); - expect(keys.publicKeyArmored.replace(/\r/g, '')).to.equal(pubkey.replace(/\r/g, '')); - done(); - }); - }); - }); - }); - - describe('Change passphrase of private key', function() { - it('should work with new passphrase', function(done) { - pgp.changePassphrase({ - privateKeyArmored: privkey, - oldPassphrase: passphrase, - newPassphrase: 'yxcv' - }, function(err, reEncryptedKey) { - expect(err).to.not.exist; - expect(reEncryptedKey).to.exist; - - pgp.importKeys({ - passphrase: 'yxcv', - privateKeyArmored: reEncryptedKey, - publicKeyArmored: pubkey - }, function(err) { - expect(err).to.not.exist; - done(); - }); - }); - }); - it('should work with empty passphrase', function(done) { - pgp.changePassphrase({ - privateKeyArmored: privkey, - oldPassphrase: passphrase, - newPassphrase: undefined - }, function(err, reEncryptedKey) { - expect(err).to.not.exist; - expect(reEncryptedKey).to.exist; - - pgp.importKeys({ - passphrase: undefined, - privateKeyArmored: reEncryptedKey, - publicKeyArmored: pubkey - }, function(err) { - expect(err).to.not.exist; - done(); - }); - }); - }); - it('should fail when passphrases are equal', function(done) { - pgp.changePassphrase({ - privateKeyArmored: privkey, - oldPassphrase: passphrase, - newPassphrase: passphrase - }, function(err, reEncryptedKey) { - expect(err).to.exist; - expect(reEncryptedKey).to.not.exist; - done(); - }); - }); - it('should fail when old passphrase is incorrect', function(done) { - pgp.changePassphrase({ - privateKeyArmored: privkey, - oldPassphrase: 'asd', - newPassphrase: 'yxcv' - }, function(err, reEncryptedKey) { - expect(err).to.exist; - expect(reEncryptedKey).to.not.exist; - done(); - }); - }); - }); - - describe('Encrypt/Sign/Decrypt/Verify', function() { - var message = 'asdfs\n\nThursday, Nov 21, 2013 7:38 PM asdf@example.com wrote:\n' + - '> asdf\n' + - '> \n' + - '> Thursday, Nov 21, 2013 7:32 PM asdf@example.com wrote:\n' + - '> > secret 3'; - var wrongPubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - http://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----'; - - beforeEach(function(done) { - pgp.importKeys({ - passphrase: passphrase, - privateKeyArmored: privkey, - publicKeyArmored: pubkey - }, function(err) { - expect(err).to.not.exist; - done(); - }); - }); - - describe('Get KeyId', function() { - it('should work without param', function() { - var keyId = pgp.getKeyId(); - expect(keyId).to.equal('F6F60E9B42CDFF4C'); - }); - it('should work with param', function() { - var keyId = pgp.getKeyId(pubkey); - expect(keyId).to.equal('F6F60E9B42CDFF4C'); - }); - }); - - describe('Get Fingerprint', function() { - it('should work without param', function() { - var fingerprint = pgp.getFingerprint(); - expect(fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C'); - }); - it('should work with param', function() { - var fingerprint = pgp.getFingerprint(pubkey); - expect(fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C'); - }); - }); - - describe('getKeyParams', function() { - it('should work with param', function() { - var params = pgp.getKeyParams(pubkey); - expect(params.fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C'); - expect(params._id).to.equal("F6F60E9B42CDFF4C"); - expect(params.bitSize).to.equal(keySize); - expect(params.userId).to.equal("whiteout.test@t-online.de"); - expect(params.userIds[0].name).to.equal("Whiteout User"); - expect(params.userIds[0].emailAddress).to.equal("whiteout.test@t-online.de"); - expect(params.algorithm).to.equal("rsa_encrypt_sign"); - }); - - it('should work without param', function() { - var params = pgp.getKeyParams(); - expect(params.fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C'); - expect(params._id).to.equal("F6F60E9B42CDFF4C"); - expect(params.bitSize).to.equal(keySize); - expect(params.userId).to.equal("whiteout.test@t-online.de"); - expect(params.userIds[0].name).to.equal("Whiteout User"); - expect(params.userIds[0].emailAddress).to.equal("whiteout.test@t-online.de"); - expect(params.algorithm).to.equal("rsa_encrypt_sign"); - }); - }); - - describe('extractPublicKey', function() { - it('should work', function() { - var pk = pgp.extractPublicKey(privkey); - expect(pk).to.exist; - expect(pk).to.contain('-----BEGIN PGP PUBLIC KEY BLOCK-----'); - }); - }); - - describe('Encrypt and sign', function() { - it('should fail', function(done) { - var input = null; - - pgp.encrypt(input, [pubkey], function(err, ct) { - expect(err).to.exist; - expect(ct).to.not.exist; - done(); - }); - }); - it('should work', function(done) { - pgp.encrypt(message, [pubkey], function(err, ct) { + pgp.encrypt('secret', [keys.publicKeyArmored], function(err, ct) { expect(err).to.not.exist; expect(ct).to.exist; - done(); - }); - }); - it('should encrypt to myself if public keys are empty', function(done) { - pgp.encrypt(message, undefined, function(err, ct) { - expect(err).to.not.exist; - expect(ct).to.exist; - done(); - }); - }); - }); - describe('Decrypt and verify', function() { - var ciphertext; - - beforeEach(function(done) { - pgp.encrypt(message, [pubkey], function(err, ct) { - expect(err).to.not.exist; - expect(ct).to.exist; - ciphertext = ct; - done(); - }); - }); - - it('should fail', function(done) { - var input = 'asdfa\rsdf'; - - pgp.decrypt(input, pubkey, function(err, pt) { - expect(err).to.exist; - expect(pt).to.not.exist; - done(); - }); - }); - it('should work', function(done) { - pgp.decrypt(ciphertext, pubkey, function(err, pt, signValid) { - expect(err).to.not.exist; - expect(pt).to.equal(message); - expect(signValid).to.be.true; - done(); - }); - }); - it('should work without signature', function(done) { - var ct = openpgp.encryptMessage([pgp._publicKey], message); - - pgp.decrypt(ct, undefined, function(err, pt, signValid) { - expect(err).to.not.exist; - expect(pt).to.equal(message); - expect(signValid).to.be.undefined; - done(); - }); - }); - it('should fail to verify if public keys are empty', function(done) { - // setup another public key so that signature verification fails - pgp._publicKey = openpgp.key.readArmored(wrongPubkey).keys[0]; - pgp.decrypt(ciphertext, undefined, function(err, pt, signValid) { - expect(err).to.not.exist; - expect(pt).to.equal(message); - expect(signValid).to.be.null; - done(); - }); - }); - it('should decrypt but signValid should be null for wrong public key', function(done) { - pgp.decrypt(ciphertext, wrongPubkey, function(err, pt, signValid) { - expect(err).to.not.exist; - expect(pt).to.equal(message); - expect(signValid).to.be.null; - done(); - }); - }); - }); - - describe('Verify clearsigned message', function() { - var clearsigned; - - beforeEach(function() { - clearsigned = openpgp.signClearMessage(pgp._privateKey, 'this is a clearsigned message'); - }); - - it('should work', function(done) { - pgp.verifyClearSignedMessage(clearsigned, pubkey, function(err, signaturesValid) { - expect(err).to.not.exist; - expect(signaturesValid).to.be.true; - done(); - }); - }); - - it('should fail', function(done) { - pgp.verifyClearSignedMessage(clearsigned.replace('clearsigned', 'invalid'), pubkey, function(err, signaturesValid) { - expect(err).to.not.exist; - expect(signaturesValid).to.be.false; - done(); - }); - }); - it('should be null for wrong public key', function(done) { - pgp.verifyClearSignedMessage(clearsigned, wrongPubkey, function(err, signaturesValid) { - expect(err).to.not.exist; - expect(signaturesValid).to.be.null; - done(); - }); - }); - }); - - describe('Verify detached signature', function() { - var signedMessage, signature; - - beforeEach(function() { - signedMessage = 'this is a signed message'; - var clearsigned = openpgp.signClearMessage(pgp._privateKey, signedMessage); - var signatureHeader = '-----BEGIN PGP SIGNATURE-----'; - signature = signatureHeader + clearsigned.split(signatureHeader).pop(); - }); - - it('should work', function(done) { - pgp.verifySignedMessage(signedMessage, signature, pubkey, function(err, signaturesValid) { - expect(err).to.not.exist; - expect(signaturesValid).to.be.true; - done(); - }); - }); - - it('should fail', function(done) { - pgp.verifySignedMessage(signedMessage.replace('signed', 'invalid'), signature, pubkey, function(err, signaturesValid) { - expect(err).to.not.exist; - expect(signaturesValid).to.be.false; - done(); - }); - }); - it('should be null for wrong public key', function(done) { - pgp.verifySignedMessage(signedMessage, signature, wrongPubkey, function(err, signaturesValid) { - expect(err).to.not.exist; - expect(signaturesValid).to.be.null; - done(); + pgp.decrypt(ct, keys.publicKeyArmored, function(err, pt, signValid) { + expect(err).to.not.exist; + expect(pt).to.equal('secret'); + expect(signValid).to.be.true; + done(); + }); }); }); }); }); }); + + describe('Import/Export key pair', function() { + it('should fail', function(done) { + pgp.importKeys({ + passphrase: 'asd', + privateKeyArmored: privkey, + publicKeyArmored: pubkey + }, function(err) { + expect(err).to.exist; + expect(err.message).to.equal('Incorrect passphrase!'); + + pgp.exportKeys(function(err, keys) { + expect(err).to.exist; + expect(keys).to.not.exist; + done(); + }); + }); + }); + it('should work', function(done) { + pgp.importKeys({ + passphrase: passphrase, + privateKeyArmored: privkey, + publicKeyArmored: pubkey + }, function(err) { + expect(err).to.not.exist; + + pgp.exportKeys(function(err, keys) { + expect(err).to.not.exist; + expect(keys.keyId).to.equal(keyId); + expect(keys.privateKeyArmored.replace(/\r/g, '')).to.equal(privkey.replace(/\r/g, '')); + expect(keys.publicKeyArmored.replace(/\r/g, '')).to.equal(pubkey.replace(/\r/g, '')); + done(); + }); + }); + }); + }); + + describe('Change passphrase of private key', function() { + it('should work with new passphrase', function(done) { + pgp.changePassphrase({ + privateKeyArmored: privkey, + oldPassphrase: passphrase, + newPassphrase: 'yxcv' + }, function(err, reEncryptedKey) { + expect(err).to.not.exist; + expect(reEncryptedKey).to.exist; + + pgp.importKeys({ + passphrase: 'yxcv', + privateKeyArmored: reEncryptedKey, + publicKeyArmored: pubkey + }, function(err) { + expect(err).to.not.exist; + done(); + }); + }); + }); + it('should work with empty passphrase', function(done) { + pgp.changePassphrase({ + privateKeyArmored: privkey, + oldPassphrase: passphrase, + newPassphrase: undefined + }, function(err, reEncryptedKey) { + expect(err).to.not.exist; + expect(reEncryptedKey).to.exist; + + pgp.importKeys({ + passphrase: undefined, + privateKeyArmored: reEncryptedKey, + publicKeyArmored: pubkey + }, function(err) { + expect(err).to.not.exist; + done(); + }); + }); + }); + it('should fail when passphrases are equal', function(done) { + pgp.changePassphrase({ + privateKeyArmored: privkey, + oldPassphrase: passphrase, + newPassphrase: passphrase + }, function(err, reEncryptedKey) { + expect(err).to.exist; + expect(reEncryptedKey).to.not.exist; + done(); + }); + }); + it('should fail when old passphrase is incorrect', function(done) { + pgp.changePassphrase({ + privateKeyArmored: privkey, + oldPassphrase: 'asd', + newPassphrase: 'yxcv' + }, function(err, reEncryptedKey) { + expect(err).to.exist; + expect(reEncryptedKey).to.not.exist; + done(); + }); + }); + }); + + describe('Encrypt/Sign/Decrypt/Verify', function() { + var message = 'asdfs\n\nThursday, Nov 21, 2013 7:38 PM asdf@example.com wrote:\n' + + '> asdf\n' + + '> \n' + + '> Thursday, Nov 21, 2013 7:32 PM asdf@example.com wrote:\n' + + '> > secret 3'; + var wrongPubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - http://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----'; + + beforeEach(function(done) { + pgp.importKeys({ + passphrase: passphrase, + privateKeyArmored: privkey, + publicKeyArmored: pubkey + }, function(err) { + expect(err).to.not.exist; + done(); + }); + }); + + describe('Get KeyId', function() { + it('should work without param', function() { + var keyId = pgp.getKeyId(); + expect(keyId).to.equal('F6F60E9B42CDFF4C'); + }); + it('should work with param', function() { + var keyId = pgp.getKeyId(pubkey); + expect(keyId).to.equal('F6F60E9B42CDFF4C'); + }); + }); + + describe('Get Fingerprint', function() { + it('should work without param', function() { + var fingerprint = pgp.getFingerprint(); + expect(fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C'); + }); + it('should work with param', function() { + var fingerprint = pgp.getFingerprint(pubkey); + expect(fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C'); + }); + }); + + describe('getKeyParams', function() { + it('should work with param', function() { + var params = pgp.getKeyParams(pubkey); + expect(params.fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C'); + expect(params._id).to.equal("F6F60E9B42CDFF4C"); + expect(params.bitSize).to.equal(keySize); + expect(params.userId).to.equal("whiteout.test@t-online.de"); + expect(params.userIds[0].name).to.equal("Whiteout User"); + expect(params.userIds[0].emailAddress).to.equal("whiteout.test@t-online.de"); + expect(params.algorithm).to.equal("rsa_encrypt_sign"); + }); + + it('should work without param', function() { + var params = pgp.getKeyParams(); + expect(params.fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C'); + expect(params._id).to.equal("F6F60E9B42CDFF4C"); + expect(params.bitSize).to.equal(keySize); + expect(params.userId).to.equal("whiteout.test@t-online.de"); + expect(params.userIds[0].name).to.equal("Whiteout User"); + expect(params.userIds[0].emailAddress).to.equal("whiteout.test@t-online.de"); + expect(params.algorithm).to.equal("rsa_encrypt_sign"); + }); + }); + + describe('extractPublicKey', function() { + it('should work', function() { + var pk = pgp.extractPublicKey(privkey); + expect(pk).to.exist; + expect(pk).to.contain('-----BEGIN PGP PUBLIC KEY BLOCK-----'); + }); + }); + + describe('Encrypt and sign', function() { + it('should fail', function(done) { + var input = null; + + pgp.encrypt(input, [pubkey], function(err, ct) { + expect(err).to.exist; + expect(ct).to.not.exist; + done(); + }); + }); + it('should work', function(done) { + pgp.encrypt(message, [pubkey], function(err, ct) { + expect(err).to.not.exist; + expect(ct).to.exist; + done(); + }); + }); + it('should encrypt to myself if public keys are empty', function(done) { + pgp.encrypt(message, undefined, function(err, ct) { + expect(err).to.not.exist; + expect(ct).to.exist; + done(); + }); + }); + }); + + describe('Decrypt and verify', function() { + var ciphertext; + + beforeEach(function(done) { + pgp.encrypt(message, [pubkey], function(err, ct) { + expect(err).to.not.exist; + expect(ct).to.exist; + ciphertext = ct; + done(); + }); + }); + + it('should fail', function(done) { + var input = 'asdfa\rsdf'; + + pgp.decrypt(input, pubkey, function(err, pt) { + expect(err).to.exist; + expect(pt).to.not.exist; + done(); + }); + }); + it('should work', function(done) { + pgp.decrypt(ciphertext, pubkey, function(err, pt, signValid) { + expect(err).to.not.exist; + expect(pt).to.equal(message); + expect(signValid).to.be.true; + done(); + }); + }); + it('should work without signature', function(done) { + var ct = openpgp.encryptMessage([pgp._publicKey], message); + + pgp.decrypt(ct, undefined, function(err, pt, signValid) { + expect(err).to.not.exist; + expect(pt).to.equal(message); + expect(signValid).to.be.undefined; + done(); + }); + }); + it('should fail to verify if public keys are empty', function(done) { + // setup another public key so that signature verification fails + pgp._publicKey = openpgp.key.readArmored(wrongPubkey).keys[0]; + pgp.decrypt(ciphertext, undefined, function(err, pt, signValid) { + expect(err).to.not.exist; + expect(pt).to.equal(message); + expect(signValid).to.be.null; + done(); + }); + }); + it('should decrypt but signValid should be null for wrong public key', function(done) { + pgp.decrypt(ciphertext, wrongPubkey, function(err, pt, signValid) { + expect(err).to.not.exist; + expect(pt).to.equal(message); + expect(signValid).to.be.null; + done(); + }); + }); + }); + + describe('Verify clearsigned message', function() { + var clearsigned; + + beforeEach(function() { + clearsigned = openpgp.signClearMessage(pgp._privateKey, 'this is a clearsigned message'); + }); + + it('should work', function(done) { + pgp.verifyClearSignedMessage(clearsigned, pubkey, function(err, signaturesValid) { + expect(err).to.not.exist; + expect(signaturesValid).to.be.true; + done(); + }); + }); + + it('should fail', function(done) { + pgp.verifyClearSignedMessage(clearsigned.replace('clearsigned', 'invalid'), pubkey, function(err, signaturesValid) { + expect(err).to.not.exist; + expect(signaturesValid).to.be.false; + done(); + }); + }); + it('should be null for wrong public key', function(done) { + pgp.verifyClearSignedMessage(clearsigned, wrongPubkey, function(err, signaturesValid) { + expect(err).to.not.exist; + expect(signaturesValid).to.be.null; + done(); + }); + }); + }); + + describe('Verify detached signature', function() { + var signedMessage, signature; + + beforeEach(function() { + signedMessage = 'this is a signed message'; + var clearsigned = openpgp.signClearMessage(pgp._privateKey, signedMessage); + var signatureHeader = '-----BEGIN PGP SIGNATURE-----'; + signature = signatureHeader + clearsigned.split(signatureHeader).pop(); + }); + + it('should work', function(done) { + pgp.verifySignedMessage(signedMessage, signature, pubkey, function(err, signaturesValid) { + expect(err).to.not.exist; + expect(signaturesValid).to.be.true; + done(); + }); + }); + + it('should fail', function(done) { + pgp.verifySignedMessage(signedMessage.replace('signed', 'invalid'), signature, pubkey, function(err, signaturesValid) { + expect(err).to.not.exist; + expect(signaturesValid).to.be.false; + done(); + }); + }); + it('should be null for wrong public key', function(done) { + pgp.verifySignedMessage(signedMessage, signature, wrongPubkey, function(err, signaturesValid) { + expect(err).to.not.exist; + expect(signaturesValid).to.be.null; + done(); + }); + }); + }); + }); }); \ No newline at end of file diff --git a/test/unit/privatekey-dao-test.js b/test/unit/privatekey-dao-test.js index 7092cfa..63bcd3c 100644 --- a/test/unit/privatekey-dao-test.js +++ b/test/unit/privatekey-dao-test.js @@ -1,226 +1,222 @@ -define(function(require) { - 'use strict'; +'use strict'; - var RestDAO = require('js/dao/rest-dao'), - PrivateKeyDAO = require('js/dao/privatekey-dao'), - expect = chai.expect; +var RestDAO = require('../../src/js/dao/rest-dao'), + PrivateKeyDAO = require('../../src/js/dao/privatekey-dao'); - describe('Private Key DAO unit tests', function() { +describe('Private Key DAO unit tests', function() { - var privkeyDao, restDaoStub, - emailAddress = 'test@example.com', - deviceName = 'iPhone Work'; + var privkeyDao, restDaoStub, + emailAddress = 'test@example.com', + deviceName = 'iPhone Work'; - beforeEach(function() { - restDaoStub = sinon.createStubInstance(RestDAO); - privkeyDao = new PrivateKeyDAO(restDaoStub); - }); + beforeEach(function() { + restDaoStub = sinon.createStubInstance(RestDAO); + privkeyDao = new PrivateKeyDAO(restDaoStub); + }); - afterEach(function() {}); + afterEach(function() {}); - describe('requestDeviceRegistration', function() { - it('should fail due to invalid args', function(done) { - privkeyDao.requestDeviceRegistration({}, function(err, sessionKey) { - expect(err).to.exist; - expect(sessionKey).to.not.exist; - done(); - }); - }); - - it('should work', function(done) { - restDaoStub.post.yields(null, { - encryptedRegSessionKey: 'asdf' - }); - - privkeyDao.requestDeviceRegistration({ - userId: emailAddress, - deviceName: deviceName - }, function(err, sessionKey) { - expect(err).to.not.exist; - expect(sessionKey).to.exist; - done(); - }); + describe('requestDeviceRegistration', function() { + it('should fail due to invalid args', function(done) { + privkeyDao.requestDeviceRegistration({}, function(err, sessionKey) { + expect(err).to.exist; + expect(sessionKey).to.not.exist; + done(); }); }); - describe('uploadDeviceSecret', function() { - it('should fail due to invalid args', function(done) { - privkeyDao.uploadDeviceSecret({}, function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + restDaoStub.post.yields(null, { + encryptedRegSessionKey: 'asdf' }); - it('should work', function(done) { - restDaoStub.put.yields(); + privkeyDao.requestDeviceRegistration({ + userId: emailAddress, + deviceName: deviceName + }, function(err, sessionKey) { + expect(err).to.not.exist; + expect(sessionKey).to.exist; + done(); + }); + }); + }); - privkeyDao.uploadDeviceSecret({ - userId: emailAddress, - deviceName: deviceName, - encryptedDeviceSecret: 'asdf', - iv: 'iv' - }, function(err) { - expect(err).to.not.exist; - done(); - }); + describe('uploadDeviceSecret', function() { + it('should fail due to invalid args', function(done) { + privkeyDao.uploadDeviceSecret({}, function(err) { + expect(err).to.exist; + done(); }); }); - describe('requestAuthSessionKey', function() { - it('should fail due to invalid args', function(done) { - privkeyDao.requestAuthSessionKey({}, function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + restDaoStub.put.yields(); + + privkeyDao.uploadDeviceSecret({ + userId: emailAddress, + deviceName: deviceName, + encryptedDeviceSecret: 'asdf', + iv: 'iv' + }, function(err) { + expect(err).to.not.exist; + done(); }); + }); + }); - it('should work', function(done) { - restDaoStub.post.withArgs(undefined, '/auth/user/' + emailAddress).yields(); - - privkeyDao.requestAuthSessionKey({ - userId: emailAddress - }, function(err) { - expect(err).to.not.exist; - done(); - }); + describe('requestAuthSessionKey', function() { + it('should fail due to invalid args', function(done) { + privkeyDao.requestAuthSessionKey({}, function(err) { + expect(err).to.exist; + done(); }); }); - describe('verifyAuthentication', function() { - it('should fail due to invalid args', function(done) { - privkeyDao.verifyAuthentication({}, function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + restDaoStub.post.withArgs(undefined, '/auth/user/' + emailAddress).yields(); + + privkeyDao.requestAuthSessionKey({ + userId: emailAddress + }, function(err) { + expect(err).to.not.exist; + done(); }); + }); + }); - it('should work', function(done) { - var sessionId = '1'; - - var options = { - userId: emailAddress, - sessionId: sessionId, - encryptedChallenge: 'asdf', - encryptedDeviceSecret: 'qwer', - iv: ' iv' - }; - - restDaoStub.put.withArgs(options, '/auth/user/' + emailAddress + '/session/' + sessionId).yields(); - - privkeyDao.verifyAuthentication(options, function(err) { - expect(err).to.not.exist; - done(); - }); + describe('verifyAuthentication', function() { + it('should fail due to invalid args', function(done) { + privkeyDao.verifyAuthentication({}, function(err) { + expect(err).to.exist; + done(); }); }); - describe('upload', function() { - it('should fail due to invalid args', function(done) { - privkeyDao.upload({}, function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + var sessionId = '1'; + + var options = { + userId: emailAddress, + sessionId: sessionId, + encryptedChallenge: 'asdf', + encryptedDeviceSecret: 'qwer', + iv: ' iv' + }; + + restDaoStub.put.withArgs(options, '/auth/user/' + emailAddress + '/session/' + sessionId).yields(); + + privkeyDao.verifyAuthentication(options, function(err) { + expect(err).to.not.exist; + done(); }); + }); + }); - it('should work', function(done) { - var options = { - _id: '12345', - userId: emailAddress, - encryptedPrivateKey: 'asdf', - sessionId: '1', - salt: 'salt', - iv: 'iv' - }; - - restDaoStub.post.withArgs(options, '/privatekey/user/' + emailAddress + '/session/' + options.sessionId).yields(); - - privkeyDao.upload(options, function(err) { - expect(err).to.not.exist; - done(); - }); + describe('upload', function() { + it('should fail due to invalid args', function(done) { + privkeyDao.upload({}, function(err) { + expect(err).to.exist; + done(); }); }); - describe('requestDownload', function() { - it('should fail due to invalid args', function(done) { - privkeyDao.requestDownload({}, function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + var options = { + _id: '12345', + userId: emailAddress, + encryptedPrivateKey: 'asdf', + sessionId: '1', + salt: 'salt', + iv: 'iv' + }; + + restDaoStub.post.withArgs(options, '/privatekey/user/' + emailAddress + '/session/' + options.sessionId).yields(); + + privkeyDao.upload(options, function(err) { + expect(err).to.not.exist; + done(); }); + }); + }); - it('should work', function(done) { - var keyId = '12345'; - - restDaoStub.get.withArgs({ - uri: '/privatekey/user/' + emailAddress + '/key/' + keyId - }).yields(); - - privkeyDao.requestDownload({ - userId: emailAddress, - keyId: keyId - }, function(err, found) { - expect(err).to.not.exist; - expect(found).to.be.true; - done(); - }); + describe('requestDownload', function() { + it('should fail due to invalid args', function(done) { + privkeyDao.requestDownload({}, function(err) { + expect(err).to.exist; + done(); }); }); - describe('hasPrivateKey', function() { - it('should fail due to invalid args', function(done) { - privkeyDao.hasPrivateKey({}, function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + var keyId = '12345'; + + restDaoStub.get.withArgs({ + uri: '/privatekey/user/' + emailAddress + '/key/' + keyId + }).yields(); + + privkeyDao.requestDownload({ + userId: emailAddress, + keyId: keyId + }, function(err, found) { + expect(err).to.not.exist; + expect(found).to.be.true; + done(); }); + }); + }); - it('should work', function(done) { - var keyId = '12345'; - - restDaoStub.get.withArgs({ - uri: '/privatekey/user/' + emailAddress + '/key/' + keyId + '?ignoreRecovery=true' - }).yields(); - - privkeyDao.hasPrivateKey({ - userId: emailAddress, - keyId: keyId - }, function(err, found) { - expect(err).to.not.exist; - expect(found).to.be.true; - done(); - }); + describe('hasPrivateKey', function() { + it('should fail due to invalid args', function(done) { + privkeyDao.hasPrivateKey({}, function(err) { + expect(err).to.exist; + done(); }); }); - describe('download', function() { - it('should fail due to invalid args', function(done) { - privkeyDao.download({}, function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + var keyId = '12345'; + + restDaoStub.get.withArgs({ + uri: '/privatekey/user/' + emailAddress + '/key/' + keyId + '?ignoreRecovery=true' + }).yields(); + + privkeyDao.hasPrivateKey({ + userId: emailAddress, + keyId: keyId + }, function(err, found) { + expect(err).to.not.exist; + expect(found).to.be.true; + done(); }); + }); + }); - it('should work', function(done) { - var key = { - _id: '12345' - }; - - restDaoStub.get.withArgs({ - uri: '/privatekey/user/' + emailAddress + '/key/' + key._id + '/recovery/token' - }).yields(); - - privkeyDao.download({ - userId: emailAddress, - keyId: key._id, - recoveryToken: 'token' - }, function(err) { - expect(err).to.not.exist; - done(); - }); + describe('download', function() { + it('should fail due to invalid args', function(done) { + privkeyDao.download({}, function(err) { + expect(err).to.exist; + done(); }); }); + it('should work', function(done) { + var key = { + _id: '12345' + }; + + restDaoStub.get.withArgs({ + uri: '/privatekey/user/' + emailAddress + '/key/' + key._id + '/recovery/token' + }).yields(); + + privkeyDao.download({ + userId: emailAddress, + keyId: key._id, + recoveryToken: 'token' + }, function(err) { + expect(err).to.not.exist; + done(); + }); + }); }); }); \ No newline at end of file diff --git a/test/unit/privatekey-upload-ctrl-test.js b/test/unit/privatekey-upload-ctrl-test.js index 9dbe3e3..b7649a2 100644 --- a/test/unit/privatekey-upload-ctrl-test.js +++ b/test/unit/privatekey-upload-ctrl-test.js @@ -1,286 +1,281 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - PrivateKeyUploadCtrl = require('js/controller/privatekey-upload'), - appController = require('js/app-controller'), - KeychainDAO = require('js/dao/keychain-dao'), - PGP = require('js/crypto/pgp'); +var mocks = angular.mocks, + PrivateKeyUploadCtrl = require('../../src/js/controller/privatekey-upload'), + appController = require('../../src/js/app-controller'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + PGP = require('../../src/js/crypto/pgp'); - describe('Private Key Upload Controller unit test', function() { - var scope, location, ctrl, - origEmailDao, emailDaoMock, - origKeychain, keychainMock, - pgpStub, - emailAddress = 'fred@foo.com'; +describe('Private Key Upload Controller unit test', function() { + var scope, location, ctrl, + origEmailDao, emailDaoMock, + origKeychain, keychainMock, + pgpStub, + emailAddress = 'fred@foo.com'; - beforeEach(function(done) { - // remember original module to restore later, then replace it - origEmailDao = appController._emailDao; - appController._emailDao = emailDaoMock = { - _account: { - emailAddress: emailAddress - } + beforeEach(function(done) { + // remember original module to restore later, then replace it + origEmailDao = appController._emailDao; + appController._emailDao = emailDaoMock = { + _account: { + emailAddress: emailAddress + } + }; + origKeychain = appController._keychain; + appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); + keychainMock._pgp = pgpStub = sinon.createStubInstance(PGP); + + angular.module('login-privatekey-download-test', []); + mocks.module('login-privatekey-download-test'); + mocks.inject(function($controller, $rootScope) { + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(PrivateKeyUploadCtrl, { + $location: location, + $scope: scope + }); + done(); + }); + }); + + afterEach(function() { + // restore the app controller module + appController._keychain = origKeychain; + appController._emailDao = origEmailDao; + }); + + describe('checkServerForKey', function() { + var keyParams = { + userId: emailAddress, + _id: 'keyId', + }; + + it('should fail', function(done) { + pgpStub.getKeyParams.returns(keyParams); + keychainMock.hasPrivateKey.yields(42); + + scope.onError = function(err) { + expect(err).to.exist; + expect(keychainMock.hasPrivateKey.calledOnce).to.be.true; + done(); }; - origKeychain = appController._keychain; - appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); - keychainMock._pgp = pgpStub = sinon.createStubInstance(PGP); - angular.module('login-privatekey-download-test', []); - mocks.module('login-privatekey-download-test'); - mocks.inject(function($controller, $rootScope) { - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(PrivateKeyUploadCtrl, { - $location: location, - $scope: scope - }); + scope.checkServerForKey(); + }); + + it('should return true', function(done) { + pgpStub.getKeyParams.returns(keyParams); + keychainMock.hasPrivateKey.withArgs({ + userId: keyParams.userId, + keyId: keyParams._id + }).yields(null, true); + + scope.checkServerForKey(function(privateKeySynced) { + expect(privateKeySynced).to.be.true; done(); }); }); - afterEach(function() { - // restore the app controller module - appController._keychain = origKeychain; - appController._emailDao = origEmailDao; + it('should return undefined', function(done) { + pgpStub.getKeyParams.returns(keyParams); + keychainMock.hasPrivateKey.withArgs({ + userId: keyParams.userId, + keyId: keyParams._id + }).yields(null, false); + + scope.checkServerForKey(function(privateKeySynced) { + expect(privateKeySynced).to.be.undefined; + done(); + }); + }); + }); + + describe('handlePaste', function() { + it('should work', function() { + scope.handlePaste({ + clipboardData: { + getData: function(val) { + expect(val).to.equal('text/plain'); + return '1qaz-2wsx-3edc-4rfv-5tgb-6yhn'; + } + } + }); + + expect(scope.code0).to.equal('1qaz'); + expect(scope.code1).to.equal('2wsx'); + expect(scope.code2).to.equal('3edc'); + expect(scope.code3).to.equal('4rfv'); + expect(scope.code4).to.equal('5tgb'); + expect(scope.code5).to.equal('6yhn'); + }); + }); + + describe('displayUploadUi', function() { + it('should work', function() { + // add some artifacts from a previous key input + scope.code0 = scope.code1 = scope.code2 = scope.code3 = scope.code4 = scope.code5 = 'asdasd'; + + scope.displayUploadUi(); + expect(scope.step).to.equal(1); + expect(scope.code.length).to.equal(24); + + // artifacts should be cleared + expect(scope.code0).to.be.empty; + expect(scope.code1).to.be.empty; + expect(scope.code2).to.be.empty; + expect(scope.code3).to.be.empty; + expect(scope.code4).to.be.empty; + expect(scope.code5).to.be.empty; + }); + }); + + describe('verifyCode', function() { + it('should fail for wrong code', function() { + scope.code0 = 'b'; + scope.code1 = 'b'; + scope.code2 = 'b'; + scope.code3 = 'b'; + scope.code4 = 'b'; + scope.code5 = 'b'; + scope.code = 'aaaaaa'; + + scope.onError = function() {}; + expect(scope.verifyCode()).to.be.false; }); - describe('checkServerForKey', function() { - var keyParams = { - userId: emailAddress, - _id: 'keyId', + it('should work', function() { + scope.code0 = 'a'; + scope.code1 = 'a'; + scope.code2 = 'a'; + scope.code3 = 'a'; + scope.code4 = 'a'; + scope.code5 = 'a'; + scope.code = 'aaaaaa'; + + scope.onError = function() {}; + expect(scope.verifyCode()).to.be.false; + }); + }); + + describe('setDeviceName', function() { + it('should work', function(done) { + keychainMock.setDeviceName.yields(); + scope.setDeviceName(done); + }); + }); + + describe('encryptAndUploadKey', function() { + it('should fail due to keychain.registerDevice', function(done) { + keychainMock.registerDevice.yields(42); + + scope.onError = function(err) { + expect(err).to.exist; + expect(keychainMock.registerDevice.calledOnce).to.be.true; + done(); }; - it('should fail', function(done) { - pgpStub.getKeyParams.returns(keyParams); - keychainMock.hasPrivateKey.yields(42); - - scope.onError = function(err) { - expect(err).to.exist; - expect(keychainMock.hasPrivateKey.calledOnce).to.be.true; - done(); - }; - - scope.checkServerForKey(); - }); - - it('should return true', function(done) { - pgpStub.getKeyParams.returns(keyParams); - keychainMock.hasPrivateKey.withArgs({ - userId: keyParams.userId, - keyId: keyParams._id - }).yields(null, true); - - scope.checkServerForKey(function(privateKeySynced) { - expect(privateKeySynced).to.be.true; - done(); - }); - }); - - it('should return undefined', function(done) { - pgpStub.getKeyParams.returns(keyParams); - keychainMock.hasPrivateKey.withArgs({ - userId: keyParams.userId, - keyId: keyParams._id - }).yields(null, false); - - scope.checkServerForKey(function(privateKeySynced) { - expect(privateKeySynced).to.be.undefined; - done(); - }); - }); + scope.encryptAndUploadKey(); }); - describe('handlePaste', function() { - it('should work', function() { - scope.handlePaste({ - clipboardData: { - getData: function(val) { - expect(val).to.equal('text/plain'); - return '1qaz-2wsx-3edc-4rfv-5tgb-6yhn'; - } - } - }); + it('should work', function(done) { + keychainMock.registerDevice.yields(); + keychainMock.uploadPrivateKey.yields(); - expect(scope.code0).to.equal('1qaz'); - expect(scope.code1).to.equal('2wsx'); - expect(scope.code2).to.equal('3edc'); - expect(scope.code3).to.equal('4rfv'); - expect(scope.code4).to.equal('5tgb'); - expect(scope.code5).to.equal('6yhn'); + scope.encryptAndUploadKey(function(err) { + expect(err).to.not.exist; + expect(keychainMock.registerDevice.calledOnce).to.be.true; + expect(keychainMock.uploadPrivateKey.calledOnce).to.be.true; + done(); }); }); + }); - describe('displayUploadUi', function() { - it('should work', function() { - // add some artifacts from a previous key input - scope.code0 = scope.code1 = scope.code2 = scope.code3 = scope.code4 = scope.code5 = 'asdasd'; - - scope.displayUploadUi(); - expect(scope.step).to.equal(1); - expect(scope.code.length).to.equal(24); - - // artifacts should be cleared - expect(scope.code0).to.be.empty; - expect(scope.code1).to.be.empty; - expect(scope.code2).to.be.empty; - expect(scope.code3).to.be.empty; - expect(scope.code4).to.be.empty; - expect(scope.code5).to.be.empty; - }); + describe('goBack', function() { + it('should work', function() { + scope.step = 2; + scope.goBack(); + expect(scope.step).to.equal(1); }); - describe('verifyCode', function() { - it('should fail for wrong code', function() { - scope.code0 = 'b'; - scope.code1 = 'b'; - scope.code2 = 'b'; - scope.code3 = 'b'; - scope.code4 = 'b'; - scope.code5 = 'b'; - scope.code = 'aaaaaa'; + it('should not work for < 2', function() { + scope.step = 1; + scope.goBack(); + expect(scope.step).to.equal(1); + }); + }); - scope.onError = function() {}; - expect(scope.verifyCode()).to.be.false; - }); - - it('should work', function() { - scope.code0 = 'a'; - scope.code1 = 'a'; - scope.code2 = 'a'; - scope.code3 = 'a'; - scope.code4 = 'a'; - scope.code5 = 'a'; - scope.code = 'aaaaaa'; - - scope.onError = function() {}; - expect(scope.verifyCode()).to.be.false; - }); + describe('goForward', function() { + var verifyCodeStub, setDeviceNameStub, encryptAndUploadKeyStub; + beforeEach(function() { + verifyCodeStub = sinon.stub(scope, 'verifyCode'); + setDeviceNameStub = sinon.stub(scope, 'setDeviceName'); + encryptAndUploadKeyStub = sinon.stub(scope, 'encryptAndUploadKey'); + }); + afterEach(function() { + verifyCodeStub.restore(); + setDeviceNameStub.restore(); + encryptAndUploadKeyStub.restore(); }); - describe('setDeviceName', function() { - it('should work', function(done) { - keychainMock.setDeviceName.yields(); - scope.setDeviceName(done); - }); + it('should work for < 2', function() { + scope.step = 1; + scope.goForward(); + expect(scope.step).to.equal(2); }); - describe('encryptAndUploadKey', function() { - it('should fail due to keychain.registerDevice', function(done) { - keychainMock.registerDevice.yields(42); - - scope.onError = function(err) { - expect(err).to.exist; - expect(keychainMock.registerDevice.calledOnce).to.be.true; - done(); - }; - - scope.encryptAndUploadKey(); - }); - - it('should work', function(done) { - keychainMock.registerDevice.yields(); - keychainMock.uploadPrivateKey.yields(); - - scope.encryptAndUploadKey(function(err) { - expect(err).to.not.exist; - expect(keychainMock.registerDevice.calledOnce).to.be.true; - expect(keychainMock.uploadPrivateKey.calledOnce).to.be.true; - done(); - }); - }); + it('should work for 2', function() { + verifyCodeStub.returns(true); + scope.step = 2; + scope.goForward(); + expect(scope.step).to.equal(3); }); - describe('goBack', function() { - it('should work', function() { - scope.step = 2; - scope.goBack(); - expect(scope.step).to.equal(1); - }); - - it('should not work for < 2', function() { - scope.step = 1; - scope.goBack(); - expect(scope.step).to.equal(1); - }); + it('should not work for 2 when code invalid', function() { + verifyCodeStub.returns(false); + scope.step = 2; + scope.goForward(); + expect(scope.step).to.equal(2); }); - describe('goForward', function() { - var verifyCodeStub, setDeviceNameStub, encryptAndUploadKeyStub; - beforeEach(function() { - verifyCodeStub = sinon.stub(scope, 'verifyCode'); - setDeviceNameStub = sinon.stub(scope, 'setDeviceName'); - encryptAndUploadKeyStub = sinon.stub(scope, 'encryptAndUploadKey'); - }); - afterEach(function() { - verifyCodeStub.restore(); - setDeviceNameStub.restore(); - encryptAndUploadKeyStub.restore(); - }); + it('should fail for 3 due to error in setDeviceName', function(done) { + scope.step = 3; + setDeviceNameStub.yields(42); - it('should work for < 2', function() { - scope.step = 1; - scope.goForward(); - expect(scope.step).to.equal(2); - }); - - it('should work for 2', function() { - verifyCodeStub.returns(true); - scope.step = 2; - scope.goForward(); + scope.onError = function(err) { + expect(err).to.exist; expect(scope.step).to.equal(3); - }); + done(); + }; - it('should not work for 2 when code invalid', function() { - verifyCodeStub.returns(false); - scope.step = 2; - scope.goForward(); - expect(scope.step).to.equal(2); - }); - - it('should fail for 3 due to error in setDeviceName', function(done) { - scope.step = 3; - setDeviceNameStub.yields(42); - - scope.onError = function(err) { - expect(err).to.exist; - expect(scope.step).to.equal(3); - done(); - }; - - scope.goForward(); - }); - - it('should fail for 3 due to error in encryptAndUploadKey', function(done) { - scope.step = 3; - setDeviceNameStub.yields(); - encryptAndUploadKeyStub.yields(42); - - scope.onError = function(err) { - expect(err).to.exist; - expect(scope.step).to.equal(4); - done(); - }; - - scope.goForward(); - }); - - it('should work for 3', function(done) { - scope.step = 3; - setDeviceNameStub.yields(); - encryptAndUploadKeyStub.yields(); - - scope.onError = function(err) { - expect(err.title).to.equal('Success'); - expect(scope.step).to.equal(4); - done(); - }; - - scope.goForward(); - }); + scope.goForward(); }); + it('should fail for 3 due to error in encryptAndUploadKey', function(done) { + scope.step = 3; + setDeviceNameStub.yields(); + encryptAndUploadKeyStub.yields(42); + + scope.onError = function(err) { + expect(err).to.exist; + expect(scope.step).to.equal(4); + done(); + }; + + scope.goForward(); + }); + + it('should work for 3', function(done) { + scope.step = 3; + setDeviceNameStub.yields(); + encryptAndUploadKeyStub.yields(); + + scope.onError = function(err) { + expect(err.title).to.equal('Success'); + expect(scope.step).to.equal(4); + done(); + }; + + scope.goForward(); + }); }); }); \ No newline at end of file diff --git a/test/unit/publickey-dao-test.js b/test/unit/publickey-dao-test.js index 8e9930f..724fc62 100644 --- a/test/unit/publickey-dao-test.js +++ b/test/unit/publickey-dao-test.js @@ -1,165 +1,161 @@ -define(function(require) { - 'use strict'; +'use strict'; - var RestDAO = require('js/dao/rest-dao'), - PublicKeyDAO = require('js/dao/publickey-dao'), - expect = chai.expect; +var RestDAO = require('../../src/js/dao/rest-dao'), + PublicKeyDAO = require('../../src/js/dao/publickey-dao'); - describe('Public Key DAO unit tests', function() { +describe('Public Key DAO unit tests', function() { - var pubkeyDao, restDaoStub; + var pubkeyDao, restDaoStub; - beforeEach(function() { - restDaoStub = sinon.createStubInstance(RestDAO); - pubkeyDao = new PublicKeyDAO(restDaoStub); - }); + beforeEach(function() { + restDaoStub = sinon.createStubInstance(RestDAO); + pubkeyDao = new PublicKeyDAO(restDaoStub); + }); - afterEach(function() {}); + afterEach(function() {}); - describe('get', function() { - it('should fail', function(done) { - restDaoStub.get.yields(42); + describe('get', function() { + it('should fail', function(done) { + restDaoStub.get.yields(42); - pubkeyDao.get('id', function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - expect(restDaoStub.get.calledOnce).to.be.true; - done(); - }); - }); - - it('should work', function(done) { - restDaoStub.get.yields(null, { - _id: '12345', - publicKey: 'asdf' - }); - - pubkeyDao.get('id', function(err, key) { - expect(err).to.not.exist; - expect(key).to.exist; - expect(key._id).to.exist; - expect(key.publicKey).to.exist; - expect(restDaoStub.get.calledOnce).to.be.true; - done(); - }); + pubkeyDao.get('id', function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; + expect(restDaoStub.get.calledOnce).to.be.true; + done(); }); }); - describe('verify', function() { - it('should fail', function(done) { - restDaoStub.get.yields(42); - - pubkeyDao.verify('id', function(err) { - expect(err).to.exist; - done(); - }); + it('should work', function(done) { + restDaoStub.get.yields(null, { + _id: '12345', + publicKey: 'asdf' }); - it('should not error for 400', function(done) { - restDaoStub.get.yields({ - code: 400 - }); - - pubkeyDao.verify('id', function(err) { - expect(err).to.not.exist; - done(); - }); + pubkeyDao.get('id', function(err, key) { + expect(err).to.not.exist; + expect(key).to.exist; + expect(key._id).to.exist; + expect(key.publicKey).to.exist; + expect(restDaoStub.get.calledOnce).to.be.true; + done(); }); + }); + }); - it('should work', function(done) { - var uuid = 'c621e328-8548-40a1-8309-adf1955e98a9'; - restDaoStub.get.yields(null); + describe('verify', function() { + it('should fail', function(done) { + restDaoStub.get.yields(42); - pubkeyDao.verify(uuid, function(err) { - expect(err).to.not.exist; - expect(restDaoStub.get.calledWith(sinon.match(function(arg){ - return arg.uri === '/verify/' + uuid && arg.type === 'text'; - }))).to.be.true; - done(); - }); + pubkeyDao.verify('id', function(err) { + expect(err).to.exist; + done(); }); }); - describe('get by userId', function() { - it('should fail', function(done) { - restDaoStub.get.yields(42); - - pubkeyDao.getByUserId('userId', function(err, key) { - expect(err).to.exist; - expect(key).to.not.exist; - expect(restDaoStub.get.calledOnce).to.be.true; - done(); - }); + it('should not error for 400', function(done) { + restDaoStub.get.yields({ + code: 400 }); - it('should react to 404', function(done) { - restDaoStub.get.yields({ - code: 404 - }); - - pubkeyDao.getByUserId('userId', function(err, key) { - expect(err).to.not.exist; - expect(key).to.not.exist; - expect(restDaoStub.get.calledOnce).to.be.true; - done(); - }); - }); - - it('should return empty array', function(done) { - restDaoStub.get.yields(null, []); - - pubkeyDao.getByUserId('userId', function(err, key) { - expect(err).to.not.exist; - expect(key).to.not.exist; - expect(restDaoStub.get.calledOnce).to.be.true; - done(); - }); - }); - - it('should work', function(done) { - restDaoStub.get.yields(null, [{ - _id: '12345', - publicKey: 'asdf' - }]); - - pubkeyDao.getByUserId('userId', function(err, key) { - expect(err).to.not.exist; - expect(key).to.exist; - expect(key._id).to.exist; - expect(key.publicKey).to.exist; - expect(restDaoStub.get.calledOnce).to.be.true; - done(); - }); + pubkeyDao.verify('id', function(err) { + expect(err).to.not.exist; + done(); }); }); - describe('put', function() { - it('should fail', function(done) { - restDaoStub.put.yields(); + it('should work', function(done) { + var uuid = 'c621e328-8548-40a1-8309-adf1955e98a9'; + restDaoStub.get.yields(null); - pubkeyDao.put({ - _id: '12345', - publicKey: 'asdf' - }, function(err) { - expect(err).to.not.exist; - expect(restDaoStub.put.calledOnce).to.be.true; - done(); - }); + pubkeyDao.verify(uuid, function(err) { + expect(err).to.not.exist; + expect(restDaoStub.get.calledWith(sinon.match(function(arg) { + return arg.uri === '/verify/' + uuid && arg.type === 'text'; + }))).to.be.true; + done(); + }); + }); + }); + + describe('get by userId', function() { + it('should fail', function(done) { + restDaoStub.get.yields(42); + + pubkeyDao.getByUserId('userId', function(err, key) { + expect(err).to.exist; + expect(key).to.not.exist; + expect(restDaoStub.get.calledOnce).to.be.true; + done(); }); }); - describe('remove', function() { - it('should fail', function(done) { - restDaoStub.remove.yields(); + it('should react to 404', function(done) { + restDaoStub.get.yields({ + code: 404 + }); - pubkeyDao.remove('12345', function(err) { - expect(err).to.not.exist; - expect(restDaoStub.remove.calledOnce).to.be.true; - done(); - }); + pubkeyDao.getByUserId('userId', function(err, key) { + expect(err).to.not.exist; + expect(key).to.not.exist; + expect(restDaoStub.get.calledOnce).to.be.true; + done(); }); }); + it('should return empty array', function(done) { + restDaoStub.get.yields(null, []); + + pubkeyDao.getByUserId('userId', function(err, key) { + expect(err).to.not.exist; + expect(key).to.not.exist; + expect(restDaoStub.get.calledOnce).to.be.true; + done(); + }); + }); + + it('should work', function(done) { + restDaoStub.get.yields(null, [{ + _id: '12345', + publicKey: 'asdf' + }]); + + pubkeyDao.getByUserId('userId', function(err, key) { + expect(err).to.not.exist; + expect(key).to.exist; + expect(key._id).to.exist; + expect(key.publicKey).to.exist; + expect(restDaoStub.get.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('put', function() { + it('should fail', function(done) { + restDaoStub.put.yields(); + + pubkeyDao.put({ + _id: '12345', + publicKey: 'asdf' + }, function(err) { + expect(err).to.not.exist; + expect(restDaoStub.put.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('remove', function() { + it('should fail', function(done) { + restDaoStub.remove.yields(); + + pubkeyDao.remove('12345', function(err) { + expect(err).to.not.exist; + expect(restDaoStub.remove.calledOnce).to.be.true; + done(); + }); + }); }); }); \ No newline at end of file diff --git a/test/unit/read-ctrl-test.js b/test/unit/read-ctrl-test.js index a7d8bc5..104b6b1 100644 --- a/test/unit/read-ctrl-test.js +++ b/test/unit/read-ctrl-test.js @@ -1,197 +1,193 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - KeychainDAO = require('js/dao/keychain-dao'), - InvitationDAO = require('js/dao/invitation-dao'), - PGP = require('js/crypto/pgp'), - ReadCtrl = require('js/controller/read'), - OutboxBO = require('js/bo/outbox'), - appController = require('js/app-controller'); +var mocks = angular.mocks, + KeychainDAO = require('../../src/js/dao/keychain-dao'), + InvitationDAO = require('../../src/js/dao/invitation-dao'), + PGP = require('../../src/js/crypto/pgp'), + ReadCtrl = require('../../src/js/controller/read'), + OutboxBO = require('../../src/js/bo/outbox'), + appController = require('../../src/js/app-controller'); - describe('Read Controller unit test', function() { - var scope, ctrl, - origKeychain, keychainMock, - origInvitation, invitationMock, - origCrypto, cryptoMock, - origOutbox, outboxMock, - origEmailDao; +describe('Read Controller unit test', function() { + var scope, ctrl, + origKeychain, keychainMock, + origInvitation, invitationMock, + origCrypto, cryptoMock, + origOutbox, outboxMock, + origEmailDao; - beforeEach(function() { - origKeychain = appController._keychain; - appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); + beforeEach(function() { + origKeychain = appController._keychain; + appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); - origInvitation = appController._invitationDao; - appController._invitationDao = invitationMock = sinon.createStubInstance(InvitationDAO); + origInvitation = appController._invitationDao; + appController._invitationDao = invitationMock = sinon.createStubInstance(InvitationDAO); - origCrypto = appController._pgp; - appController._pgp = cryptoMock = sinon.createStubInstance(PGP); + origCrypto = appController._pgp; + appController._pgp = cryptoMock = sinon.createStubInstance(PGP); - origOutbox = appController._outboxBo; - appController._outboxBo = outboxMock = sinon.createStubInstance(OutboxBO); + origOutbox = appController._outboxBo; + appController._outboxBo = outboxMock = sinon.createStubInstance(OutboxBO); - origEmailDao = appController._emailDao; - appController._emailDao = { - _account: 'sender@example.com' + origEmailDao = appController._emailDao; + appController._emailDao = { + _account: 'sender@example.com' + }; + + angular.module('readtest', []); + mocks.module('readtest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(ReadCtrl, { + $scope: scope + }); + }); + }); + + afterEach(function() { + appController._keychain = origKeychain; + appController._invitationDao = origInvitation; + appController._pgp = origCrypto; + appController._outboxBo = origOutbox; + appController._emailDao = origEmailDao; + }); + + describe('scope variables', function() { + it('should be set correctly', function() { + expect(scope.state.read).to.exist; + expect(scope.state.read.open).to.be.false; + expect(scope.state.read.toggle).to.exist; + }); + }); + + describe('open/close read view', function() { + it('should open/close', function() { + expect(scope.state.read.open).to.be.false; + scope.state.read.toggle(true); + expect(scope.state.read.open).to.be.true; + scope.state.read.toggle(false); + expect(scope.state.read.open).to.be.false; + }); + }); + + describe('getKeyId', function() { + var address = 'asfd@asdf.com'; + + it('should show searching on error', function() { + expect(scope.keyId).to.equal('No key found.'); + keychainMock.getReceiverPublicKey.yields(42); + + scope.onError = function(err) { + expect(err).to.equal(42); + expect(scope.keyId).to.equal('Searching...'); }; - angular.module('readtest', []); - mocks.module('readtest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(ReadCtrl, { - $scope: scope - }); - }); + scope.getKeyId(address); }); - afterEach(function() { - appController._keychain = origKeychain; - appController._invitationDao = origInvitation; - appController._pgp = origCrypto; - appController._outboxBo = origOutbox; - appController._emailDao = origEmailDao; + it('should allow invitation on empty key', function() { + keychainMock.getReceiverPublicKey.yields(); + + scope.onError = function(err) { + expect(err).not.exist; + expect(scope.keyId).to.equal('User has no key. Click to invite.'); + }; + + scope.getKeyId(address); }); - describe('scope variables', function() { - it('should be set correctly', function() { - expect(scope.state.read).to.exist; - expect(scope.state.read.open).to.be.false; - expect(scope.state.read.toggle).to.exist; + it('should show searching on error', function() { + keychainMock.getReceiverPublicKey.yields(null, { + publicKey: 'PUBLIC KEY' }); + + cryptoMock.getFingerprint.returns('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'); + + scope.onError = function(err) { + expect(err).to.not.exist; + expect(scope.keyId).to.equal('PGP key: XXXXXXXX'); + }; + + scope.getKeyId(address); }); - - describe('open/close read view', function() { - it('should open/close', function() { - expect(scope.state.read.open).to.be.false; - scope.state.read.toggle(true); - expect(scope.state.read.open).to.be.true; - scope.state.read.toggle(false); - expect(scope.state.read.open).to.be.false; - }); - }); - - describe('getKeyId', function() { - var address = 'asfd@asdf.com'; - - it('should show searching on error', function() { - expect(scope.keyId).to.equal('No key found.'); - keychainMock.getReceiverPublicKey.yields(42); - - scope.onError = function(err) { - expect(err).to.equal(42); - expect(scope.keyId).to.equal('Searching...'); - }; - - scope.getKeyId(address); - }); - - it('should allow invitation on empty key', function() { - keychainMock.getReceiverPublicKey.yields(); - - scope.onError = function(err) { - expect(err).not.exist; - expect(scope.keyId).to.equal('User has no key. Click to invite.'); - }; - - scope.getKeyId(address); - }); - - it('should show searching on error', function() { - keychainMock.getReceiverPublicKey.yields(null, { - publicKey: 'PUBLIC KEY' - }); - - cryptoMock.getFingerprint.returns('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'); - - scope.onError = function(err) { - expect(err).to.not.exist; - expect(scope.keyId).to.equal('PGP key: XXXXXXXX'); - }; - - scope.getKeyId(address); - }); - }); - - describe('invite', function() { - it('not allow invitation for secure users', function() { - expect(scope.keyId).to.equal('No key found.'); - - scope.invite({ - secure: true, - address: 'asdf@asdf.de' - }); - - expect(scope.keyId).to.equal('No key found.'); - }); - - it('should show error on invitation dao invite error', function() { - invitationMock.invite.yields(42); - - scope.onError = function(err) { - expect(err).to.equal(42); - }; - - scope.invite({ - address: 'asdf@asdf.de' - }); - }); - - it('should show error on outbox put error', function() { - invitationMock.invite.yields(); - outboxMock.put.yields(42); - - scope.onError = function(err) { - expect(err).to.equal(42); - }; - - scope.invite({ - address: 'asdf@asdf.de' - }); - }); - - it('should work', function() { - invitationMock.invite.yields(); - outboxMock.put.yields(); - - scope.onError = function(err) { - expect(err).to.not.exist; - }; - - scope.invite({ - address: 'asdf@asdf.de' - }); - }); - }); - - describe('parseConversation', function() { - it.skip('should work', function() { - var body = 'foo\n' + - '\n' + - '> bar\n' + - '>\n' + - '> foofoo\n' + - '>> foofoobar\n' + - '\ncomment\n' + - '>> barbar'; - - var nodes = scope.parseConversation({ - body: body - }); - expect(nodes).to.exist; - - var expectedJson = '{"children":["foo\\n",{"children":["bar\\n\\nfoofoo",{"children":["foofoobar"]}]},"\\ncomment",{"children":[{"children":["barbar"]}]}]}'; - var json = JSON.stringify(nodes); - expect(json).to.equal(expectedJson); - - var expectedHtml = '
foo

bar

foofoo
foofoobar

comment
barbar
'; - var html = scope.renderNodes(nodes); - expect(html).to.equal(expectedHtml); - }); - }); - }); + + describe('invite', function() { + it('not allow invitation for secure users', function() { + expect(scope.keyId).to.equal('No key found.'); + + scope.invite({ + secure: true, + address: 'asdf@asdf.de' + }); + + expect(scope.keyId).to.equal('No key found.'); + }); + + it('should show error on invitation dao invite error', function() { + invitationMock.invite.yields(42); + + scope.onError = function(err) { + expect(err).to.equal(42); + }; + + scope.invite({ + address: 'asdf@asdf.de' + }); + }); + + it('should show error on outbox put error', function() { + invitationMock.invite.yields(); + outboxMock.put.yields(42); + + scope.onError = function(err) { + expect(err).to.equal(42); + }; + + scope.invite({ + address: 'asdf@asdf.de' + }); + }); + + it('should work', function() { + invitationMock.invite.yields(); + outboxMock.put.yields(); + + scope.onError = function(err) { + expect(err).to.not.exist; + }; + + scope.invite({ + address: 'asdf@asdf.de' + }); + }); + }); + + describe('parseConversation', function() { + it.skip('should work', function() { + var body = 'foo\n' + + '\n' + + '> bar\n' + + '>\n' + + '> foofoo\n' + + '>> foofoobar\n' + + '\ncomment\n' + + '>> barbar'; + + var nodes = scope.parseConversation({ + body: body + }); + expect(nodes).to.exist; + + var expectedJson = '{"children":["foo\\n",{"children":["bar\\n\\nfoofoo",{"children":["foofoobar"]}]},"\\ncomment",{"children":[{"children":["barbar"]}]}]}'; + var json = JSON.stringify(nodes); + expect(json).to.equal(expectedJson); + + var expectedHtml = '
foo

bar

foofoo
foofoobar

comment
barbar
'; + var html = scope.renderNodes(nodes); + expect(html).to.equal(expectedHtml); + }); + }); + }); \ No newline at end of file diff --git a/test/unit/rest-dao-test.js b/test/unit/rest-dao-test.js index 0bb2e06..2686a04 100644 --- a/test/unit/rest-dao-test.js +++ b/test/unit/rest-dao-test.js @@ -1,225 +1,221 @@ -define(function(require) { - 'use strict'; +'use strict'; - var RestDAO = require('js/dao/rest-dao'), - expect = chai.expect; +var RestDAO = require('../../src/js/dao/rest-dao'); - describe('Rest DAO unit tests', function() { +describe('Rest DAO unit tests', function() { - var restDao, xhrMock, requests; + var restDao, xhrMock, requests; - beforeEach(function() { + beforeEach(function() { + restDao = new RestDAO(); + xhrMock = sinon.useFakeXMLHttpRequest(); + requests = []; + + xhrMock.onCreate = function(xhr) { + requests.push(xhr); + }; + }); + + afterEach(function() { + xhrMock.restore(); + }); + + describe('contructor', function() { + it('should set default base uri', function() { restDao = new RestDAO(); - xhrMock = sinon.useFakeXMLHttpRequest(); - requests = []; - - xhrMock.onCreate = function(xhr) { - requests.push(xhr); - }; + expect(restDao).to.exist; + expect(restDao._baseUri).to.exist; }); - afterEach(function() { - xhrMock.restore(); - }); + it('should accept default base uri', function() { + var baseUri = 'http://custom.com'; - describe('contructor', function() { - it('should set default base uri', function() { - restDao = new RestDAO(); - expect(restDao).to.exist; - expect(restDao._baseUri).to.exist; + restDao = new RestDAO(baseUri); + expect(restDao).to.exist; + expect(restDao._baseUri).to.equal(baseUri); + }); + }); + + describe('get', function() { + it('should work with json as default type', function() { + restDao.get({ + uri: '/asdf' + }, function(err, data, status) { + expect(err).to.not.exist; + expect(data.foo).to.equal('bar'); + var req = requests[0]; + expect(req.requestHeaders.Accept).to.equal('application/json'); + expect(status).to.equal(200); }); - it('should accept default base uri', function() { - var baseUri = 'http://custom.com'; + expect(requests.length).to.equal(1); + requests[0].respond(200, { + "Content-Type": "application/json" + }, '{"foo": "bar"}'); + }); - restDao = new RestDAO(baseUri); - expect(restDao).to.exist; - expect(restDao._baseUri).to.equal(baseUri); + it('should work with jsonz', function() { + restDao.get({ + uri: '/asdf', + type: 'json' + }, function(err, data, status) { + expect(err).to.not.exist; + expect(data.foo).to.equal('bar'); + var req = requests[0]; + expect(req.requestHeaders.Accept).to.equal('application/json'); + expect(status).to.equal(200); + }); + + expect(requests.length).to.equal(1); + requests[0].respond(200, { + "Content-Type": "application/json" + }, '{"foo": "bar"}'); + }); + + it('should work with plain text', function() { + restDao.get({ + uri: '/asdf', + type: 'text' + }, function(err, data, status) { + expect(err).to.not.exist; + expect(data).to.equal('foobar!'); + var req = requests[0]; + expect(req.requestHeaders.Accept).to.equal('text/plain'); + expect(status).to.equal(200); + }); + + expect(requests.length).to.equal(1); + requests[0].respond(200, { + "Content-Type": "text/plain" + }, 'foobar!'); + }); + + it('should work with xml', function() { + restDao.get({ + uri: '/asdf', + type: 'xml' + }, function(err, data, status) { + expect(err).to.not.exist; + expect(data).to.equal('bar'); + var req = requests[0]; + expect(req.requestHeaders.Accept).to.equal('application/xml'); + expect(status).to.equal(200); + }); + + expect(requests.length).to.equal(1); + requests[0].respond(200, { + "Content-Type": "application/xml" + }, 'bar'); + }); + + it('should fail for missing uri parameter', function() { + restDao.get({}, function(err, data) { + expect(err).to.exist; + expect(err.code).to.equal(400); + expect(data).to.not.exist; }); }); - describe('get', function() { - it('should work with json as default type', function() { - restDao.get({ - uri: '/asdf' - }, function(err, data, status) { - expect(err).to.not.exist; - expect(data.foo).to.equal('bar'); - var req = requests[0]; - expect(req.requestHeaders.Accept).to.equal('application/json'); - expect(status).to.equal(200); - }); - - expect(requests.length).to.equal(1); - requests[0].respond(200, { - "Content-Type": "application/json" - }, '{"foo": "bar"}'); - }); - - it('should work with jsonz', function() { - restDao.get({ - uri: '/asdf', - type: 'json' - }, function(err, data, status) { - expect(err).to.not.exist; - expect(data.foo).to.equal('bar'); - var req = requests[0]; - expect(req.requestHeaders.Accept).to.equal('application/json'); - expect(status).to.equal(200); - }); - - expect(requests.length).to.equal(1); - requests[0].respond(200, { - "Content-Type": "application/json" - }, '{"foo": "bar"}'); - }); - - it('should work with plain text', function() { - restDao.get({ - uri: '/asdf', - type: 'text' - }, function(err, data, status) { - expect(err).to.not.exist; - expect(data).to.equal('foobar!'); - var req = requests[0]; - expect(req.requestHeaders.Accept).to.equal('text/plain'); - expect(status).to.equal(200); - }); - - expect(requests.length).to.equal(1); - requests[0].respond(200, { - "Content-Type": "text/plain" - }, 'foobar!'); - }); - - it('should work with xml', function() { - restDao.get({ - uri: '/asdf', - type: 'xml' - }, function(err, data, status) { - expect(err).to.not.exist; - expect(data).to.equal('bar'); - var req = requests[0]; - expect(req.requestHeaders.Accept).to.equal('application/xml'); - expect(status).to.equal(200); - }); - - expect(requests.length).to.equal(1); - requests[0].respond(200, { - "Content-Type": "application/xml" - }, 'bar'); - }); - - it('should fail for missing uri parameter', function() { - restDao.get({}, function(err, data) { - expect(err).to.exist; - expect(err.code).to.equal(400); - expect(data).to.not.exist; - }); - }); - - it('should fail for unhandled data type', function() { - restDao.get({ - uri: '/asdf', - type: 'snafu' - }, function(err, data) { - expect(err).to.exist; - expect(err.code).to.equal(400); - expect(data).to.not.exist; - }); - }); - - it('should fail for server error', function() { - restDao.get({ - uri: '/asdf' - }, function(err, data) { - expect(err).to.exist; - expect(err.code).to.equal(500); - expect(data).to.not.exist; - }); - - expect(requests.length).to.equal(1); - requests[0].respond(500, { - "Content-Type": "text/plain" - }, 'Internal error'); + it('should fail for unhandled data type', function() { + restDao.get({ + uri: '/asdf', + type: 'snafu' + }, function(err, data) { + expect(err).to.exist; + expect(err.code).to.equal(400); + expect(data).to.not.exist; }); }); - describe('post', function() { - it('should fail', function() { - restDao.post('/asdf', {}, function(err) { - expect(err).to.exist; - expect(err.code).to.equal(500); - }); - - expect(requests.length).to.equal(1); - requests[0].respond(500, { - "Content-Type": "text/plain" - }, 'Internal error'); + it('should fail for server error', function() { + restDao.get({ + uri: '/asdf' + }, function(err, data) { + expect(err).to.exist; + expect(err.code).to.equal(500); + expect(data).to.not.exist; }); - it('should work', function() { - restDao.post('/asdf', {}, function(err, res, status) { - expect(err).to.not.exist; - expect(res).to.equal(''); - expect(status).to.equal(201); - }); + expect(requests.length).to.equal(1); + requests[0].respond(500, { + "Content-Type": "text/plain" + }, 'Internal error'); + }); + }); - expect(requests.length).to.equal(1); - requests[0].respond(201); + describe('post', function() { + it('should fail', function() { + restDao.post('/asdf', {}, function(err) { + expect(err).to.exist; + expect(err.code).to.equal(500); }); + + expect(requests.length).to.equal(1); + requests[0].respond(500, { + "Content-Type": "text/plain" + }, 'Internal error'); }); - describe('put', function() { - it('should fail', function() { - restDao.put('/asdf', {}, function(err) { - expect(err).to.exist; - expect(err.code).to.equal(500); - }); - - expect(requests.length).to.equal(1); - requests[0].respond(500, { - "Content-Type": "text/plain" - }, 'Internal error'); + it('should work', function() { + restDao.post('/asdf', {}, function(err, res, status) { + expect(err).to.not.exist; + expect(res).to.equal(''); + expect(status).to.equal(201); }); - it('should work', function() { - restDao.put('/asdf', {}, function(err, res, status) { - expect(err).to.not.exist; - expect(res).to.equal(''); - expect(status).to.equal(201); - }); + expect(requests.length).to.equal(1); + requests[0].respond(201); + }); + }); - expect(requests.length).to.equal(1); - requests[0].respond(201); + describe('put', function() { + it('should fail', function() { + restDao.put('/asdf', {}, function(err) { + expect(err).to.exist; + expect(err.code).to.equal(500); }); + + expect(requests.length).to.equal(1); + requests[0].respond(500, { + "Content-Type": "text/plain" + }, 'Internal error'); }); - describe('remove', function() { - it('should fail', function() { - restDao.remove('/asdf', function(err) { - expect(err).to.exist; - expect(err.code).to.equal(500); - }); - - expect(requests.length).to.equal(1); - requests[0].respond(500, { - "Content-Type": "text/plain" - }, 'Internal error'); + it('should work', function() { + restDao.put('/asdf', {}, function(err, res, status) { + expect(err).to.not.exist; + expect(res).to.equal(''); + expect(status).to.equal(201); }); - it('should work', function() { - restDao.remove('/asdf', function(err, res, status) { - expect(err).to.not.exist; - expect(res).to.equal(''); - expect(status).to.equal(200); - }); + expect(requests.length).to.equal(1); + requests[0].respond(201); + }); + }); - expect(requests.length).to.equal(1); - requests[0].respond(200); + describe('remove', function() { + it('should fail', function() { + restDao.remove('/asdf', function(err) { + expect(err).to.exist; + expect(err.code).to.equal(500); }); + + expect(requests.length).to.equal(1); + requests[0].respond(500, { + "Content-Type": "text/plain" + }, 'Internal error'); }); + it('should work', function() { + restDao.remove('/asdf', function(err, res, status) { + expect(err).to.not.exist; + expect(res).to.equal(''); + expect(status).to.equal(200); + }); + + expect(requests.length).to.equal(1); + requests[0].respond(200); + }); }); }); \ No newline at end of file diff --git a/test/unit/set-passphrase-ctrl-test.js b/test/unit/set-passphrase-ctrl-test.js index 42e0f37..aaa9bc8 100644 --- a/test/unit/set-passphrase-ctrl-test.js +++ b/test/unit/set-passphrase-ctrl-test.js @@ -1,126 +1,122 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - SetPassphraseCtrl = require('js/controller/set-passphrase'), - PGP = require('js/crypto/pgp'), - appController = require('js/app-controller'), - KeychainDAO = require('js/dao/keychain-dao'); +var mocks = angular.mocks, + SetPassphraseCtrl = require('../../src/js/controller/set-passphrase'), + PGP = require('../../src/js/crypto/pgp'), + appController = require('../../src/js/app-controller'), + KeychainDAO = require('../../src/js/dao/keychain-dao'); - describe('Set Passphrase Controller unit test', function() { - var scope, setPassphraseCtrl, - dummyFingerprint, expectedFingerprint, - dummyKeyId, expectedKeyId, - emailAddress, keySize, cryptoMock, keychainMock; +describe('Set Passphrase Controller unit test', function() { + var scope, setPassphraseCtrl, + dummyFingerprint, expectedFingerprint, + dummyKeyId, expectedKeyId, + emailAddress, keySize, cryptoMock, keychainMock; - beforeEach(function() { - appController._pgp = cryptoMock = sinon.createStubInstance(PGP); - appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); + beforeEach(function() { + appController._pgp = cryptoMock = sinon.createStubInstance(PGP); + appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO); - dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926'; - expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926'; - dummyKeyId = '9FEB47936E712926'; - expectedKeyId = '6E712926'; - cryptoMock.getFingerprint.returns(dummyFingerprint); - cryptoMock.getKeyId.returns(dummyKeyId); - emailAddress = 'fred@foo.com'; - keySize = 1234; + dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926'; + expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926'; + dummyKeyId = '9FEB47936E712926'; + expectedKeyId = '6E712926'; + cryptoMock.getFingerprint.returns(dummyFingerprint); + cryptoMock.getKeyId.returns(dummyKeyId); + emailAddress = 'fred@foo.com'; + keySize = 1234; - cryptoMock.getKeyParams.returns({ + cryptoMock.getKeyParams.returns({ + _id: dummyKeyId, + fingerprint: dummyFingerprint, + userId: emailAddress, + userIds: [], + bitSize: keySize + }); + + angular.module('setpassphrasetest', []); + mocks.module('setpassphrasetest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = {}; + setPassphraseCtrl = $controller(SetPassphraseCtrl, { + $scope: scope + }); + }); + }); + + afterEach(function() {}); + + describe('setPassphrase', function() { + it('should work', function(done) { + scope.oldPassphrase = 'old'; + scope.newPassphrase = 'new'; + + keychainMock.lookupPrivateKey.withArgs(dummyKeyId).yields(null, { + encryptedKey: 'encrypted' + }); + + cryptoMock.changePassphrase.withArgs({ + privateKeyArmored: 'encrypted', + oldPassphrase: 'old', + newPassphrase: 'new' + }).yields(null, 'newArmoredKey'); + + keychainMock.saveLocalPrivateKey.withArgs({ _id: dummyKeyId, - fingerprint: dummyFingerprint, userId: emailAddress, userIds: [], - bitSize: keySize - }); + encryptedKey: 'newArmoredKey' + }).yields(); - angular.module('setpassphrasetest', []); - mocks.module('setpassphrasetest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = {}; - setPassphraseCtrl = $controller(SetPassphraseCtrl, { - $scope: scope - }); - }); + scope.onError = function(err) { + expect(err.title).to.equal('Success'); + done(); + }; + + scope.setPassphrase(); }); - - afterEach(function() {}); - - describe('setPassphrase', function() { - it('should work', function(done) { - scope.oldPassphrase = 'old'; - scope.newPassphrase = 'new'; - - keychainMock.lookupPrivateKey.withArgs(dummyKeyId).yields(null, { - encryptedKey: 'encrypted' - }); - - cryptoMock.changePassphrase.withArgs({ - privateKeyArmored: 'encrypted', - oldPassphrase: 'old', - newPassphrase: 'new' - }).yields(null, 'newArmoredKey'); - - keychainMock.saveLocalPrivateKey.withArgs({ - _id: dummyKeyId, - userId: emailAddress, - userIds: [], - encryptedKey: 'newArmoredKey' - }).yields(); - - scope.onError = function(err) { - expect(err.title).to.equal('Success'); - done(); - }; - - scope.setPassphrase(); - }); - }); - - describe('check passphrase quality', function() { - it('should be too short', function() { - scope.newPassphrase = '&§DG36'; - scope.checkPassphraseQuality(); - - expect(scope.passphraseMsg).to.equal('Very weak'); - expect(scope.passphraseRating).to.equal(0); - }); - - it('should be very weak', function() { - scope.newPassphrase = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; - scope.checkPassphraseQuality(); - - expect(scope.passphraseMsg).to.equal('Very weak'); - expect(scope.passphraseRating).to.equal(0); - }); - - it('should be weak', function() { - scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf'; - scope.checkPassphraseQuality(); - - expect(scope.passphraseMsg).to.equal('Weak'); - expect(scope.passphraseRating).to.equal(1); - }); - - it('should be good', function() { - scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf5'; - scope.checkPassphraseQuality(); - - expect(scope.passphraseMsg).to.equal('Good'); - expect(scope.passphraseRating).to.equal(2); - }); - - it('should be strong', function() { - scope.newPassphrase = '&§DG36abcd'; - scope.checkPassphraseQuality(); - - expect(scope.passphraseMsg).to.equal('Strong'); - expect(scope.passphraseRating).to.equal(3); - }); - }); - }); + + describe('check passphrase quality', function() { + it('should be too short', function() { + scope.newPassphrase = '&§DG36'; + scope.checkPassphraseQuality(); + + expect(scope.passphraseMsg).to.equal('Very weak'); + expect(scope.passphraseRating).to.equal(0); + }); + + it('should be very weak', function() { + scope.newPassphrase = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; + scope.checkPassphraseQuality(); + + expect(scope.passphraseMsg).to.equal('Very weak'); + expect(scope.passphraseRating).to.equal(0); + }); + + it('should be weak', function() { + scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf'; + scope.checkPassphraseQuality(); + + expect(scope.passphraseMsg).to.equal('Weak'); + expect(scope.passphraseRating).to.equal(1); + }); + + it('should be good', function() { + scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf5'; + scope.checkPassphraseQuality(); + + expect(scope.passphraseMsg).to.equal('Good'); + expect(scope.passphraseRating).to.equal(2); + }); + + it('should be strong', function() { + scope.newPassphrase = '&§DG36abcd'; + scope.checkPassphraseQuality(); + + expect(scope.passphraseMsg).to.equal('Strong'); + expect(scope.passphraseRating).to.equal(3); + }); + }); + }); \ No newline at end of file diff --git a/test/unit/update-handler-test.js b/test/unit/update-handler-test.js index 606be07..8267938 100644 --- a/test/unit/update-handler-test.js +++ b/test/unit/update-handler-test.js @@ -1,472 +1,469 @@ -define(function(require) { - 'use strict'; +'use strict'; - var DeviceStorageDAO = require('js/dao/devicestorage-dao'), - Auth = require('js/bo/auth'), - cfg = require('js/app-config').config, - UpdateHandler = require('js/util/update/update-handler'), - config = require('js/app-config').config, - expect = chai.expect; +var DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'), + Auth = require('../../src/js/bo/auth'), + cfg = require('../../src/js/app-config').config, + UpdateHandler = require('../../src/js/util/update/update-handler'), + config = require('../../src/js/app-config').config; - describe('UpdateHandler', function() { - var updateHandler, appConfigStorageStub, authStub, userStorageStub, origDbVersion; +describe('UpdateHandler', function() { + var updateHandler, appConfigStorageStub, authStub, userStorageStub, origDbVersion; - chai.Assertion.includeStack = true; + chai.Assertion.includeStack = true; - beforeEach(function() { - origDbVersion = cfg.dbVersion; - appConfigStorageStub = sinon.createStubInstance(DeviceStorageDAO); - userStorageStub = sinon.createStubInstance(DeviceStorageDAO); - authStub = sinon.createStubInstance(Auth); - updateHandler = new UpdateHandler(appConfigStorageStub, userStorageStub, authStub); + beforeEach(function() { + origDbVersion = cfg.dbVersion; + appConfigStorageStub = sinon.createStubInstance(DeviceStorageDAO); + userStorageStub = sinon.createStubInstance(DeviceStorageDAO); + authStub = sinon.createStubInstance(Auth); + updateHandler = new UpdateHandler(appConfigStorageStub, userStorageStub, authStub); + }); + + afterEach(function() { + cfg.dbVersion = origDbVersion; + }); + + describe('#constructor', function() { + it('should create instance', function() { + expect(updateHandler).to.exist; + expect(updateHandler._appConfigStorage).to.equal(appConfigStorageStub); + expect(updateHandler._userStorage).to.equal(userStorageStub); + + // the update handler must contain as many db update sripts as there are database versions + expect(updateHandler._updateScripts.length).to.equal(cfg.dbVersion); }); + }); - afterEach(function() { - cfg.dbVersion = origDbVersion; - }); + describe('#update', function() { + var versionDbType = 'dbVersion'; - describe('#constructor', function() { - it('should create instance', function() { - expect(updateHandler).to.exist; - expect(updateHandler._appConfigStorage).to.equal(appConfigStorageStub); - expect(updateHandler._userStorage).to.equal(userStorageStub); + it('should not update when up to date', function(done) { + cfg.dbVersion = 10; // app requires database version 10 + appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, ['10']); // database version is 10 - // the update handler must contain as many db update sripts as there are database versions - expect(updateHandler._updateScripts.length).to.equal(cfg.dbVersion); + updateHandler.update(function(error) { + expect(error).to.not.exist; + expect(appConfigStorageStub.listItems.calledOnce).to.be.true; + + done(); }); }); - describe('#update', function() { - var versionDbType = 'dbVersion'; + describe('dummy updates for v2 to v4', function() { + var updateCounter; - it('should not update when up to date', function(done) { - cfg.dbVersion = 10; // app requires database version 10 - appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, ['10']); // database version is 10 + beforeEach(function() { + updateCounter = 0; + appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, ['2']); // database version is 0 + }); + afterEach(function() { + expect(appConfigStorageStub.listItems.calledOnce).to.be.true; + }); + + + it('should work', function(done) { + cfg.dbVersion = 4; // app requires database version 4 + + // a simple dummy update to executed that only increments the update counter + function dummyUpdate(options, callback) { + updateCounter++; + callback(); + } + + // inject the dummy updates instead of live ones + updateHandler._updateScripts = [dummyUpdate, dummyUpdate, dummyUpdate, dummyUpdate]; + + // execute test updateHandler.update(function(error) { expect(error).to.not.exist; - expect(appConfigStorageStub.listItems.calledOnce).to.be.true; + expect(updateCounter).to.equal(2); done(); }); }); - describe('dummy updates for v2 to v4', function() { - var updateCounter; + it('should fail while updating to v3', function(done) { + cfg.dbVersion = 4; // app requires database version 4 - beforeEach(function() { - updateCounter = 0; - appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, ['2']); // database version is 0 - }); + function dummyUpdate(options, callback) { + updateCounter++; + callback(); + } - afterEach(function() { - expect(appConfigStorageStub.listItems.calledOnce).to.be.true; - }); + function failingUpdate(options, callback) { + callback({}); + } + // inject the dummy updates instead of live ones + updateHandler._updateScripts = [dummyUpdate, dummyUpdate, failingUpdate, dummyUpdate]; - it('should work', function(done) { - cfg.dbVersion = 4; // app requires database version 4 + // execute test + updateHandler.update(function(error) { + expect(error).to.exist; + expect(updateCounter).to.equal(0); - // a simple dummy update to executed that only increments the update counter - function dummyUpdate(options, callback) { - updateCounter++; - callback(); - } - - // inject the dummy updates instead of live ones - updateHandler._updateScripts = [dummyUpdate, dummyUpdate, dummyUpdate, dummyUpdate]; - - // execute test - updateHandler.update(function(error) { - expect(error).to.not.exist; - expect(updateCounter).to.equal(2); - - done(); - }); - }); - - it('should fail while updating to v3', function(done) { - cfg.dbVersion = 4; // app requires database version 4 - - function dummyUpdate(options, callback) { - updateCounter++; - callback(); - } - - function failingUpdate(options, callback) { - callback({}); - } - - // inject the dummy updates instead of live ones - updateHandler._updateScripts = [dummyUpdate, dummyUpdate, failingUpdate, dummyUpdate]; - - // execute test - updateHandler.update(function(error) { - expect(error).to.exist; - expect(updateCounter).to.equal(0); - - done(); - }); - }); - - }); - - describe('v0 -> v1', function() { - var emailDbType = 'email_'; - - beforeEach(function() { - cfg.dbVersion = 1; // app requires database version 1 - appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(); // database version is 0 - }); - - afterEach(function() { - // database version is only queried for version checking prior to the update script - // so no need to check this in case-specific tests - expect(appConfigStorageStub.listItems.calledOnce).to.be.true; - }); - - it('should work', function(done) { - userStorageStub.removeList.withArgs(emailDbType).yieldsAsync(); - appConfigStorageStub.storeList.withArgs([1], versionDbType).yieldsAsync(); - - updateHandler.update(function(error) { - expect(error).to.not.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when persisting database version fails', function(done) { - userStorageStub.removeList.yieldsAsync(); - appConfigStorageStub.storeList.yieldsAsync(new Error()); - - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when wiping emails from database fails', function(done) { - userStorageStub.removeList.yieldsAsync(new Error()); - - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.called).to.be.false; - - done(); - }); + done(); }); }); - describe('v1 -> v2', function() { - var emailDbType = 'email_'; + }); - beforeEach(function() { - cfg.dbVersion = 2; // app requires database version 2 - appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [1]); // database version is 0 - }); + describe('v0 -> v1', function() { + var emailDbType = 'email_'; - afterEach(function() { - // database version is only queried for version checking prior to the update script - // so no need to check this in case-specific tests - expect(appConfigStorageStub.listItems.calledOnce).to.be.true; - }); + beforeEach(function() { + cfg.dbVersion = 1; // app requires database version 1 + appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(); // database version is 0 + }); - it('should work', function(done) { - userStorageStub.removeList.withArgs(emailDbType).yieldsAsync(); - appConfigStorageStub.storeList.withArgs([2], versionDbType).yieldsAsync(); + afterEach(function() { + // database version is only queried for version checking prior to the update script + // so no need to check this in case-specific tests + expect(appConfigStorageStub.listItems.calledOnce).to.be.true; + }); - updateHandler.update(function(error) { - expect(error).to.not.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; + it('should work', function(done) { + userStorageStub.removeList.withArgs(emailDbType).yieldsAsync(); + appConfigStorageStub.storeList.withArgs([1], versionDbType).yieldsAsync(); - done(); - }); - }); + updateHandler.update(function(error) { + expect(error).to.not.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - it('should fail when persisting database version fails', function(done) { - userStorageStub.removeList.yieldsAsync(); - appConfigStorageStub.storeList.yieldsAsync(new Error()); - - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when wiping emails from database fails', function(done) { - userStorageStub.removeList.yieldsAsync(new Error()); - - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.called).to.be.false; - - done(); - }); + done(); }); }); - describe('v2 -> v3', function() { - var emailDbType = 'email_'; + it('should fail when persisting database version fails', function(done) { + userStorageStub.removeList.yieldsAsync(); + appConfigStorageStub.storeList.yieldsAsync(new Error()); - beforeEach(function() { - cfg.dbVersion = 3; // app requires database version 2 - appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [2]); // database version is 0 - }); + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - afterEach(function() { - // database version is only queried for version checking prior to the update script - // so no need to check this in case-specific tests - expect(appConfigStorageStub.listItems.calledOnce).to.be.true; - }); - - it('should work', function(done) { - userStorageStub.removeList.withArgs(emailDbType).yieldsAsync(); - appConfigStorageStub.storeList.withArgs([3], versionDbType).yieldsAsync(); - - updateHandler.update(function(error) { - expect(error).to.not.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when persisting database version fails', function(done) { - userStorageStub.removeList.yieldsAsync(); - appConfigStorageStub.storeList.yieldsAsync(new Error()); - - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when wiping emails from database fails', function(done) { - userStorageStub.removeList.yieldsAsync(new Error()); - - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.removeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.called).to.be.false; - - done(); - }); - }); - }); - describe('v3 -> v4', function() { - var EMAIL_ADDR_DB_KEY = 'emailaddress'; - var USERNAME_DB_KEY = 'username'; - var PROVIDER_DB_KEY = 'provider'; - var IMAP_DB_KEY = 'imap'; - var SMTP_DB_KEY = 'smtp'; - var REALNAME_DB_KEY = 'realname'; - var emailaddress = 'bla@blubb.io'; - - var imap = config.gmail.imap, - smtp = config.gmail.smtp; - - beforeEach(function() { - cfg.dbVersion = 4; // app requires database version 4 - appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [3]); // database version is 3 - }); - - it('should add gmail as mail service provider with email address and no provider present in db', function(done) { - appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(null, [emailaddress]); - appConfigStorageStub.listItems.withArgs(PROVIDER_DB_KEY).yieldsAsync(null, []); - appConfigStorageStub.storeList.withArgs([4], versionDbType).yieldsAsync(); - appConfigStorageStub.storeList.withArgs(['gmail'], PROVIDER_DB_KEY).yieldsAsync(); - appConfigStorageStub.storeList.withArgs([emailaddress], USERNAME_DB_KEY).yieldsAsync(); - appConfigStorageStub.storeList.withArgs([imap], IMAP_DB_KEY).yieldsAsync(); - appConfigStorageStub.storeList.withArgs([smtp], SMTP_DB_KEY).yieldsAsync(); - appConfigStorageStub.storeList.withArgs([''], REALNAME_DB_KEY).yieldsAsync(); - authStub._loadCredentials.yieldsAsync(); - - updateHandler.update(function(error) { - expect(error).to.not.exist; - expect(appConfigStorageStub.storeList.callCount).to.equal(6); - expect(appConfigStorageStub.listItems.calledThrice).to.be.true; - expect(authStub._loadCredentials.calledOnce).to.be.true; - - done(); - }); - }); - - it('should not add a provider when no email adress is in db', function(done) { - appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(null, []); - appConfigStorageStub.listItems.withArgs(PROVIDER_DB_KEY).yieldsAsync(null, []); - appConfigStorageStub.storeList.withArgs([4], versionDbType).yieldsAsync(); - - updateHandler.update(function(error) { - expect(error).to.not.exist; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - expect(appConfigStorageStub.listItems.calledThrice).to.be.true; - - done(); - }); - }); - - it('should fail when appConfigStore write fails', function(done) { - appConfigStorageStub.listItems.yieldsAsync(null, []); - appConfigStorageStub.storeList.yieldsAsync(new Error()); - - updateHandler.update(function(error) { - expect(error).to.exist; - expect(appConfigStorageStub.listItems.calledThrice).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when appConfigStore read fails', function(done) { - appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(new Error()); - appConfigStorageStub.storeList.yieldsAsync(new Error()); - - updateHandler.update(function(error) { - expect(error).to.exist; - expect(appConfigStorageStub.listItems.calledTwice).to.be.true; - expect(appConfigStorageStub.storeList.called).to.be.false; - - done(); - }); + done(); }); }); - describe('v4 -> v5', function() { - var FOLDER_TYPE_INBOX = 'Inbox'; - var FOLDER_TYPE_SENT = 'Sent'; - var FOLDER_TYPE_DRAFTS = 'Drafts'; - var FOLDER_TYPE_TRASH = 'Trash'; + it('should fail when wiping emails from database fails', function(done) { + userStorageStub.removeList.yieldsAsync(new Error()); - var FOLDER_DB_TYPE = 'folders'; - var VERSION_DB_TYPE = 'dbVersion'; + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.called).to.be.false; - var POST_UPDATE_DB_VERSION = 5; - - beforeEach(function() { - cfg.dbVersion = 5; // app requires database version 4 - appConfigStorageStub.listItems.withArgs(VERSION_DB_TYPE).yieldsAsync(null, [4]); // database version is 4 + done(); }); + }); + }); - afterEach(function() { - // database version is only queried for version checking prior to the update script - // so no need to check this in case-specific tests - expect(appConfigStorageStub.listItems.calledOnce).to.be.true; + describe('v1 -> v2', function() { + var emailDbType = 'email_'; + + beforeEach(function() { + cfg.dbVersion = 2; // app requires database version 2 + appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [1]); // database version is 0 + }); + + afterEach(function() { + // database version is only queried for version checking prior to the update script + // so no need to check this in case-specific tests + expect(appConfigStorageStub.listItems.calledOnce).to.be.true; + }); + + it('should work', function(done) { + userStorageStub.removeList.withArgs(emailDbType).yieldsAsync(); + appConfigStorageStub.storeList.withArgs([2], versionDbType).yieldsAsync(); + + updateHandler.update(function(error) { + expect(error).to.not.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; + + done(); }); + }); - it('should work', function(done) { - userStorageStub.listItems.withArgs(FOLDER_DB_TYPE).yieldsAsync(null, [ - [{ - name: 'inbox1', - type: FOLDER_TYPE_INBOX - }, { - name: 'inbox2', - type: FOLDER_TYPE_INBOX - }, { - name: 'sent1', - type: FOLDER_TYPE_SENT - }, { - name: 'sent2', - type: FOLDER_TYPE_SENT - }, { - name: 'drafts1', - type: FOLDER_TYPE_DRAFTS - }, { - name: 'drafts2', - type: FOLDER_TYPE_DRAFTS - }, { - name: 'trash1', - type: FOLDER_TYPE_TRASH - }, { - name: 'trash2', - type: FOLDER_TYPE_TRASH - }] - ]); + it('should fail when persisting database version fails', function(done) { + userStorageStub.removeList.yieldsAsync(); + appConfigStorageStub.storeList.yieldsAsync(new Error()); - userStorageStub.storeList.withArgs([ - [{ - name: 'inbox1', - type: FOLDER_TYPE_INBOX - }, { - name: 'sent1', - type: FOLDER_TYPE_SENT - }, { - name: 'drafts1', - type: FOLDER_TYPE_DRAFTS - }, { - name: 'trash1', - type: FOLDER_TYPE_TRASH - }] - ], FOLDER_DB_TYPE).yieldsAsync(); + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - appConfigStorageStub.storeList.withArgs([POST_UPDATE_DB_VERSION], VERSION_DB_TYPE).yieldsAsync(); - - updateHandler.update(function(error) { - expect(error).to.not.exist; - expect(userStorageStub.listItems.calledOnce).to.be.true; - expect(userStorageStub.storeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - - done(); - }); + done(); }); + }); - it('should fail when persisting database version fails', function(done) { - userStorageStub.listItems.yieldsAsync(null, []); - userStorageStub.storeList.yieldsAsync(); - appConfigStorageStub.storeList.yieldsAsync(new Error()); + it('should fail when wiping emails from database fails', function(done) { + userStorageStub.removeList.yieldsAsync(new Error()); - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.listItems.calledOnce).to.be.true; - expect(userStorageStub.storeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.calledOnce).to.be.true; + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.called).to.be.false; - done(); - }); + done(); }); + }); + }); - it('should fail when persisting folders fails', function(done) { - userStorageStub.listItems.yieldsAsync(null, []); - userStorageStub.storeList.yieldsAsync(new Error()); + describe('v2 -> v3', function() { + var emailDbType = 'email_'; - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.listItems.calledOnce).to.be.true; - expect(userStorageStub.storeList.calledOnce).to.be.true; - expect(appConfigStorageStub.storeList.called).to.be.false; + beforeEach(function() { + cfg.dbVersion = 3; // app requires database version 2 + appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [2]); // database version is 0 + }); - done(); - }); + afterEach(function() { + // database version is only queried for version checking prior to the update script + // so no need to check this in case-specific tests + expect(appConfigStorageStub.listItems.calledOnce).to.be.true; + }); + + it('should work', function(done) { + userStorageStub.removeList.withArgs(emailDbType).yieldsAsync(); + appConfigStorageStub.storeList.withArgs([3], versionDbType).yieldsAsync(); + + updateHandler.update(function(error) { + expect(error).to.not.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; + + done(); }); + }); - it('should fail when listing folders fails', function(done) { - userStorageStub.listItems.yieldsAsync(new Error()); + it('should fail when persisting database version fails', function(done) { + userStorageStub.removeList.yieldsAsync(); + appConfigStorageStub.storeList.yieldsAsync(new Error()); - updateHandler.update(function(error) { - expect(error).to.exist; - expect(userStorageStub.listItems.calledOnce).to.be.true; - expect(userStorageStub.storeList.called).to.be.false; - expect(appConfigStorageStub.storeList.called).to.be.false; + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; - done(); - }); + done(); + }); + }); + + it('should fail when wiping emails from database fails', function(done) { + userStorageStub.removeList.yieldsAsync(new Error()); + + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.removeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.called).to.be.false; + + done(); + }); + }); + }); + describe('v3 -> v4', function() { + var EMAIL_ADDR_DB_KEY = 'emailaddress'; + var USERNAME_DB_KEY = 'username'; + var PROVIDER_DB_KEY = 'provider'; + var IMAP_DB_KEY = 'imap'; + var SMTP_DB_KEY = 'smtp'; + var REALNAME_DB_KEY = 'realname'; + var emailaddress = 'bla@blubb.io'; + + var imap = config.gmail.imap, + smtp = config.gmail.smtp; + + beforeEach(function() { + cfg.dbVersion = 4; // app requires database version 4 + appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [3]); // database version is 3 + }); + + it('should add gmail as mail service provider with email address and no provider present in db', function(done) { + appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(null, [emailaddress]); + appConfigStorageStub.listItems.withArgs(PROVIDER_DB_KEY).yieldsAsync(null, []); + appConfigStorageStub.storeList.withArgs([4], versionDbType).yieldsAsync(); + appConfigStorageStub.storeList.withArgs(['gmail'], PROVIDER_DB_KEY).yieldsAsync(); + appConfigStorageStub.storeList.withArgs([emailaddress], USERNAME_DB_KEY).yieldsAsync(); + appConfigStorageStub.storeList.withArgs([imap], IMAP_DB_KEY).yieldsAsync(); + appConfigStorageStub.storeList.withArgs([smtp], SMTP_DB_KEY).yieldsAsync(); + appConfigStorageStub.storeList.withArgs([''], REALNAME_DB_KEY).yieldsAsync(); + authStub._loadCredentials.yieldsAsync(); + + updateHandler.update(function(error) { + expect(error).to.not.exist; + expect(appConfigStorageStub.storeList.callCount).to.equal(6); + expect(appConfigStorageStub.listItems.calledThrice).to.be.true; + expect(authStub._loadCredentials.calledOnce).to.be.true; + + done(); + }); + }); + + it('should not add a provider when no email adress is in db', function(done) { + appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(null, []); + appConfigStorageStub.listItems.withArgs(PROVIDER_DB_KEY).yieldsAsync(null, []); + appConfigStorageStub.storeList.withArgs([4], versionDbType).yieldsAsync(); + + updateHandler.update(function(error) { + expect(error).to.not.exist; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; + expect(appConfigStorageStub.listItems.calledThrice).to.be.true; + + done(); + }); + }); + + it('should fail when appConfigStore write fails', function(done) { + appConfigStorageStub.listItems.yieldsAsync(null, []); + appConfigStorageStub.storeList.yieldsAsync(new Error()); + + updateHandler.update(function(error) { + expect(error).to.exist; + expect(appConfigStorageStub.listItems.calledThrice).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when appConfigStore read fails', function(done) { + appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(new Error()); + appConfigStorageStub.storeList.yieldsAsync(new Error()); + + updateHandler.update(function(error) { + expect(error).to.exist; + expect(appConfigStorageStub.listItems.calledTwice).to.be.true; + expect(appConfigStorageStub.storeList.called).to.be.false; + + done(); + }); + }); + }); + + describe('v4 -> v5', function() { + var FOLDER_TYPE_INBOX = 'Inbox'; + var FOLDER_TYPE_SENT = 'Sent'; + var FOLDER_TYPE_DRAFTS = 'Drafts'; + var FOLDER_TYPE_TRASH = 'Trash'; + + var FOLDER_DB_TYPE = 'folders'; + var VERSION_DB_TYPE = 'dbVersion'; + + var POST_UPDATE_DB_VERSION = 5; + + beforeEach(function() { + cfg.dbVersion = 5; // app requires database version 4 + appConfigStorageStub.listItems.withArgs(VERSION_DB_TYPE).yieldsAsync(null, [4]); // database version is 4 + }); + + afterEach(function() { + // database version is only queried for version checking prior to the update script + // so no need to check this in case-specific tests + expect(appConfigStorageStub.listItems.calledOnce).to.be.true; + }); + + it('should work', function(done) { + userStorageStub.listItems.withArgs(FOLDER_DB_TYPE).yieldsAsync(null, [ + [{ + name: 'inbox1', + type: FOLDER_TYPE_INBOX + }, { + name: 'inbox2', + type: FOLDER_TYPE_INBOX + }, { + name: 'sent1', + type: FOLDER_TYPE_SENT + }, { + name: 'sent2', + type: FOLDER_TYPE_SENT + }, { + name: 'drafts1', + type: FOLDER_TYPE_DRAFTS + }, { + name: 'drafts2', + type: FOLDER_TYPE_DRAFTS + }, { + name: 'trash1', + type: FOLDER_TYPE_TRASH + }, { + name: 'trash2', + type: FOLDER_TYPE_TRASH + }] + ]); + + userStorageStub.storeList.withArgs([ + [{ + name: 'inbox1', + type: FOLDER_TYPE_INBOX + }, { + name: 'sent1', + type: FOLDER_TYPE_SENT + }, { + name: 'drafts1', + type: FOLDER_TYPE_DRAFTS + }, { + name: 'trash1', + type: FOLDER_TYPE_TRASH + }] + ], FOLDER_DB_TYPE).yieldsAsync(); + + appConfigStorageStub.storeList.withArgs([POST_UPDATE_DB_VERSION], VERSION_DB_TYPE).yieldsAsync(); + + updateHandler.update(function(error) { + expect(error).to.not.exist; + expect(userStorageStub.listItems.calledOnce).to.be.true; + expect(userStorageStub.storeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when persisting database version fails', function(done) { + userStorageStub.listItems.yieldsAsync(null, []); + userStorageStub.storeList.yieldsAsync(); + appConfigStorageStub.storeList.yieldsAsync(new Error()); + + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.listItems.calledOnce).to.be.true; + expect(userStorageStub.storeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when persisting folders fails', function(done) { + userStorageStub.listItems.yieldsAsync(null, []); + userStorageStub.storeList.yieldsAsync(new Error()); + + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.listItems.calledOnce).to.be.true; + expect(userStorageStub.storeList.calledOnce).to.be.true; + expect(appConfigStorageStub.storeList.called).to.be.false; + + done(); + }); + }); + + it('should fail when listing folders fails', function(done) { + userStorageStub.listItems.yieldsAsync(new Error()); + + updateHandler.update(function(error) { + expect(error).to.exist; + expect(userStorageStub.listItems.calledOnce).to.be.true; + expect(userStorageStub.storeList.called).to.be.false; + expect(appConfigStorageStub.storeList.called).to.be.false; + + done(); }); }); }); diff --git a/test/unit/write-ctrl-test.js b/test/unit/write-ctrl-test.js index b53ffd3..2df9468 100644 --- a/test/unit/write-ctrl-test.js +++ b/test/unit/write-ctrl-test.js @@ -1,401 +1,397 @@ -define(function(require) { - 'use strict'; +'use strict'; - var expect = chai.expect, - angular = require('angular'), - mocks = require('angularMocks'), - WriteCtrl = require('js/controller/write'), - EmailDAO = require('js/dao/email-dao'), - OutboxBO = require('js/bo/outbox'), - KeychainDAO = require('js/dao/keychain-dao'), - appController = require('js/app-controller'); +var mocks = angular.mocks, + WriteCtrl = require('../../src/js/controller/write'), + EmailDAO = require('../../src/js/dao/email-dao'), + OutboxBO = require('../../src/js/bo/outbox'), + KeychainDAO = require('../../src/js/dao/keychain-dao'), + appController = require('../../src/js/app-controller'); - describe('Write controller unit test', function() { - var ctrl, scope, - origEmailDao, origOutbox, origKeychain, - emailDaoMock, keychainMock, outboxMock, emailAddress, realname; +describe('Write controller unit test', function() { + var ctrl, scope, + origEmailDao, origOutbox, origKeychain, + emailDaoMock, keychainMock, outboxMock, emailAddress, realname; - beforeEach(function() { - // the app controller is a singleton, we need to remember the - // outbox and email dao to restore it after the tests - origEmailDao = appController._emailDao; - origOutbox = appController._outboxBo; - origKeychain = appController._keychain; + beforeEach(function() { + // the app controller is a singleton, we need to remember the + // outbox and email dao to restore it after the tests + origEmailDao = appController._emailDao; + origOutbox = appController._outboxBo; + origKeychain = appController._keychain; - outboxMock = sinon.createStubInstance(OutboxBO); - appController._outboxBo = outboxMock; + outboxMock = sinon.createStubInstance(OutboxBO); + appController._outboxBo = outboxMock; - emailDaoMock = sinon.createStubInstance(EmailDAO); - appController._emailDao = emailDaoMock; + emailDaoMock = sinon.createStubInstance(EmailDAO); + appController._emailDao = emailDaoMock; - emailAddress = 'fred@foo.com'; - realname = 'Fred Foo'; - emailDaoMock._account = { - emailAddress: emailAddress, - realname: realname - }; + emailAddress = 'fred@foo.com'; + realname = 'Fred Foo'; + emailDaoMock._account = { + emailAddress: emailAddress, + realname: realname + }; - keychainMock = sinon.createStubInstance(KeychainDAO); - appController._keychain = keychainMock; + keychainMock = sinon.createStubInstance(KeychainDAO); + appController._keychain = keychainMock; - angular.module('writetest', []); - mocks.module('writetest'); - mocks.inject(function($rootScope, $controller) { - scope = $rootScope.$new(); - scope.state = {}; - ctrl = $controller(WriteCtrl, { - $scope: scope - }); + angular.module('writetest', []); + mocks.module('writetest'); + mocks.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(WriteCtrl, { + $scope: scope }); }); + }); - afterEach(function() { - // restore the app controller - appController._emailDao = origEmailDao; - appController._outboxBo = origOutbox; - appController._keychain = origKeychain; + afterEach(function() { + // restore the app controller + appController._emailDao = origEmailDao; + appController._outboxBo = origOutbox; + appController._keychain = origKeychain; + }); + + describe('scope variables', function() { + it('should be set correctly', function() { + expect(scope.state.writer).to.exist; + expect(scope.state.lightbox).to.be.undefined; + expect(scope.state.writer.write).to.exist; + expect(scope.state.writer.close).to.exist; + expect(scope.verify).to.exist; + expect(scope.checkSendStatus).to.exist; + expect(scope.sendToOutbox).to.exist; + expect(scope.tagStyle).to.exist; + expect(scope.lookupAddressBook).to.exist; + }); + }); + + describe('close', function() { + it('should close the writer', function() { + scope.state.lightbox = 'write'; + + scope.state.writer.close(); + + expect(scope.state.lightbox).to.be.undefined; + }); + }); + + describe('write', function() { + it('should prepare write view', function() { + var verifyMock = sinon.stub(scope, 'verify'); + + scope.state.writer.write(); + + expect(scope.writerTitle).to.equal('New email'); + expect(scope.to).to.deep.equal([]); + expect(scope.subject).to.equal(''); + expect(scope.body).to.equal(''); + expect(verifyMock.calledOnce).to.be.true; + + scope.verify.restore(); }); - describe('scope variables', function() { - it('should be set correctly', function() { - expect(scope.state.writer).to.exist; - expect(scope.state.lightbox).to.be.undefined; - expect(scope.state.writer.write).to.exist; - expect(scope.state.writer.close).to.exist; - expect(scope.verify).to.exist; - expect(scope.checkSendStatus).to.exist; - expect(scope.sendToOutbox).to.exist; - expect(scope.tagStyle).to.exist; - expect(scope.lookupAddressBook).to.exist; - }); + it('should prefill write view for response', function() { + var verifyMock = sinon.stub(scope, 'verify'), + address = 'pity@dafool', + subject = 'Ermahgerd!', + body = 'so much body!', + re = { + id: 'abc', + from: [{ + address: address + }], + subject: subject, + sentDate: new Date(), + body: body, + references: ['ghi', 'def'] + }; + + scope.sendBtnSecure = true; + + scope.state.writer.write(re); + + expect(scope.writerTitle).to.equal('Reply'); + expect(scope.to).to.deep.equal([{ + address: address, + }]); + expect(scope.subject).to.equal('Re: ' + subject); + expect(scope.body).to.contain(body); + expect(scope.references).to.deep.equal(['ghi', 'def', 'abc']); + expect(verifyMock.called).to.be.true; + + scope.verify.restore(); }); - describe('close', function() { - it('should close the writer', function() { - scope.state.lightbox = 'write'; - - scope.state.writer.close(); - - expect(scope.state.lightbox).to.be.undefined; - }); - }); - - describe('write', function() { - it('should prepare write view', function() { - var verifyMock = sinon.stub(scope, 'verify'); - - scope.state.writer.write(); - - expect(scope.writerTitle).to.equal('New email'); - expect(scope.to).to.deep.equal([]); - expect(scope.subject).to.equal(''); - expect(scope.body).to.equal(''); - expect(verifyMock.calledOnce).to.be.true; - - scope.verify.restore(); - }); - - it('should prefill write view for response', function() { - var verifyMock = sinon.stub(scope, 'verify'), - address = 'pity@dafool', - subject = 'Ermahgerd!', - body = 'so much body!', - re = { - id: 'abc', - from: [{ - address: address - }], - subject: subject, - sentDate: new Date(), - body: body, - references: ['ghi', 'def'] - }; - - scope.sendBtnSecure = true; - - scope.state.writer.write(re); - - expect(scope.writerTitle).to.equal('Reply'); - expect(scope.to).to.deep.equal([{ - address: address, - }]); - expect(scope.subject).to.equal('Re: ' + subject); - expect(scope.body).to.contain(body); - expect(scope.references).to.deep.equal(['ghi', 'def', 'abc']); - expect(verifyMock.called).to.be.true; - - scope.verify.restore(); - }); - - it('should prefill write view for forward', function() { - var verifyMock = sinon.stub(scope, 'verify'), - address = 'pity@dafool', - subject = 'Ermahgerd!', - body = 'so much body!', - re = { - from: [{ - address: address - }], - to: [{ - address: address - }], - subject: subject, - sentDate: new Date(), - body: body, - attachments: [{}] - }; - - scope.sendBtnSecure = false; - - scope.state.writer.write(re, null, true); - - expect(scope.writerTitle).to.equal('Forward'); - expect(scope.to).to.deep.equal([]); - expect(scope.subject).to.equal('Fwd: ' + subject); - expect(scope.body).to.contain(body); - expect(verifyMock.called).to.be.true; - expect(scope.attachments).to.not.equal(re.attachments); // not the same reference - expect(scope.attachments).to.deep.equal(re.attachments); // but the same content - - scope.verify.restore(); - }); - - }); - - describe('verify', function() { - var checkSendStatusMock; - - beforeEach(function() { - checkSendStatusMock = sinon.stub(scope, 'checkSendStatus'); - }); - - afterEach(function() { - scope.checkSendStatus.restore(); - }); - - it('should do nothing if recipient is not provided', function() { - scope.verify(undefined); - }); - - it('should not work for invalid email addresses', function() { - var recipient = { - address: '' + it('should prefill write view for forward', function() { + var verifyMock = sinon.stub(scope, 'verify'), + address = 'pity@dafool', + subject = 'Ermahgerd!', + body = 'so much body!', + re = { + from: [{ + address: address + }], + to: [{ + address: address + }], + subject: subject, + sentDate: new Date(), + body: body, + attachments: [{}] }; - scope.verify(recipient); + scope.sendBtnSecure = false; - expect(recipient.key).to.be.undefined; - expect(recipient.secure).to.be.undefined; - expect(scope.checkSendStatus.callCount).to.equal(2); - expect(keychainMock.getReceiverPublicKey.called).to.be.false; - }); + scope.state.writer.write(re, null, true); - it('should not work for error in keychain', function(done) { - var recipient = { - address: 'asds@example.com' - }; + expect(scope.writerTitle).to.equal('Forward'); + expect(scope.to).to.deep.equal([]); + expect(scope.subject).to.equal('Fwd: ' + subject); + expect(scope.body).to.contain(body); + expect(verifyMock.called).to.be.true; + expect(scope.attachments).to.not.equal(re.attachments); // not the same reference + expect(scope.attachments).to.deep.equal(re.attachments); // but the same content - keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields({ - errMsg: '404 not found yadda yadda' - }); - - scope.onError = function() { - expect(recipient.key).to.be.undefined; - expect(recipient.secure).to.be.false; - expect(scope.checkSendStatus.callCount).to.equal(1); - expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; - done(); - }; - - scope.verify(recipient); - }); - - it('should work for main userId', function(done) { - var recipient = { - address: 'asdf@example.com' - }; - - keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, { - userId: 'asdf@example.com' - }); - - scope.$digest = function() { - expect(recipient.key).to.deep.equal({ - userId: 'asdf@example.com' - }); - expect(recipient.secure).to.be.true; - expect(scope.checkSendStatus.callCount).to.equal(2); - expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; - done(); - }; - - scope.verify(recipient); - }); - - it('should work for secondary userId', function(done) { - var recipient = { - address: 'asdf@example.com' - }; - var key = { - userId: 'qwer@example.com', - userIds: [{ - emailAddress: 'asdf@example.com' - }] - }; - - keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, key); - - scope.$digest = function() { - expect(recipient.key).to.deep.equal(key); - expect(recipient.secure).to.be.true; - expect(scope.checkSendStatus.callCount).to.equal(2); - expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; - done(); - }; - - scope.verify(recipient); - }); - }); - - describe('checkSendStatus', function() { - beforeEach(function() { - scope.state.writer.write(); - }); - - afterEach(function() {}); - - it('should not be able to send with no recipients', function() { - scope.checkSendStatus(); - - expect(scope.okToSend).to.be.false; - expect(scope.sendBtnText).to.be.undefined; - expect(scope.sendBtnSecure).to.be.undefined; - }); - - it('should be able to send plaintext', function() { - scope.to = [{ - address: 'asdf@asdf.de' - }]; - scope.checkSendStatus(); - - expect(scope.okToSend).to.be.true; - expect(scope.sendBtnText).to.equal('Send'); - expect(scope.sendBtnSecure).to.be.false; - }); - - it('should send plaintext if one receiver is not secure', function() { - scope.to = [{ - address: 'asdf@asdf.de', - secure: true - }, { - address: 'asdf@asdfg.de' - }]; - scope.checkSendStatus(); - - expect(scope.okToSend).to.be.true; - expect(scope.sendBtnText).to.equal('Send'); - expect(scope.sendBtnSecure).to.be.false; - }); - - it('should be able to send securely to multiple recipients', function() { - scope.to = [{ - address: 'asdf@asdf.de', - secure: true - }, { - address: 'asdf@asdfg.de', - secure: true - }]; - scope.checkSendStatus(); - - expect(scope.okToSend).to.be.true; - expect(scope.sendBtnText).to.equal('Send securely'); - expect(scope.sendBtnSecure).to.be.true; - }); - }); - - describe('send to outbox', function() { - it('should work', function() { - scope.to = [{ - address: 'pity@dafool' - }]; - scope.cc = []; - scope.bcc = []; - scope.subject = 'Ermahgerd!'; - scope.body = 'wow. much body! very text!'; - scope.attachments = []; - scope.state.nav = { - currentFolder: 'currentFolder' - }; - - scope.replyTo = {}; - - outboxMock.put.withArgs(sinon.match(function(mail) { - expect(mail.from).to.deep.equal([{ - address: emailAddress, - name: realname - }]); - expect(mail.to).to.deep.equal(scope.to); - expect(mail.cc).to.deep.equal(scope.cc); - expect(mail.bcc).to.deep.equal(scope.bcc); - expect(mail.body).to.contain(scope.body); - expect(mail.subject).to.equal(scope.subject); - expect(mail.attachments).to.be.empty; - expect(mail.sentDate).to.exist; - - - return true; - })).yields(); - emailDaoMock.setFlags.yields(); - - scope.onError = function(err) { - expect(err).to.not.exist; - }; - - scope.sendToOutbox(); - - expect(outboxMock.put.calledOnce).to.be.true; - expect(emailDaoMock.setFlags.calledOnce).to.be.true; - expect(scope.state.lightbox).to.be.undefined; - expect(scope.replyTo.answered).to.be.true; - }); - }); - - describe('lookupAddressBook', function() { - it('should work', function(done) { - keychainMock.listLocalPublicKeys.yields(null, [{ - userId: 'test@asdf.com', - publicKey: 'KEY' - }]); - - var result = scope.lookupAddressBook('test'); - - result.then(function(response) { - expect(response).to.deep.equal([{ - address: 'test@asdf.com' - }]); - done(); - }); - scope.$digest(); - }); - - it('should work with cache', function(done) { - scope.addressBookCache = [{ - address: 'test@asdf.com' - }, { - address: 'tes@asdf.com' - }]; - - var result = scope.lookupAddressBook('test'); - - result.then(function(response) { - expect(response).to.deep.equal([{ - address: 'test@asdf.com' - }]); - done(); - }); - scope.$digest(); - }); + scope.verify.restore(); }); }); + + describe('verify', function() { + var checkSendStatusMock; + + beforeEach(function() { + checkSendStatusMock = sinon.stub(scope, 'checkSendStatus'); + }); + + afterEach(function() { + scope.checkSendStatus.restore(); + }); + + it('should do nothing if recipient is not provided', function() { + scope.verify(undefined); + }); + + it('should not work for invalid email addresses', function() { + var recipient = { + address: '' + }; + + scope.verify(recipient); + + expect(recipient.key).to.be.undefined; + expect(recipient.secure).to.be.undefined; + expect(scope.checkSendStatus.callCount).to.equal(2); + expect(keychainMock.getReceiverPublicKey.called).to.be.false; + }); + + it('should not work for error in keychain', function(done) { + var recipient = { + address: 'asds@example.com' + }; + + keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields({ + errMsg: '404 not found yadda yadda' + }); + + scope.onError = function() { + expect(recipient.key).to.be.undefined; + expect(recipient.secure).to.be.false; + expect(scope.checkSendStatus.callCount).to.equal(1); + expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; + done(); + }; + + scope.verify(recipient); + }); + + it('should work for main userId', function(done) { + var recipient = { + address: 'asdf@example.com' + }; + + keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, { + userId: 'asdf@example.com' + }); + + scope.$digest = function() { + expect(recipient.key).to.deep.equal({ + userId: 'asdf@example.com' + }); + expect(recipient.secure).to.be.true; + expect(scope.checkSendStatus.callCount).to.equal(2); + expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; + done(); + }; + + scope.verify(recipient); + }); + + it('should work for secondary userId', function(done) { + var recipient = { + address: 'asdf@example.com' + }; + var key = { + userId: 'qwer@example.com', + userIds: [{ + emailAddress: 'asdf@example.com' + }] + }; + + keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, key); + + scope.$digest = function() { + expect(recipient.key).to.deep.equal(key); + expect(recipient.secure).to.be.true; + expect(scope.checkSendStatus.callCount).to.equal(2); + expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true; + done(); + }; + + scope.verify(recipient); + }); + }); + + describe('checkSendStatus', function() { + beforeEach(function() { + scope.state.writer.write(); + }); + + afterEach(function() {}); + + it('should not be able to send with no recipients', function() { + scope.checkSendStatus(); + + expect(scope.okToSend).to.be.false; + expect(scope.sendBtnText).to.be.undefined; + expect(scope.sendBtnSecure).to.be.undefined; + }); + + it('should be able to send plaintext', function() { + scope.to = [{ + address: 'asdf@asdf.de' + }]; + scope.checkSendStatus(); + + expect(scope.okToSend).to.be.true; + expect(scope.sendBtnText).to.equal('Send'); + expect(scope.sendBtnSecure).to.be.false; + }); + + it('should send plaintext if one receiver is not secure', function() { + scope.to = [{ + address: 'asdf@asdf.de', + secure: true + }, { + address: 'asdf@asdfg.de' + }]; + scope.checkSendStatus(); + + expect(scope.okToSend).to.be.true; + expect(scope.sendBtnText).to.equal('Send'); + expect(scope.sendBtnSecure).to.be.false; + }); + + it('should be able to send securely to multiple recipients', function() { + scope.to = [{ + address: 'asdf@asdf.de', + secure: true + }, { + address: 'asdf@asdfg.de', + secure: true + }]; + scope.checkSendStatus(); + + expect(scope.okToSend).to.be.true; + expect(scope.sendBtnText).to.equal('Send securely'); + expect(scope.sendBtnSecure).to.be.true; + }); + }); + + describe('send to outbox', function() { + it('should work', function() { + scope.to = [{ + address: 'pity@dafool' + }]; + scope.cc = []; + scope.bcc = []; + scope.subject = 'Ermahgerd!'; + scope.body = 'wow. much body! very text!'; + scope.attachments = []; + scope.state.nav = { + currentFolder: 'currentFolder' + }; + + scope.replyTo = {}; + + outboxMock.put.withArgs(sinon.match(function(mail) { + expect(mail.from).to.deep.equal([{ + address: emailAddress, + name: realname + }]); + expect(mail.to).to.deep.equal(scope.to); + expect(mail.cc).to.deep.equal(scope.cc); + expect(mail.bcc).to.deep.equal(scope.bcc); + expect(mail.body).to.contain(scope.body); + expect(mail.subject).to.equal(scope.subject); + expect(mail.attachments).to.be.empty; + expect(mail.sentDate).to.exist; + + + return true; + })).yields(); + emailDaoMock.setFlags.yields(); + + scope.onError = function(err) { + expect(err).to.not.exist; + }; + + scope.sendToOutbox(); + + expect(outboxMock.put.calledOnce).to.be.true; + expect(emailDaoMock.setFlags.calledOnce).to.be.true; + expect(scope.state.lightbox).to.be.undefined; + expect(scope.replyTo.answered).to.be.true; + }); + }); + + describe('lookupAddressBook', function() { + it('should work', function(done) { + keychainMock.listLocalPublicKeys.yields(null, [{ + userId: 'test@asdf.com', + publicKey: 'KEY' + }]); + + var result = scope.lookupAddressBook('test'); + + result.then(function(response) { + expect(response).to.deep.equal([{ + address: 'test@asdf.com' + }]); + done(); + }); + scope.$digest(); + }); + + it('should work with cache', function(done) { + scope.addressBookCache = [{ + address: 'test@asdf.com' + }, { + address: 'tes@asdf.com' + }]; + + var result = scope.lookupAddressBook('test'); + + result.then(function(response) { + expect(response).to.deep.equal([{ + address: 'test@asdf.com' + }]); + done(); + }); + scope.$digest(); + }); + }); + }); \ No newline at end of file