mirror of https://github.com/moparisthebest/mail
commit
5d09e32320
|
@ -7,7 +7,7 @@ src/css/
|
|||
dist/
|
||||
release/
|
||||
test/integration/src/
|
||||
src/lib/*.js
|
||||
src/js/crypto/aes-gcm.js
|
||||
src/js/crypto/util.js
|
||||
.elasticbeanstalk/
|
||||
test/*/index.js
|
||||
**/*.browserified.js
|
||||
**/*.js.map
|
||||
|
|
36
.jshintrc
36
.jshintrc
|
@ -18,31 +18,29 @@
|
|||
"unused": true,
|
||||
|
||||
"predef": [
|
||||
"console",
|
||||
"Notification",
|
||||
"importScripts",
|
||||
"process",
|
||||
"Event",
|
||||
"QUnit",
|
||||
"test",
|
||||
"asyncTest",
|
||||
"ok",
|
||||
"equal",
|
||||
"deepEqual",
|
||||
"start",
|
||||
"chrome",
|
||||
"requirejs",
|
||||
"define",
|
||||
"self",
|
||||
"describe",
|
||||
"it",
|
||||
"chai",
|
||||
"importScripts",
|
||||
"console",
|
||||
"process",
|
||||
"chrome",
|
||||
"Notification",
|
||||
"Event",
|
||||
"sinon",
|
||||
"mocha",
|
||||
"chai",
|
||||
"expect",
|
||||
"describe",
|
||||
"it",
|
||||
"before",
|
||||
"beforeEach",
|
||||
"after",
|
||||
"afterEach"
|
||||
"afterEach",
|
||||
"FastClick",
|
||||
"angular",
|
||||
"forge",
|
||||
"Lawnchair",
|
||||
"_",
|
||||
"openpgp"
|
||||
],
|
||||
|
||||
"globals": {
|
||||
|
|
354
Gruntfile.js
354
Gruntfile.js
|
@ -1,11 +1,22 @@
|
|||
module.exports = function(grunt) {
|
||||
'use strict';
|
||||
|
||||
require('time-grunt')(grunt);
|
||||
|
||||
var version = grunt.option('release'),
|
||||
zipName = (version) ? version : 'DEV';
|
||||
|
||||
var browserifyOpt = {
|
||||
exclude: ['openpgp', 'node-forge', 'net', 'tls', 'crypto'], // node apis not required at build time
|
||||
ignore: ['buffer'], // node apis to be stubbed for runtime
|
||||
browserifyOptions: {
|
||||
debug: true
|
||||
}
|
||||
};
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
|
||||
connect: {
|
||||
dev: {
|
||||
options: {
|
||||
|
@ -23,32 +34,27 @@ 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/*-test.js'],
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
}
|
||||
},
|
||||
|
||||
mocha: {
|
||||
mocha_phantomjs: {
|
||||
all: {
|
||||
options: {
|
||||
urls: [
|
||||
'http://localhost:<%= connect.test.options.port %>/test/unit/index.html',
|
||||
'http://localhost:<%= connect.test.options.port %>/test/integration/index.html'
|
||||
],
|
||||
run: false,
|
||||
reporter: 'Spec',
|
||||
log: false,
|
||||
|
||||
// phanotmjs is soooo slow
|
||||
timeout: 100000
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
clean: {
|
||||
dist: ['dist', 'src/lib/*.js', 'test/lib', 'test/integration/src']
|
||||
dist: ['dist', 'test/lib', 'test/integration/src']
|
||||
},
|
||||
|
||||
sass: {
|
||||
dist: {
|
||||
files: {
|
||||
|
@ -57,6 +63,7 @@ module.exports = function(grunt) {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
autoprefixer: {
|
||||
options: {
|
||||
browsers: ['last 2 versions']
|
||||
|
@ -68,9 +75,10 @@ module.exports = function(grunt) {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
csso: {
|
||||
options: {
|
||||
banner: '/*! Copyright © 2013, Whiteout Networks GmbH. All rights reserved.*/\n'
|
||||
banner: '/*! Copyright © <%= grunt.template.today("yyyy") %>, Whiteout Networks GmbH.*/\n'
|
||||
},
|
||||
dist: {
|
||||
files: {
|
||||
|
@ -79,6 +87,7 @@ module.exports = function(grunt) {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
css: {
|
||||
files: ['src/sass/**/*.scss'],
|
||||
|
@ -86,7 +95,7 @@ module.exports = function(grunt) {
|
|||
},
|
||||
js: {
|
||||
files: ['src/js/**/*.js'],
|
||||
tasks: ['copy:js', 'copy:integration', 'manifest']
|
||||
tasks: ['dist-js', 'copy:integration', 'manifest']
|
||||
},
|
||||
lib: {
|
||||
files: ['src/lib/**/*.js'],
|
||||
|
@ -97,59 +106,234 @@ module.exports = function(grunt) {
|
|||
tasks: ['copy:app', 'copy:ca', 'copy:tpl', 'copy:img', 'copy:font', 'manifest-dev', 'manifest']
|
||||
}
|
||||
},
|
||||
copy: {
|
||||
npm: {
|
||||
expand: true,
|
||||
flatten: true,
|
||||
cwd: 'node_modules/',
|
||||
src: [
|
||||
'requirejs/require.js',
|
||||
'imap-client/src/*.js',
|
||||
'imap-client/node_modules/browserbox/src/*.js',
|
||||
'imap-client/node_modules/browserbox/node_modules/wo-imap-handler/src/*.js',
|
||||
'imap-client/node_modules/browserbox/node_modules/mimefuncs/src/*.js',
|
||||
'imap-client/node_modules/browserbox/node_modules/tcp-socket/src/*.js',
|
||||
'imap-client/node_modules/browserbox/node_modules/wo-utf7/src/*.js',
|
||||
'mailreader/src/*.js',
|
||||
'mailreader/node_modules/mimeparser/src/*.js',
|
||||
'mailreader/node_modules/mimeparser/node_modules/wo-addressparser/src/*.js',
|
||||
'pgpbuilder/src/*.js',
|
||||
'pgpbuilder/node_modules/mailbuild/src/*.js',
|
||||
'pgpbuilder/node_modules/mailbuild/node_modules/mimetypes/src/*.js',
|
||||
'pgpbuilder/node_modules/mailbuild/node_modules/punycode/punycode.min.js',
|
||||
'pgpmailer/src/*.js',
|
||||
'pgpmailer/node_modules/wo-smtpclient/src/*.js',
|
||||
'pgpmailer/node_modules/wo-smtpclient/node_modules/wo-stringencoding/dist/stringencoding.js',
|
||||
'axe-logger/axe.js',
|
||||
'dompurify/purify.js',
|
||||
'jquery/dist/jquery.min.js',
|
||||
'ng-infinite-scroll/build/ng-infinite-scroll.min.js'
|
||||
],
|
||||
dest: 'src/lib/'
|
||||
|
||||
browserify: {
|
||||
app: {
|
||||
files: {
|
||||
'dist/js/app.browserified.js': ['src/js/app.js']
|
||||
},
|
||||
options: browserifyOpt
|
||||
},
|
||||
pbkdf2Worker: {
|
||||
files: {
|
||||
'dist/js/pbkdf2-worker.browserified.js': ['src/js/crypto/pbkdf2-worker.js']
|
||||
},
|
||||
options: browserifyOpt
|
||||
},
|
||||
mailreaderWorker: {
|
||||
files: {
|
||||
'dist/js/mailreader-parser-worker.browserified.js': ['node_modules/mailreader/src/mailreader-parser-worker-browserify.js']
|
||||
},
|
||||
options: browserifyOpt
|
||||
},
|
||||
tlsWorker: {
|
||||
files: {
|
||||
'dist/js/tcp-socket-tls-worker.browserified.js': ['node_modules/tcp-socket/src/tcp-socket-tls-worker.js']
|
||||
},
|
||||
options: browserifyOpt
|
||||
},
|
||||
unitTest: {
|
||||
files: {
|
||||
'test/unit/index.browserified.js': [
|
||||
'test/unit/oauth-test.js',
|
||||
'test/unit/auth-test.js',
|
||||
'test/unit/email-dao-test.js',
|
||||
'test/unit/app-controller-test.js',
|
||||
'test/unit/pgp-test.js',
|
||||
'test/unit/crypto-test.js',
|
||||
'test/unit/backbutton-handler-test.js',
|
||||
'test/unit/rest-dao-test.js',
|
||||
'test/unit/admin-dao-test.js',
|
||||
'test/unit/publickey-dao-test.js',
|
||||
'test/unit/privatekey-dao-test.js',
|
||||
'test/unit/lawnchair-dao-test.js',
|
||||
'test/unit/keychain-dao-test.js',
|
||||
'test/unit/devicestorage-dao-test.js',
|
||||
'test/unit/dialog-ctrl-test.js',
|
||||
'test/unit/add-account-ctrl-test.js',
|
||||
'test/unit/account-ctrl-test.js',
|
||||
'test/unit/set-passphrase-ctrl-test.js',
|
||||
'test/unit/contacts-ctrl-test.js',
|
||||
'test/unit/login-existing-ctrl-test.js',
|
||||
'test/unit/login-initial-ctrl-test.js',
|
||||
'test/unit/login-new-device-ctrl-test.js',
|
||||
'test/unit/login-privatekey-download-ctrl-test.js',
|
||||
'test/unit/login-set-credentials-ctrl-test.js',
|
||||
'test/unit/privatekey-upload-ctrl-test.js',
|
||||
'test/unit/login-ctrl-test.js',
|
||||
'test/unit/read-ctrl-test.js',
|
||||
'test/unit/navigation-ctrl-test.js',
|
||||
'test/unit/mail-list-ctrl-test.js',
|
||||
'test/unit/write-ctrl-test.js',
|
||||
'test/unit/outbox-bo-test.js',
|
||||
'test/unit/invitation-dao-test.js',
|
||||
'test/unit/update-handler-test.js',
|
||||
'test/unit/connection-doctor-test.js',
|
||||
'test/main.js'
|
||||
]
|
||||
},
|
||||
options: browserifyOpt
|
||||
},
|
||||
integrationTest: {
|
||||
files: {
|
||||
'test/integration/index.browserified.js': [
|
||||
'test/integration/email-dao-test.js',
|
||||
'test/main.js'
|
||||
]
|
||||
},
|
||||
options: browserifyOpt
|
||||
}
|
||||
},
|
||||
|
||||
exorcise: {
|
||||
app: {
|
||||
files: {
|
||||
'dist/js/app.browserified.js.map': ['dist/js/app.browserified.js'],
|
||||
}
|
||||
},
|
||||
unitTest: {
|
||||
files: {
|
||||
'test/unit/index.browserified.js.map': ['test/unit/index.browserified.js'],
|
||||
}
|
||||
},
|
||||
integrationTest: {
|
||||
files: {
|
||||
'test/integration/index.browserified.js.map': ['test/integration/index.browserified.js'],
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
uglify: {
|
||||
app: {
|
||||
files: {
|
||||
'dist/js/app.min.js': [
|
||||
'src/lib/underscore/underscore-min.js',
|
||||
'node_modules/jquery/dist/jquery.min.js',
|
||||
'src/lib/angular/angular.min.js',
|
||||
'src/lib/angular/angular-route.min.js',
|
||||
'src/lib/angular/angular-animate.min.js',
|
||||
'src/lib/ngtagsinput/ng-tags-input.min.js',
|
||||
'node_modules/ng-infinite-scroll/build/ng-infinite-scroll.min.js',
|
||||
'src/lib/fastclick/fastclick.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',
|
||||
'dist/js/app.browserified.js'
|
||||
]
|
||||
},
|
||||
options: {
|
||||
mangle: false,
|
||||
sourceMap: true,
|
||||
sourceMapIn: 'dist/js/app.browserified.js.map',
|
||||
sourceMapIncludeSources: true,
|
||||
sourceMapName: 'dist/js/app.min.js.map'
|
||||
}
|
||||
},
|
||||
readSandbox: {
|
||||
files: {
|
||||
'dist/js/read-sandbox.min.js': [
|
||||
'node_modules/dompurify/purify.js',
|
||||
'src/js/controller/read-sandbox.js'
|
||||
]
|
||||
},
|
||||
options: {
|
||||
sourceMap: true,
|
||||
sourceMapName: 'dist/js/read-sandbox.min.js.map'
|
||||
}
|
||||
},
|
||||
pbkdf2Worker: {
|
||||
files: {
|
||||
'dist/js/pbkdf2-worker.min.js': ['dist/js/pbkdf2-worker.browserified.js']
|
||||
}
|
||||
},
|
||||
mailreaderWorker: {
|
||||
files: {
|
||||
'dist/js/mailreader-parser-worker.min.js': ['dist/js/mailreader-parser-worker.browserified.js']
|
||||
},
|
||||
options: {
|
||||
sourceMap: true,
|
||||
sourceMapName: 'dist/js/mailreader-parser-worker.min.js.map'
|
||||
}
|
||||
},
|
||||
tlsWorker: {
|
||||
files: {
|
||||
'dist/js/tcp-socket-tls-worker.min.js': ['dist/js/tcp-socket-tls-worker.browserified.js']
|
||||
},
|
||||
options: {
|
||||
sourceMap: true,
|
||||
sourceMapName: 'dist/js/tcp-socket-tls-worker.min.js.map'
|
||||
}
|
||||
},
|
||||
unitTest: {
|
||||
files: {
|
||||
'test/unit/index.js': [
|
||||
'src/lib/underscore/underscore-min.js',
|
||||
'node_modules/jquery/dist/jquery.min.js',
|
||||
'src/lib/angular/angular.min.js',
|
||||
'src/lib/angular/angular-route.min.js',
|
||||
'src/lib/angular/angular-animate.min.js',
|
||||
'node_modules/angularjs/src/ngMock/angular-mocks.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',
|
||||
'test/unit/index.browserified.js'
|
||||
]
|
||||
},
|
||||
options: {
|
||||
mangle: false,
|
||||
sourceMap: true,
|
||||
sourceMapIn: 'test/unit/index.browserified.js.map',
|
||||
sourceMapIncludeSources: true,
|
||||
sourceMapName: 'test/unit/index.js.map'
|
||||
}
|
||||
},
|
||||
integrationTest: {
|
||||
files: {
|
||||
'test/integration/index.js': [
|
||||
'src/lib/underscore/underscore-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',
|
||||
'test/integration/index.browserified.js'
|
||||
]
|
||||
},
|
||||
options: {
|
||||
mangle: false,
|
||||
sourceMap: true,
|
||||
sourceMapIn: 'test/integration/index.browserified.js.map',
|
||||
sourceMapIncludeSources: true,
|
||||
sourceMapName: 'test/integration/index.js.map'
|
||||
}
|
||||
},
|
||||
options: {
|
||||
banner: '/*! Copyright © <%= grunt.template.today("yyyy") %>, Whiteout Networks GmbH.*/\n'
|
||||
}
|
||||
},
|
||||
|
||||
copy: {
|
||||
npmDev: {
|
||||
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'],
|
||||
cwd: './',
|
||||
src: [
|
||||
'node_modules/mocha/mocha.css',
|
||||
'node_modules/mocha/mocha.js',
|
||||
'node_modules/chai/chai.js',
|
||||
'node_modules/sinon/pkg/sinon.js',
|
||||
'node_modules/browsercrow/src/*.js',
|
||||
'node_modules/browsersmtp/src/*.js',
|
||||
'src/lib/openpgp/openpgp.js',
|
||||
'src/lib/openpgp/openpgp.worker.js',
|
||||
'src/lib/forge/forge.min.js',
|
||||
'dist/js/pbkdf2-worker.min.js'
|
||||
],
|
||||
dest: 'test/lib/'
|
||||
},
|
||||
cryptoLib: {
|
||||
expand: true,
|
||||
cwd: 'node_modules/crypto-lib/src/',
|
||||
src: ['*.js'],
|
||||
dest: 'src/js/crypto/'
|
||||
},
|
||||
lib: {
|
||||
expand: true,
|
||||
flatten: true,
|
||||
cwd: 'src/lib/',
|
||||
src: ['**'],
|
||||
dest: 'dist/lib/'
|
||||
},
|
||||
js: {
|
||||
expand: true,
|
||||
cwd: 'src/js/',
|
||||
src: ['**'],
|
||||
src: ['openpgp/openpgp.js', 'openpgp/openpgp.worker.js', 'forge/forge.min.js'],
|
||||
dest: 'dist/js/'
|
||||
},
|
||||
font: {
|
||||
|
@ -170,23 +354,11 @@ module.exports = function(grunt) {
|
|||
src: ['*'],
|
||||
dest: 'dist/tpl/'
|
||||
},
|
||||
ca: {
|
||||
expand: true,
|
||||
cwd: 'src/ca/',
|
||||
src: ['*'],
|
||||
dest: 'dist/ca/'
|
||||
},
|
||||
app: {
|
||||
expand: true,
|
||||
cwd: 'src/',
|
||||
src: ['*.html', '*.js', '*.json', 'manifest.*'],
|
||||
dest: 'dist/'
|
||||
},
|
||||
integration: {
|
||||
expand: true,
|
||||
cwd: 'src/',
|
||||
src: ['**'],
|
||||
dest: 'test/integration/src/'
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -200,16 +372,6 @@ module.exports = function(grunt) {
|
|||
cwd: 'dist/',
|
||||
src: ['**/*'],
|
||||
dest: 'release/'
|
||||
},
|
||||
nodeWebkit: {
|
||||
options: {
|
||||
mode: 'zip',
|
||||
archive: 'release/whiteout-mail_' + zipName + '.nw'
|
||||
},
|
||||
expand: true,
|
||||
cwd: 'dist/',
|
||||
src: ['**/*'],
|
||||
dest: '/'
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -220,31 +382,30 @@ module.exports = function(grunt) {
|
|||
timestamp: true,
|
||||
hash: true,
|
||||
cache: ['socket.io/socket.io.js'],
|
||||
exclude: ['appcache.manifest', 'manifest.webapp'],
|
||||
exclude: [
|
||||
'appcache.manifest',
|
||||
'manifest.webapp',
|
||||
'js/app.min.js.map',
|
||||
'js/app.browserified.js',
|
||||
'js/app.browserified.js.map',
|
||||
'js/crypto/pbkdf2-worker.browserified.js',
|
||||
'js/pbkdf2-worker.browserified.js',
|
||||
'js/read-sandbox.min.js.map'
|
||||
],
|
||||
master: ['index.html']
|
||||
},
|
||||
src: ['**/*.*'],
|
||||
dest: 'dist/appcache.manifest'
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
nodewebkit: {
|
||||
options: {
|
||||
version: '0.9.2', // node-webkit version
|
||||
build_dir: './release/node-webkit/', // Where the build version of my node-webkit app is saved
|
||||
mac: true, // We want to build it for mac
|
||||
win: false, // We want to build it for win
|
||||
linux32: false, // We don't need linux32
|
||||
linux64: false, // We don't need linux64
|
||||
},
|
||||
src: ['./dist/**/*'] // Your node-webkit app
|
||||
},
|
||||
});
|
||||
|
||||
// Load the plugin(s)
|
||||
grunt.loadNpmTasks('grunt-browserify');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-mocha');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-csso');
|
||||
grunt.loadNpmTasks('grunt-contrib-sass');
|
||||
|
@ -252,18 +413,19 @@ module.exports = function(grunt) {
|
|||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-compress');
|
||||
grunt.loadNpmTasks('grunt-node-webkit-builder');
|
||||
grunt.loadNpmTasks('grunt-manifest');
|
||||
grunt.loadNpmTasks('grunt-mocha-phantomjs');
|
||||
grunt.loadNpmTasks('grunt-exorcise');
|
||||
|
||||
// Build tasks
|
||||
grunt.registerTask('dist-npm', ['copy:npm', 'copy:npmDev', 'copy:cryptoLib']);
|
||||
grunt.registerTask('dist-css', ['sass', 'autoprefixer', 'csso']);
|
||||
grunt.registerTask('dist-js', ['browserify', 'exorcise', 'uglify']);
|
||||
grunt.registerTask('dist-copy', ['copy']);
|
||||
grunt.registerTask('dist', ['clean', 'dist-npm', 'dist-css', 'dist-copy', 'manifest']);
|
||||
grunt.registerTask('dist', ['clean', 'dist-css', 'dist-js', 'dist-copy', 'manifest']);
|
||||
|
||||
// Test/Dev tasks
|
||||
grunt.registerTask('dev', ['connect:dev']);
|
||||
grunt.registerTask('test', ['jshint', 'connect:test', 'mocha']);
|
||||
grunt.registerTask('test', ['jshint', 'connect:test', 'mocha_phantomjs']);
|
||||
grunt.registerTask('prod', ['connect:prod']);
|
||||
|
||||
//
|
||||
|
|
33
package.json
33
package.json
|
@ -24,25 +24,27 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "grunt && grunt test",
|
||||
"start": "node server.js"
|
||||
"start": "node server.js",
|
||||
"postinstall": "dir=$(pwd) && cd node_modules/mailreader/ && npm install --production && cd $dir"
|
||||
},
|
||||
"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",
|
||||
"mailreader": "~0.4.0",
|
||||
"morgan": "^1.2.3",
|
||||
"ng-infinite-scroll": "~1.1.2",
|
||||
"npmlog": "^0.1.1",
|
||||
"pgpbuilder": "~0.4.0",
|
||||
"pgpmailer": "~0.4.0",
|
||||
"requirejs": "~2.1.14",
|
||||
"config": "^1.0.2",
|
||||
"morgan": "^1.2.3",
|
||||
"npmlog": "^0.1.1",
|
||||
"socket.io": "^1.0.6"
|
||||
"socket.io": "^1.0.6",
|
||||
"tcp-socket": "~0.3.13",
|
||||
"wo-smtpclient": "^0.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angularjs": "https://github.com/whiteout-io/angular.js/tarball/npm-version",
|
||||
|
@ -50,19 +52,22 @@
|
|||
"browsersmtp": "https://github.com/whiteout-io/browsersmtp/tarball/master",
|
||||
"chai": "~1.7.2",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"grunt-manifest": "^0.4.0",
|
||||
"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-mocha": "~0.4.1",
|
||||
"grunt-node-webkit-builder": "~0.1.17",
|
||||
"mocha": "~1.13.0",
|
||||
"sinon": "~1.7.3"
|
||||
"grunt-exorcise": "^0.2.0",
|
||||
"grunt-manifest": "^0.4.0",
|
||||
"grunt-mocha-phantomjs": "^0.6.0",
|
||||
"mocha": "^1.21.4",
|
||||
"sinon": "~1.7.3",
|
||||
"time-grunt": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
|
||||
<!-- The Scripts -->
|
||||
<script src="socket.io/socket.io.js"></script>
|
||||
<script src="lib/require.js"></script>
|
||||
<script src="require-config.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
<script src="js/openpgp.js"></script>
|
||||
<script src="js/forge.min.js"></script>
|
||||
<script src="js/app.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body key-shortcuts>
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore'),
|
||||
app = {},
|
||||
appVersion, cloudUrl, keychainUrl, clientId;
|
||||
var appVersion, cloudUrl, keychainUrl, clientId;
|
||||
|
||||
// parse manifest to get configurations for current runtime
|
||||
try {
|
||||
// parse manifest to get configurations for current runtime
|
||||
try {
|
||||
var manifest = chrome.runtime.getManifest();
|
||||
// get key server base url
|
||||
cloudUrl = _.find(manifest.permissions, function(permission) {
|
||||
|
@ -24,12 +21,12 @@ define(function(require) {
|
|||
clientId = manifest.oauth2.client_id;
|
||||
// get the app version
|
||||
appVersion = manifest.version;
|
||||
} catch (e) {}
|
||||
} catch (e) {}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Global app configurations
|
||||
*/
|
||||
app.config = {
|
||||
exports.config = {
|
||||
cloudUrl: cloudUrl || 'https://keys.whiteout.io',
|
||||
privkeyServerUrl: keychainUrl || 'https://keychain.whiteout.io',
|
||||
adminUrl: 'https://admin-node.whiteout.io',
|
||||
|
@ -180,12 +177,12 @@ define(function(require) {
|
|||
outboxMailboxType: 'Outbox',
|
||||
connDocTimeout: 5000,
|
||||
imapUpdateBatchSize: 25
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Strings are maintained here
|
||||
*/
|
||||
app.string = {
|
||||
exports.string = {
|
||||
fallbackSubject: '(no subject)',
|
||||
invitationSubject: 'Invitation to a private conversation',
|
||||
invitationMessage: 'Hi,\n\nI use Whiteout Mail to send and receive encrypted email. I would like to exchange encrypted messages with you as well.\n\nPlease install the Whiteout Mail application. This application makes it easy to read and write messages securely with PGP encryption applied.\n\nGo to the Whiteout Networks homepage to learn more and to download the application: https://whiteout.io\n\n',
|
||||
|
@ -217,7 +214,4 @@ define(function(require) {
|
|||
connDocAuthRejected: 'Your credentials for {0} were rejected. Please check your username and password!',
|
||||
connDocNoInbox: 'We could not detect an IMAP inbox folder on {0}. Please have a look at the FAQ for information on how to fix this error.',
|
||||
connDocGenericError: 'There was an error connecting to {0}: {1}'
|
||||
};
|
||||
|
||||
return app;
|
||||
});
|
||||
};
|
|
@ -1,46 +1,46 @@
|
|||
/**
|
||||
* The main application controller
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var axe = require('axe'),
|
||||
Auth = require('js/bo/auth'),
|
||||
PGP = require('js/crypto/pgp'),
|
||||
'use strict';
|
||||
|
||||
var axe = require('axe-logger'),
|
||||
Auth = require('./bo/auth'),
|
||||
PGP = require('./crypto/pgp'),
|
||||
PgpMailer = require('pgpmailer'),
|
||||
OAuth = require('js/util/oauth'),
|
||||
OAuth = require('./util/oauth'),
|
||||
PgpBuilder = require('pgpbuilder'),
|
||||
OutboxBO = require('js/bo/outbox'),
|
||||
OutboxBO = require('./bo/outbox'),
|
||||
mailreader = require('mailreader'),
|
||||
ImapClient = require('imap-client'),
|
||||
Crypto = require('js/crypto/crypto'),
|
||||
RestDAO = require('js/dao/rest-dao'),
|
||||
appConfig = require('js/app-config'),
|
||||
EmailDAO = require('js/dao/email-dao'),
|
||||
AdminDao = require('js/dao/admin-dao'),
|
||||
KeychainDAO = require('js/dao/keychain-dao'),
|
||||
PublicKeyDAO = require('js/dao/publickey-dao'),
|
||||
LawnchairDAO = require('js/dao/lawnchair-dao'),
|
||||
PrivateKeyDAO = require('js/dao/privatekey-dao'),
|
||||
InvitationDAO = require('js/dao/invitation-dao'),
|
||||
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||
ConnectionDoctor = require('js/util/connection-doctor'),
|
||||
UpdateHandler = require('js/util/update/update-handler'),
|
||||
Crypto = require('./crypto/crypto'),
|
||||
RestDAO = require('./dao/rest-dao'),
|
||||
appConfig = require('./app-config'),
|
||||
EmailDAO = require('./dao/email-dao'),
|
||||
AdminDao = require('./dao/admin-dao'),
|
||||
KeychainDAO = require('./dao/keychain-dao'),
|
||||
PublicKeyDAO = require('./dao/publickey-dao'),
|
||||
LawnchairDAO = require('./dao/lawnchair-dao'),
|
||||
PrivateKeyDAO = require('./dao/privatekey-dao'),
|
||||
InvitationDAO = require('./dao/invitation-dao'),
|
||||
DeviceStorageDAO = require('./dao/devicestorage-dao'),
|
||||
ConnectionDoctor = require('./util/connection-doctor'),
|
||||
UpdateHandler = require('./util/update/update-handler'),
|
||||
config = appConfig.config,
|
||||
str = appConfig.string;
|
||||
|
||||
var self = {};
|
||||
var ctrl = {};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Start the application.
|
||||
*/
|
||||
self.start = function(options, callback) {
|
||||
if (self.started) {
|
||||
ctrl.start = function(options, callback) {
|
||||
if (ctrl.started) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
self.started = true;
|
||||
self.onError = options.onError;
|
||||
ctrl.started = true;
|
||||
ctrl.onError = options.onError;
|
||||
|
||||
// are we running in a cordova app or in a browser environment?
|
||||
if (window.cordova) {
|
||||
|
@ -56,24 +56,24 @@ define(function(require) {
|
|||
function onDeviceReady() {
|
||||
axe.debug('Starting app.');
|
||||
|
||||
self.buildModules();
|
||||
ctrl.buildModules();
|
||||
|
||||
// Handle offline and online gracefully
|
||||
window.addEventListener('online', self.onConnect.bind(self, self.onError));
|
||||
window.addEventListener('offline', self.onDisconnect.bind(self));
|
||||
window.addEventListener('online', ctrl.onConnect.bind(ctrl, ctrl.onError));
|
||||
window.addEventListener('offline', ctrl.onDisconnect.bind(ctrl));
|
||||
|
||||
self._appConfigStore.init('app-config', callback);
|
||||
ctrl._appConfigStore.init('app-config', callback);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Initialize the dependency tree.
|
||||
*/
|
||||
self.buildModules = function() {
|
||||
ctrl.buildModules = function() {
|
||||
var lawnchairDao, restDao, pubkeyDao, privkeyDao, crypto, emailDao, keychain, pgp, userStorage, pgpbuilder, oauth, appConfigStore, auth;
|
||||
|
||||
// start the mailreader's worker thread
|
||||
mailreader.startWorker(config.workerPath + '/../lib/mailreader-parser-worker.js');
|
||||
mailreader.startWorker(config.workerPath + '/mailreader-parser-worker.min.js');
|
||||
|
||||
// init objects and inject dependencies
|
||||
restDao = new RestDAO();
|
||||
|
@ -83,13 +83,13 @@ define(function(require) {
|
|||
oauth = new OAuth(new RestDAO('https://www.googleapis.com'));
|
||||
|
||||
crypto = new Crypto();
|
||||
self._pgp = pgp = new PGP();
|
||||
self._keychain = keychain = new KeychainDAO(lawnchairDao, pubkeyDao, privkeyDao, crypto, pgp);
|
||||
ctrl._pgp = pgp = new PGP();
|
||||
ctrl._keychain = keychain = new KeychainDAO(lawnchairDao, pubkeyDao, privkeyDao, crypto, pgp);
|
||||
keychain.requestPermissionForKeyUpdate = function(params, callback) {
|
||||
var message = params.newKey ? str.updatePublicKeyMsgNewKey : str.updatePublicKeyMsgRemovedKey;
|
||||
message = message.replace('{0}', params.userId);
|
||||
|
||||
self.onError({
|
||||
ctrl.onError({
|
||||
title: str.updatePublicKeyTitle,
|
||||
message: message,
|
||||
positiveBtnStr: str.updatePublicKeyPosBtn,
|
||||
|
@ -99,40 +99,40 @@ define(function(require) {
|
|||
});
|
||||
};
|
||||
|
||||
self._appConfigStore = appConfigStore = new DeviceStorageDAO(new LawnchairDAO());
|
||||
self._auth = auth = new Auth(appConfigStore, oauth, pgp);
|
||||
self._userStorage = userStorage = new DeviceStorageDAO(lawnchairDao);
|
||||
self._invitationDao = new InvitationDAO(restDao);
|
||||
self._pgpbuilder = pgpbuilder = new PgpBuilder();
|
||||
self._emailDao = emailDao = new EmailDAO(keychain, pgp, userStorage, pgpbuilder, mailreader);
|
||||
self._outboxBo = new OutboxBO(emailDao, keychain, userStorage);
|
||||
self._updateHandler = new UpdateHandler(appConfigStore, userStorage, auth);
|
||||
self._adminDao = new AdminDao(new RestDAO(config.adminUrl));
|
||||
self._doctor = new ConnectionDoctor();
|
||||
ctrl._appConfigStore = appConfigStore = new DeviceStorageDAO(new LawnchairDAO());
|
||||
ctrl._auth = auth = new Auth(appConfigStore, oauth, pgp);
|
||||
ctrl._userStorage = userStorage = new DeviceStorageDAO(lawnchairDao);
|
||||
ctrl._invitationDao = new InvitationDAO(restDao);
|
||||
ctrl._pgpbuilder = pgpbuilder = new PgpBuilder();
|
||||
ctrl._emailDao = emailDao = new EmailDAO(keychain, pgp, userStorage, pgpbuilder, mailreader);
|
||||
ctrl._outboxBo = new OutboxBO(emailDao, keychain, userStorage);
|
||||
ctrl._updateHandler = new UpdateHandler(appConfigStore, userStorage, auth);
|
||||
ctrl._adminDao = new AdminDao(new RestDAO(config.adminUrl));
|
||||
ctrl._doctor = new ConnectionDoctor();
|
||||
|
||||
emailDao.onError = self.onError;
|
||||
};
|
||||
emailDao.onError = ctrl.onError;
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Calls runtime hooks to check if an app update is available.
|
||||
*/
|
||||
self.checkForUpdate = function() {
|
||||
self._updateHandler.checkForUpdate(self.onError);
|
||||
};
|
||||
ctrl.checkForUpdate = function() {
|
||||
ctrl._updateHandler.checkForUpdate(ctrl.onError);
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Instanciate the mail email data access object and its dependencies. Login to imap on init.
|
||||
*/
|
||||
self.init = function(options, callback) {
|
||||
ctrl.init = function(options, callback) {
|
||||
// init user's local database
|
||||
self._userStorage.init(options.emailAddress, function(err) {
|
||||
ctrl._userStorage.init(options.emailAddress, function(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Migrate the databases if necessary
|
||||
self._updateHandler.update(onUpdate);
|
||||
ctrl._updateHandler.update(onUpdate);
|
||||
});
|
||||
|
||||
function onUpdate(err) {
|
||||
|
@ -152,7 +152,7 @@ define(function(require) {
|
|||
};
|
||||
|
||||
// init email dao
|
||||
self._emailDao.init({
|
||||
ctrl._emailDao.init({
|
||||
account: account
|
||||
}, function(err, keypair) {
|
||||
if (err) {
|
||||
|
@ -163,39 +163,37 @@ define(function(require) {
|
|||
callback(null, keypair);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check if the user agent is online.
|
||||
*/
|
||||
self.isOnline = function() {
|
||||
ctrl.isOnline = function() {
|
||||
return navigator.onLine;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Event handler that is called when the user agent goes offline.
|
||||
*/
|
||||
self.onDisconnect = function() {
|
||||
self._emailDao.onDisconnect();
|
||||
};
|
||||
ctrl.onDisconnect = function() {
|
||||
ctrl._emailDao.onDisconnect();
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Log the current user out by clear the app config store and deleting instances of imap-client and pgp-mailer.
|
||||
*/
|
||||
self.logout = function() {
|
||||
var self = this;
|
||||
|
||||
ctrl.logout = function() {
|
||||
// clear app config store
|
||||
self._auth.logout(function(err) {
|
||||
ctrl._auth.logout(function(err) {
|
||||
if (err) {
|
||||
self.onError(err);
|
||||
ctrl.onError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// delete instance of imap-client and pgp-mailer
|
||||
self._emailDao.onDisconnect(function(err) {
|
||||
ctrl._emailDao.onDisconnect(function(err) {
|
||||
if (err) {
|
||||
self.onError(err);
|
||||
ctrl.onError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -203,19 +201,19 @@ define(function(require) {
|
|||
window.location.href = '/';
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Event that is called when the user agent goes online. This create new instances of the imap-client and pgp-mailer and connects to the mail server.
|
||||
*/
|
||||
self.onConnect = function(callback) {
|
||||
if (!self.isOnline() || !self._emailDao || !self._emailDao._account) {
|
||||
ctrl.onConnect = function(callback) {
|
||||
if (!ctrl.isOnline() || !ctrl._emailDao || !ctrl._emailDao._account) {
|
||||
// prevent connection infinite loop
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
self._auth.getCredentials(function(err, credentials) {
|
||||
ctrl._auth.getCredentials(function(err, credentials) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
|
@ -228,22 +226,25 @@ define(function(require) {
|
|||
// add the maximum update batch size for imap folders to the imap configuration
|
||||
credentials.imap.maxUpdateSize = config.imapUpdateBatchSize;
|
||||
|
||||
var pgpMailer = new PgpMailer(credentials.smtp, self._pgpbuilder);
|
||||
// tls socket worker path for multithreaded tls in non-native tls environments
|
||||
credentials.imap.tlsWorkerPath = credentials.smtp.tlsWorkerPath = config.workerPath + '/tcp-socket-tls-worker.min.js';
|
||||
|
||||
var pgpMailer = new PgpMailer(credentials.smtp, ctrl._pgpbuilder);
|
||||
var imapClient = new ImapClient(credentials.imap);
|
||||
imapClient.onError = onConnectionError;
|
||||
pgpMailer.onError = onConnectionError;
|
||||
|
||||
// certificate update handling
|
||||
imapClient.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'imap', self.onConnect, self.onError);
|
||||
pgpMailer.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'smtp', self.onConnect, self.onError);
|
||||
imapClient.onCert = ctrl._auth.handleCertificateUpdate.bind(ctrl._auth, 'imap', ctrl.onConnect, ctrl.onError);
|
||||
pgpMailer.onCert = ctrl._auth.handleCertificateUpdate.bind(ctrl._auth, 'smtp', ctrl.onConnect, ctrl.onError);
|
||||
|
||||
// after-setup configuration depending on the provider:
|
||||
// gmail does not require you to upload to the sent items folder
|
||||
// after successful sending, whereas most other providers do
|
||||
self._emailDao.ignoreUploadOnSent = !!(config[self._auth.provider] && config[self._auth.provider].ignoreUploadOnSent);
|
||||
ctrl._emailDao.ignoreUploadOnSent = !!(config[ctrl._auth.provider] && config[ctrl._auth.provider].ignoreUploadOnSent);
|
||||
|
||||
// connect to clients
|
||||
self._emailDao.onConnect({
|
||||
ctrl._emailDao.onConnect({
|
||||
imapClient: imapClient,
|
||||
pgpMailer: pgpMailer
|
||||
}, callback);
|
||||
|
@ -255,7 +256,7 @@ define(function(require) {
|
|||
setTimeout(function() {
|
||||
axe.debug('Reconnecting...');
|
||||
// re-init client modules on error
|
||||
self.onConnect(function(err) {
|
||||
ctrl.onConnect(function(err) {
|
||||
if (err) {
|
||||
axe.error('Reconnect attempt failed! ' + (err.errMsg || err.message) + (err.stack ? ('\n' + err.stack) : ''));
|
||||
return;
|
||||
|
@ -265,7 +266,6 @@ define(function(require) {
|
|||
});
|
||||
}, config.reconnectInterval);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return self;
|
||||
});
|
||||
module.exports = ctrl;
|
||||
|
|
122
src/js/app.js
122
src/js/app.js
|
@ -14,67 +14,29 @@ if (typeof window.applicationCache !== 'undefined') {
|
|||
};
|
||||
}
|
||||
|
||||
// hey Angular, we're bootstrapping manually!
|
||||
window.name = 'NG_DEFER_BOOTSTRAP!';
|
||||
var DialogCtrl = require('./controller/dialog'),
|
||||
PopoverCtrl = require('./controller/popover'),
|
||||
AddAccountCtrl = require('./controller/add-account'),
|
||||
AccountCtrl = require('./controller/account'),
|
||||
SetPassphraseCtrl = require('./controller/set-passphrase'),
|
||||
PrivateKeyUploadCtrl = require('./controller/privatekey-upload'),
|
||||
ContactsCtrl = require('./controller/contacts'),
|
||||
AboutCtrl = require('./controller/about'),
|
||||
LoginCtrl = require('./controller/login'),
|
||||
LoginInitialCtrl = require('./controller/login-initial'),
|
||||
LoginNewDeviceCtrl = require('./controller/login-new-device'),
|
||||
LoginExistingCtrl = require('./controller/login-existing'),
|
||||
LoginPrivateKeyDownloadCtrl = require('./controller/login-privatekey-download'),
|
||||
LoginSetCredentialsCtrl = require('./controller/login-set-credentials'),
|
||||
MailListCtrl = require('./controller/mail-list'),
|
||||
ReadCtrl = require('./controller/read'),
|
||||
WriteCtrl = require('./controller/write'),
|
||||
NavigationCtrl = require('./controller/navigation'),
|
||||
errorUtil = require('./util/error'),
|
||||
backButtonUtil = require('./util/backbutton-handler');
|
||||
|
||||
requirejs([
|
||||
'angular',
|
||||
'js/controller/dialog',
|
||||
'js/controller/popover',
|
||||
'js/controller/add-account',
|
||||
'js/controller/account',
|
||||
'js/controller/set-passphrase',
|
||||
'js/controller/privatekey-upload',
|
||||
'js/controller/contacts',
|
||||
'js/controller/about',
|
||||
'js/controller/login',
|
||||
'js/controller/login-initial',
|
||||
'js/controller/login-new-device',
|
||||
'js/controller/login-existing',
|
||||
'js/controller/login-privatekey-download',
|
||||
'js/controller/login-set-credentials',
|
||||
'js/controller/mail-list',
|
||||
'js/controller/read',
|
||||
'js/controller/write',
|
||||
'js/controller/navigation',
|
||||
'js/crypto/util',
|
||||
'js/util/error',
|
||||
'js/util/backbutton-handler',
|
||||
'fastclick',
|
||||
'angularRoute',
|
||||
'angularAnimate',
|
||||
'ngInfiniteScroll',
|
||||
'ngTagsInput'
|
||||
], function(
|
||||
angular,
|
||||
DialogCtrl,
|
||||
PopoverCtrl,
|
||||
AddAccountCtrl,
|
||||
AccountCtrl,
|
||||
SetPassphraseCtrl,
|
||||
PrivateKeyUploadCtrl,
|
||||
ContactsCtrl,
|
||||
AboutCtrl,
|
||||
LoginCtrl,
|
||||
LoginInitialCtrl,
|
||||
LoginNewDeviceCtrl,
|
||||
LoginExistingCtrl,
|
||||
LoginPrivateKeyDownloadCtrl,
|
||||
LoginSetCredentialsCtrl,
|
||||
MailListCtrl,
|
||||
ReadCtrl,
|
||||
WriteCtrl,
|
||||
NavigationCtrl,
|
||||
util,
|
||||
errorUtil,
|
||||
backButtonUtil,
|
||||
FastClick
|
||||
) {
|
||||
// reset window.name
|
||||
window.name = util.UUID();
|
||||
|
||||
// init main angular module including dependencies
|
||||
var app = angular.module('mail', [
|
||||
// init main angular module including dependencies
|
||||
var app = angular.module('mail', [
|
||||
'ngRoute',
|
||||
'ngAnimate',
|
||||
'navigation',
|
||||
|
@ -87,10 +49,10 @@ requirejs([
|
|||
'popover',
|
||||
'infinite-scroll',
|
||||
'ngTagsInput'
|
||||
]);
|
||||
]);
|
||||
|
||||
// set router paths
|
||||
app.config(function($routeProvider) {
|
||||
// set router paths
|
||||
app.config(function($routeProvider) {
|
||||
$routeProvider.when('/add-account', {
|
||||
templateUrl: 'tpl/add-account.html',
|
||||
controller: AddAccountCtrl
|
||||
|
@ -126,9 +88,9 @@ requirejs([
|
|||
$routeProvider.otherwise({
|
||||
redirectTo: '/login'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.run(function($rootScope) {
|
||||
app.run(function($rootScope) {
|
||||
// global state... inherited to all child scopes
|
||||
$rootScope.state = {};
|
||||
|
||||
|
@ -140,22 +102,16 @@ requirejs([
|
|||
|
||||
// attach fastclick
|
||||
FastClick.attach(document.body);
|
||||
});
|
||||
|
||||
// inject controllers from ng-included view templates
|
||||
app.controller('ReadCtrl', ReadCtrl);
|
||||
app.controller('WriteCtrl', WriteCtrl);
|
||||
app.controller('MailListCtrl', MailListCtrl);
|
||||
app.controller('AccountCtrl', AccountCtrl);
|
||||
app.controller('SetPassphraseCtrl', SetPassphraseCtrl);
|
||||
app.controller('PrivateKeyUploadCtrl', PrivateKeyUploadCtrl);
|
||||
app.controller('ContactsCtrl', ContactsCtrl);
|
||||
app.controller('AboutCtrl', AboutCtrl);
|
||||
app.controller('DialogCtrl', DialogCtrl);
|
||||
app.controller('PopoverCtrl', PopoverCtrl);
|
||||
|
||||
// manually bootstrap angular due to require.js
|
||||
angular.element().ready(function() {
|
||||
angular.bootstrap(document, ['mail']);
|
||||
});
|
||||
});
|
||||
|
||||
// inject controllers from ng-included view templates
|
||||
app.controller('ReadCtrl', ReadCtrl);
|
||||
app.controller('WriteCtrl', WriteCtrl);
|
||||
app.controller('MailListCtrl', MailListCtrl);
|
||||
app.controller('AccountCtrl', AccountCtrl);
|
||||
app.controller('SetPassphraseCtrl', SetPassphraseCtrl);
|
||||
app.controller('PrivateKeyUploadCtrl', PrivateKeyUploadCtrl);
|
||||
app.controller('ContactsCtrl', ContactsCtrl);
|
||||
app.controller('AboutCtrl', AboutCtrl);
|
||||
app.controller('DialogCtrl', DialogCtrl);
|
||||
app.controller('PopoverCtrl', PopoverCtrl);
|
|
@ -1,18 +1,17 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var axe = require('axe'),
|
||||
str = require('js/app-config').string;
|
||||
var axe = require('axe-logger'),
|
||||
str = require('../app-config').string;
|
||||
|
||||
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';
|
||||
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';
|
||||
|
||||
/**
|
||||
/**
|
||||
* The Auth BO handles the rough edges and gaps between user/password authentication
|
||||
* and OAuth via Chrome Identity API.
|
||||
* Typical usage:
|
||||
|
@ -22,13 +21,13 @@ define(function(require) {
|
|||
* auth.getCredentials(...); // called to gather all the information to connect to IMAP/SMTP, e.g. pinned intermediate certificates,
|
||||
* username, password / oauth token, IMAP/SMTP server host names, ...
|
||||
*/
|
||||
var Auth = function(appConfigStore, oauth, pgp) {
|
||||
var Auth = function(appConfigStore, oauth, pgp) {
|
||||
this._appConfigStore = appConfigStore;
|
||||
this._oauth = oauth;
|
||||
this._pgp = pgp;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Retrieves credentials and IMAP/SMTP settings:
|
||||
* 1) Fetches the credentials from disk, then...
|
||||
* 2 a) ... in an oauth setting, retrieves a fresh oauth token from the Chrome Identity API.
|
||||
|
@ -37,7 +36,7 @@ define(function(require) {
|
|||
*
|
||||
* @param {Function} callback(err, credentials)
|
||||
*/
|
||||
Auth.prototype.getCredentials = function(callback) {
|
||||
Auth.prototype.getCredentials = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (!self.provider || !self.emailAddress) {
|
||||
|
@ -115,9 +114,9 @@ define(function(require) {
|
|||
|
||||
callback(null, credentials);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Set the credentials
|
||||
*
|
||||
* @param {String} options.provider The service provider, e.g. 'gmail', 'yahoo', 'tonline'. Matches the entry in the app-config.
|
||||
|
@ -128,7 +127,7 @@ define(function(require) {
|
|||
* @param {String} options.smtp The smtp settings (host, port, secure)
|
||||
* @param {String} options.imap The imap settings (host, port, secure)
|
||||
*/
|
||||
Auth.prototype.setCredentials = function(options) {
|
||||
Auth.prototype.setCredentials = function(options) {
|
||||
this.credentialsDirty = true;
|
||||
this.provider = options.provider;
|
||||
this.emailAddress = options.emailAddress;
|
||||
|
@ -137,9 +136,9 @@ define(function(require) {
|
|||
this.password = options.password;
|
||||
this.smtp = options.smtp; // host, port, secure, ca, pinned
|
||||
this.imap = options.imap; // host, port, secure, ca, pinned
|
||||
};
|
||||
};
|
||||
|
||||
Auth.prototype.storeCredentials = function(callback) {
|
||||
Auth.prototype.storeCredentials = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (!self.credentialsDirty) {
|
||||
|
@ -215,12 +214,12 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the email address. Loads it from disk, if necessary
|
||||
*/
|
||||
Auth.prototype.getEmailAddress = function(callback) {
|
||||
Auth.prototype.getEmailAddress = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (self.emailAddress) {
|
||||
|
@ -240,9 +239,9 @@ define(function(require) {
|
|||
realname: self.realname
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* READ FIRST b/c usage of the oauth api is weird.
|
||||
* the chrome identity api will let you query an oauth token for an email account without knowing
|
||||
* the corresponding email address. also, android has multiple accounts whereas desktop chrome only
|
||||
|
@ -253,7 +252,7 @@ define(function(require) {
|
|||
* is android only, since the desktop chrome will query the user that is logged into chrome
|
||||
* 3) fetch the email address for the oauth token from the chrome identity api
|
||||
*/
|
||||
Auth.prototype.getOAuthToken = function(callback) {
|
||||
Auth.prototype.getOAuthToken = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (self.oauthToken) {
|
||||
|
@ -289,12 +288,12 @@ define(function(require) {
|
|||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Loads email address, password, provider, ... from disk and sets them on `this`
|
||||
*/
|
||||
Auth.prototype._loadCredentials = function(callback) {
|
||||
Auth.prototype._loadCredentials = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (self.initialized) {
|
||||
|
@ -364,15 +363,15 @@ define(function(require) {
|
|||
callback(err, (!err && cachedItems && cachedItems[0]));
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Handles certificate updates and errors by notifying the user.
|
||||
* @param {String} component Either imap or smtp
|
||||
* @param {Function} callback The error handler
|
||||
* @param {[type]} pemEncodedCert The PEM encoded SSL certificate
|
||||
*/
|
||||
Auth.prototype.handleCertificateUpdate = function(component, onConnect, callback, pemEncodedCert) {
|
||||
Auth.prototype.handleCertificateUpdate = function(component, onConnect, callback, pemEncodedCert) {
|
||||
var self = this;
|
||||
|
||||
axe.debug('new ssl certificate received: ' + pemEncodedCert);
|
||||
|
@ -424,12 +423,12 @@ define(function(require) {
|
|||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Logout of the app by clearing the app config store and in memory credentials
|
||||
*/
|
||||
Auth.prototype.logout = function(callback) {
|
||||
Auth.prototype.logout = function(callback) {
|
||||
var self = this;
|
||||
|
||||
// clear app config db
|
||||
|
@ -447,7 +446,6 @@ define(function(require) {
|
|||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return Auth;
|
||||
});
|
||||
module.exports = Auth;
|
|
@ -1,17 +1,15 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore'),
|
||||
util = require('js/crypto/util'),
|
||||
config = require('js/app-config').config,
|
||||
var util = require('crypto-lib').util,
|
||||
config = require('../app-config').config,
|
||||
outboxDb = 'email_OUTBOX';
|
||||
|
||||
/**
|
||||
/**
|
||||
* High level business object that orchestrates the local outbox.
|
||||
* The local outbox takes care of the emails before they are being sent.
|
||||
* It also checks periodically if there are any mails in the local device storage to be sent.
|
||||
*/
|
||||
var OutboxBO = function(emailDao, keychain, devicestorage) {
|
||||
var OutboxBO = function(emailDao, keychain, devicestorage) {
|
||||
/** @private */
|
||||
this._emailDao = emailDao;
|
||||
|
||||
|
@ -25,37 +23,37 @@ define(function(require) {
|
|||
* Semaphore-esque flag to avoid 'concurrent' calls to _processOutbox when the timeout fires, but a call is still in process.
|
||||
* @private */
|
||||
this._outboxBusy = false;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* This function activates the periodic checking of the local device storage for pending mails.
|
||||
* @param {Function} callback(error, pendingMailsCount) Callback that informs you about the count of pending mails.
|
||||
*/
|
||||
OutboxBO.prototype.startChecking = function(callback) {
|
||||
OutboxBO.prototype.startChecking = function(callback) {
|
||||
// remember global callback
|
||||
this._onUpdate = callback;
|
||||
// start periodic checking of outbox
|
||||
this._intervalId = setInterval(this._processOutbox.bind(this, this._onUpdate), config.checkOutboxInterval);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Outbox stops the periodic checking of the local device storage for pending mails.
|
||||
*/
|
||||
OutboxBO.prototype.stopChecking = function() {
|
||||
OutboxBO.prototype.stopChecking = function() {
|
||||
if (!this._intervalId) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearInterval(this._intervalId);
|
||||
delete this._intervalId;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Put a email dto in the outbox for sending when ready
|
||||
* @param {Object} mail The Email DTO
|
||||
* @param {Function} callback Invoked when the object was encrypted and persisted to disk
|
||||
*/
|
||||
OutboxBO.prototype.put = function(mail, callback) {
|
||||
OutboxBO.prototype.put = function(mail, callback) {
|
||||
var self = this,
|
||||
allReaders = mail.from.concat(mail.to.concat(mail.cc.concat(mail.bcc))); // all the users that should be able to read the mail
|
||||
|
||||
|
@ -129,13 +127,13 @@ define(function(require) {
|
|||
self._processOutbox(self._onUpdate);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks the local device storage for pending mails.
|
||||
* @param {Function} callback(error, pendingMailsCount) Callback that informs you about the count of pending mails.
|
||||
*/
|
||||
OutboxBO.prototype._processOutbox = function(callback) {
|
||||
OutboxBO.prototype._processOutbox = function(callback) {
|
||||
var self = this,
|
||||
unsentMails = 0;
|
||||
|
||||
|
@ -226,7 +224,6 @@ define(function(require) {
|
|||
done();
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return OutboxBO;
|
||||
});
|
||||
module.exports = OutboxBO;
|
|
@ -1,13 +1,12 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var cfg = require('js/app-config').config;
|
||||
var cfg = require('../app-config').config;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var AboutCtrl = function($scope) {
|
||||
var AboutCtrl = function($scope) {
|
||||
|
||||
$scope.state.about = {
|
||||
toggle: function(to) {
|
||||
|
@ -25,7 +24,6 @@ define(function(require) {
|
|||
//
|
||||
// scope functions
|
||||
//
|
||||
};
|
||||
};
|
||||
|
||||
return AboutCtrl;
|
||||
});
|
||||
module.exports = AboutCtrl;
|
|
@ -1,16 +1,15 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var appController = require('js/app-controller'),
|
||||
dl = require('js/util/download'),
|
||||
config = require('js/app-config').config,
|
||||
var appController = require('../app-controller'),
|
||||
dl = require('../util/download'),
|
||||
config = require('../app-config').config,
|
||||
pgp, keychain, userId;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var AccountCtrl = function($scope) {
|
||||
var AccountCtrl = function($scope) {
|
||||
userId = appController._emailDao._account.emailAddress;
|
||||
keychain = appController._keychain;
|
||||
pgp = appController._pgp;
|
||||
|
@ -55,7 +54,6 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return AccountCtrl;
|
||||
});
|
||||
module.exports = AccountCtrl;
|
|
@ -1,10 +1,9 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var appCtrl = require('js/app-controller'),
|
||||
cfg = require('js/app-config').config;
|
||||
var appCtrl = require('../app-controller'),
|
||||
cfg = require('../app-config').config;
|
||||
|
||||
var AddAccountCtrl = function($scope, $location, $routeParams) {
|
||||
var AddAccountCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appCtrl._auth && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
|
@ -114,7 +113,6 @@ define(function(require) {
|
|||
provider: provider
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return AddAccountCtrl;
|
||||
});
|
||||
module.exports = AddAccountCtrl;
|
|
@ -1,16 +1,13 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var angular = require('angular'),
|
||||
_ = require('underscore'),
|
||||
appController = require('js/app-controller'),
|
||||
var appController = require('../app-controller'),
|
||||
keychain, pgp;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var ContactsCtrl = function($scope) {
|
||||
var ContactsCtrl = function($scope) {
|
||||
keychain = appController._keychain,
|
||||
pgp = appController._pgp;
|
||||
|
||||
|
@ -104,15 +101,15 @@ define(function(require) {
|
|||
$scope.listKeys();
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
|
||||
var ngModule = angular.module('contacts', []);
|
||||
var ngModule = angular.module('contacts', []);
|
||||
|
||||
ngModule.directive('keyfileInput', function() {
|
||||
ngModule.directive('keyfileInput', function() {
|
||||
return function(scope, elm) {
|
||||
elm.on('change', function(e) {
|
||||
for (var i = 0; i < e.target.files.length; i++) {
|
||||
|
@ -128,16 +125,15 @@ define(function(require) {
|
|||
reader.readAsText(file);
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
ngModule.directive('keyfileBtn', function() {
|
||||
ngModule.directive('keyfileBtn', function() {
|
||||
return function(scope, elm) {
|
||||
elm.on('click touchstart', function(e) {
|
||||
e.preventDefault();
|
||||
document.querySelector('#keyfile-input').click();
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return ContactsCtrl;
|
||||
});
|
||||
|
||||
module.exports = ContactsCtrl;
|
|
@ -1,7 +1,6 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var DialogCtrl = function($scope) {
|
||||
var DialogCtrl = function($scope) {
|
||||
$scope.confirm = function(ok) {
|
||||
$scope.state.dialog.open = false;
|
||||
|
||||
|
@ -10,7 +9,6 @@ define(function() {
|
|||
}
|
||||
$scope.state.dialog.callback = undefined;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return DialogCtrl;
|
||||
});
|
||||
module.exports = DialogCtrl;
|
|
@ -1,9 +1,8 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var appController = require('js/app-controller');
|
||||
var appController = require('../app-controller');
|
||||
|
||||
var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
|
@ -67,7 +66,6 @@ define(function(require) {
|
|||
$scope.buttonEnabled = true;
|
||||
$scope.onError(err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return LoginExistingCtrl;
|
||||
});
|
||||
module.exports = LoginExistingCtrl;
|
|
@ -1,9 +1,8 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var appController = require('js/app-controller');
|
||||
var appController = require('../app-controller');
|
||||
|
||||
var LoginInitialCtrl = function($scope, $location, $routeParams) {
|
||||
var LoginInitialCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
|
@ -115,7 +114,6 @@ define(function(require) {
|
|||
$scope.setState = function(state) {
|
||||
$scope.state.ui = state;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return LoginInitialCtrl;
|
||||
});
|
||||
module.exports = LoginInitialCtrl;
|
|
@ -1,10 +1,8 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var angular = require('angular'),
|
||||
appController = require('js/app-controller');
|
||||
var appController = require('../app-controller');
|
||||
|
||||
var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
|
@ -100,10 +98,10 @@ define(function(require) {
|
|||
$scope.$apply();
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var ngModule = angular.module('login-new-device', []);
|
||||
ngModule.directive('fileReader', function() {
|
||||
var ngModule = angular.module('login-new-device', []);
|
||||
ngModule.directive('fileReader', function() {
|
||||
return function(scope, elm) {
|
||||
elm.bind('change', function(e) {
|
||||
var files = e.target.files,
|
||||
|
@ -135,7 +133,6 @@ define(function(require) {
|
|||
reader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return LoginExistingCtrl;
|
||||
});
|
||||
|
||||
module.exports = LoginExistingCtrl;
|
|
@ -1,9 +1,8 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var appController = require('js/app-controller');
|
||||
var appController = require('../app-controller');
|
||||
|
||||
var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||
var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
|
@ -128,7 +127,6 @@ define(function(require) {
|
|||
$location.path(location);
|
||||
$scope.$apply();
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return LoginPrivateKeyDownloadCtrl;
|
||||
});
|
||||
module.exports = LoginPrivateKeyDownloadCtrl;
|
|
@ -1,14 +1,13 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var ENCRYPTION_METHOD_NONE = 0;
|
||||
var ENCRYPTION_METHOD_STARTTLS = 1;
|
||||
var ENCRYPTION_METHOD_TLS = 2;
|
||||
var ENCRYPTION_METHOD_NONE = 0;
|
||||
var ENCRYPTION_METHOD_STARTTLS = 1;
|
||||
var ENCRYPTION_METHOD_TLS = 2;
|
||||
|
||||
var appCtrl = require('js/app-controller'),
|
||||
config = require('js/app-config').config;
|
||||
var appCtrl = require('../app-controller'),
|
||||
config = require('../app-config').config;
|
||||
|
||||
var SetCredentialsCtrl = function($scope, $location, $routeParams) {
|
||||
var SetCredentialsCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appCtrl._auth && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
|
@ -114,7 +113,6 @@ define(function(require) {
|
|||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return SetCredentialsCtrl;
|
||||
});
|
||||
module.exports = SetCredentialsCtrl;
|
|
@ -1,9 +1,8 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var appController = require('js/app-controller');
|
||||
var appController = require('../app-controller');
|
||||
|
||||
var LoginCtrl = function($scope, $location) {
|
||||
var LoginCtrl = function($scope, $location) {
|
||||
|
||||
// start main application controller
|
||||
appController.start({
|
||||
|
@ -97,7 +96,6 @@ define(function(require) {
|
|||
$location.path(location);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return LoginCtrl;
|
||||
});
|
||||
module.exports = LoginCtrl;
|
|
@ -1,17 +1,14 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var angular = require('angular'),
|
||||
_ = require('underscore'),
|
||||
appController = require('js/app-controller'),
|
||||
notification = require('js/util/notification'),
|
||||
var appController = require('../app-controller'),
|
||||
notification = require('../util/notification'),
|
||||
emailDao, outboxBo, keychainDao, searchTimeout, firstSelect;
|
||||
|
||||
var INIT_DISPLAY_LEN = 20,
|
||||
var INIT_DISPLAY_LEN = 20,
|
||||
SCROLL_DISPLAY_LEN = 10,
|
||||
FOLDER_TYPE_INBOX = 'Inbox';
|
||||
|
||||
var MailListCtrl = function($scope, $routeParams) {
|
||||
var MailListCtrl = function($scope, $routeParams) {
|
||||
//
|
||||
// Init
|
||||
//
|
||||
|
@ -416,15 +413,15 @@ define(function(require) {
|
|||
});
|
||||
$scope.pendingNotifications.push(note);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
|
||||
var ngModule = angular.module('mail-list', []);
|
||||
var ngModule = angular.module('mail-list', []);
|
||||
|
||||
ngModule.directive('woTouch', function($parse) {
|
||||
ngModule.directive('woTouch', function($parse) {
|
||||
return function(scope, elm, attrs) {
|
||||
var handler = $parse(attrs.woTouch);
|
||||
|
||||
|
@ -444,9 +441,9 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
ngModule.directive('listScroll', function() {
|
||||
ngModule.directive('listScroll', function() {
|
||||
return {
|
||||
link: function(scope, elm, attrs) {
|
||||
var model = attrs.listScroll,
|
||||
|
@ -516,9 +513,9 @@ define(function(require) {
|
|||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
function byUidDescending(a, b) {
|
||||
function byUidDescending(a, b) {
|
||||
if (a.uid < b.uid) {
|
||||
return 1;
|
||||
} else if (b.uid < a.uid) {
|
||||
|
@ -526,11 +523,11 @@ define(function(require) {
|
|||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper for development mode
|
||||
// Helper for development mode
|
||||
|
||||
function createDummyMails() {
|
||||
function createDummyMails() {
|
||||
var uid = 1000000;
|
||||
|
||||
var Email = function(unread, attachments, answered) {
|
||||
|
@ -594,7 +591,6 @@ define(function(require) {
|
|||
}
|
||||
|
||||
return dummies;
|
||||
}
|
||||
}
|
||||
|
||||
return MailListCtrl;
|
||||
});
|
||||
module.exports = MailListCtrl;
|
|
@ -1,19 +1,16 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var angular = require('angular'),
|
||||
appController = require('js/app-controller'),
|
||||
config = require('js/app-config').config,
|
||||
notification = require('js/util/notification'),
|
||||
backBtnHandler = require('js/util/backbutton-handler'),
|
||||
_ = require('underscore'),
|
||||
var appController = require('../app-controller'),
|
||||
config = require('../app-config').config,
|
||||
notification = require('../util/notification'),
|
||||
backBtnHandler = require('../util/backbutton-handler'),
|
||||
emailDao, outboxBo;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var NavigationCtrl = function($scope, $routeParams, $location) {
|
||||
var NavigationCtrl = function($scope, $routeParams, $location) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
|
@ -151,14 +148,14 @@ define(function(require) {
|
|||
path: 'TRASH'
|
||||
}];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
|
||||
var ngModule = angular.module('navigation', []);
|
||||
ngModule.directive('keyShortcuts', function($timeout) {
|
||||
var ngModule = angular.module('navigation', []);
|
||||
ngModule.directive('keyShortcuts', function($timeout) {
|
||||
return function(scope, elm) {
|
||||
elm.bind('keydown', function(e) {
|
||||
// global state is not yet set, ignore keybaord shortcuts
|
||||
|
@ -204,7 +201,6 @@ define(function(require) {
|
|||
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return NavigationCtrl;
|
||||
});
|
||||
|
||||
module.exports = NavigationCtrl;
|
|
@ -1,22 +1,19 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var angular = require('angular');
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var PopoverCtrl = function($scope) {
|
||||
var PopoverCtrl = function($scope) {
|
||||
$scope.state.popover = {};
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
|
||||
var ngModule = angular.module('popover', []);
|
||||
ngModule.directive('popover', function() {
|
||||
var ngModule = angular.module('popover', []);
|
||||
ngModule.directive('popover', function() {
|
||||
return function(scope, elm, attrs) {
|
||||
var selector = attrs.popover;
|
||||
var popover = angular.element(document.querySelector(selector));
|
||||
|
@ -41,7 +38,6 @@ define(function(require) {
|
|||
popover[0].style.left = '-9999px';
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return PopoverCtrl;
|
||||
});
|
||||
|
||||
module.exports = PopoverCtrl;
|
|
@ -1,12 +1,10 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var angular = require('angular'),
|
||||
appController = require('js/app-controller'),
|
||||
util = require('js/crypto/util'),
|
||||
var appController = require('../app-controller'),
|
||||
util = require('crypto-lib').util,
|
||||
keychain, pgp;
|
||||
|
||||
var PrivateKeyUploadCtrl = function($scope) {
|
||||
var PrivateKeyUploadCtrl = function($scope) {
|
||||
keychain = appController._keychain;
|
||||
pgp = keychain._pgp;
|
||||
|
||||
|
@ -176,14 +174,14 @@ define(function(require) {
|
|||
}
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
|
||||
var ngModule = angular.module('privatekey-upload', []);
|
||||
ngModule.directive('focusNext', function() {
|
||||
var ngModule = angular.module('privatekey-upload', []);
|
||||
ngModule.directive('focusNext', function() {
|
||||
return {
|
||||
link: function(scope, element, attr) {
|
||||
var maxLen = element[0].maxLength;
|
||||
|
@ -198,7 +196,6 @@ define(function(require) {
|
|||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return PrivateKeyUploadCtrl;
|
||||
});
|
||||
|
||||
module.exports = PrivateKeyUploadCtrl;
|
|
@ -1,8 +1,7 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
// set listener for event from main window
|
||||
window.onmessage = function(e) {
|
||||
// set listener for event from main window
|
||||
window.onmessage = function(e) {
|
||||
var html = '';
|
||||
|
||||
if (e.data.html) {
|
||||
|
@ -28,16 +27,16 @@
|
|||
document.body.innerHTML = html;
|
||||
|
||||
scaleToFit();
|
||||
};
|
||||
};
|
||||
|
||||
window.addEventListener('resize', scaleToFit);
|
||||
window.addEventListener('resize', scaleToFit);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Parse email body and generate conversation nodes
|
||||
* @param {Object} email The email object
|
||||
* @return {Node} The root node of the conversion
|
||||
*/
|
||||
function parseConversation(textBody) {
|
||||
function parseConversation(textBody) {
|
||||
var nodes;
|
||||
|
||||
function parseLines(body) {
|
||||
|
@ -140,14 +139,14 @@
|
|||
removeParentReference(nodes);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Render the conversation nodes as markup. This is not injected directly into the DOM, but rather send to a sandboxed iframe to be rendered
|
||||
* @param {Node} root The conversation root node
|
||||
* @return {Strin} The conversation as markup
|
||||
*/
|
||||
function renderNodes(root) {
|
||||
function renderNodes(root) {
|
||||
var body = '';
|
||||
|
||||
function render(node) {
|
||||
|
@ -189,14 +188,14 @@
|
|||
}
|
||||
|
||||
return '<div class="view-read-body">' + body + '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Transform scale content to fit iframe width
|
||||
*/
|
||||
function scaleToFit() {
|
||||
function scaleToFit() {
|
||||
var view = document.getElementsByClassName('scale-body').item(0);
|
||||
if(!view) {
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -204,7 +203,7 @@
|
|||
var w = view.offsetWidth;
|
||||
var scale = '';
|
||||
|
||||
if(w > parentWidth) {
|
||||
if (w > parentWidth) {
|
||||
scale = parentWidth / w;
|
||||
scale = 'scale(' + scale + ',' + scale + ')';
|
||||
}
|
||||
|
@ -213,6 +212,4 @@
|
|||
view.style.transformOrigin = '0 0';
|
||||
view.style['-webkit-transform'] = scale;
|
||||
view.style.transform = scale;
|
||||
}
|
||||
|
||||
})();
|
||||
}
|
|
@ -1,17 +1,15 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var appController = require('js/app-controller'),
|
||||
download = require('js/util/download'),
|
||||
angular = require('angular'),
|
||||
str = require('js/app-config').string,
|
||||
var appController = require('../app-controller'),
|
||||
download = require('../util/download'),
|
||||
str = require('../app-config').string,
|
||||
emailDao, invitationDao, outbox, pgp, keychain;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var ReadCtrl = function($scope) {
|
||||
var ReadCtrl = function($scope) {
|
||||
|
||||
emailDao = appController._emailDao;
|
||||
invitationDao = appController._invitationDao;
|
||||
|
@ -144,15 +142,15 @@ define(function(require) {
|
|||
outbox.put(invitationMail, $scope.onError);
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
|
||||
var ngModule = angular.module('read', []);
|
||||
var ngModule = angular.module('read', []);
|
||||
|
||||
ngModule.directive('replySelection', function() {
|
||||
ngModule.directive('replySelection', function() {
|
||||
return function(scope, elm) {
|
||||
var popover, visible;
|
||||
|
||||
|
@ -193,9 +191,9 @@ define(function(require) {
|
|||
visible = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
ngModule.directive('frameLoad', function($timeout, $window) {
|
||||
ngModule.directive('frameLoad', function($timeout, $window) {
|
||||
return function(scope, elm) {
|
||||
var iframe = elm[0];
|
||||
|
||||
|
@ -280,7 +278,6 @@ define(function(require) {
|
|||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return ReadCtrl;
|
||||
});
|
||||
|
||||
module.exports = ReadCtrl;
|
|
@ -1,14 +1,13 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var appController = require('js/app-controller'),
|
||||
var appController = require('../app-controller'),
|
||||
pgp, keychain;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var SetPassphraseCtrl = function($scope) {
|
||||
var SetPassphraseCtrl = function($scope) {
|
||||
keychain = appController._keychain;
|
||||
pgp = appController._pgp;
|
||||
|
||||
|
@ -132,7 +131,6 @@ define(function(require) {
|
|||
message: 'Passphrase change complete.'
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return SetPassphraseCtrl;
|
||||
});
|
||||
module.exports = SetPassphraseCtrl;
|
|
@ -1,19 +1,16 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var angular = require('angular'),
|
||||
_ = require('underscore'),
|
||||
appController = require('js/app-controller'),
|
||||
axe = require('axe'),
|
||||
util = require('js/crypto/util'),
|
||||
str = require('js/app-config').string,
|
||||
var appController = require('../app-controller'),
|
||||
axe = require('axe-logger'),
|
||||
util = require('crypto-lib').util,
|
||||
str = require('../app-config').string,
|
||||
pgp, emailDao, outbox, keychainDao, auth;
|
||||
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
//
|
||||
// Controller
|
||||
//
|
||||
|
||||
var WriteCtrl = function($scope, $filter, $q) {
|
||||
var WriteCtrl = function($scope, $filter, $q) {
|
||||
pgp = appController._pgp;
|
||||
auth = appController._auth;
|
||||
emailDao = appController._emailDao;
|
||||
|
@ -440,16 +437,16 @@ define(function(require) {
|
|||
function filterEmptyAddresses(addr) {
|
||||
return !!addr.address;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
//
|
||||
// Directives
|
||||
//
|
||||
|
||||
var ngModule = angular.module('write', []);
|
||||
var ngModule = angular.module('write', []);
|
||||
|
||||
ngModule.directive('focusMe', function($timeout, $parse) {
|
||||
ngModule.directive('focusMe', function($timeout, $parse) {
|
||||
return {
|
||||
//scope: true, // optionally create a child scope
|
||||
link: function(scope, element, attrs) {
|
||||
|
@ -469,9 +466,9 @@ define(function(require) {
|
|||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
ngModule.directive('focusInput', function($timeout, $parse) {
|
||||
ngModule.directive('focusInput', function($timeout, $parse) {
|
||||
return {
|
||||
//scope: true, // optionally create a child scope
|
||||
link: function(scope, element, attrs) {
|
||||
|
@ -485,9 +482,9 @@ define(function(require) {
|
|||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
ngModule.directive('focusInputOnClick', function() {
|
||||
ngModule.directive('focusInputOnClick', function() {
|
||||
return {
|
||||
//scope: true, // optionally create a child scope
|
||||
link: function(scope, element) {
|
||||
|
@ -496,9 +493,9 @@ define(function(require) {
|
|||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
ngModule.directive('attachmentInput', function() {
|
||||
ngModule.directive('attachmentInput', function() {
|
||||
return function(scope, elm) {
|
||||
elm.on('change', function(e) {
|
||||
for (var i = 0; i < e.target.files.length; i++) {
|
||||
|
@ -519,16 +516,15 @@ define(function(require) {
|
|||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
ngModule.directive('attachmentBtn', function() {
|
||||
ngModule.directive('attachmentBtn', function() {
|
||||
return function(scope, elm) {
|
||||
elm.on('click touchstart', function(e) {
|
||||
e.preventDefault();
|
||||
document.querySelector('#attachment-input').click();
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return WriteCtrl;
|
||||
});
|
||||
|
||||
module.exports = WriteCtrl;
|
|
@ -2,19 +2,17 @@
|
|||
* High level crypto api that invokes native crypto (if available) and
|
||||
* gracefully degrades to JS crypto (if unavailable)
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var aes = require('js/crypto/aes-gcm'),
|
||||
pbkdf2 = require('js/crypto/pbkdf2'),
|
||||
config = require('js/app-config').config,
|
||||
axe = require('axe');
|
||||
'use strict';
|
||||
|
||||
var PBKDF2_WORKER = '/crypto/pbkdf2-worker.js';
|
||||
var aes = require('crypto-lib').aes,
|
||||
pbkdf2 = require('./pbkdf2'),
|
||||
config = require('../app-config').config,
|
||||
axe = require('axe-logger');
|
||||
|
||||
var Crypto = function() {};
|
||||
var Crypto = function() {};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Encrypt plaintext using AES-GCM.
|
||||
* @param {String} plaintext The input string in UTF-16
|
||||
* @param {String} key The base64 encoded key
|
||||
|
@ -22,7 +20,7 @@ define(function(require) {
|
|||
* @param {Function} callback(error, ciphertext)
|
||||
* @return {String} The base64 encoded ciphertext
|
||||
*/
|
||||
Crypto.prototype.encrypt = function(plaintext, key, iv, callback) {
|
||||
Crypto.prototype.encrypt = function(plaintext, key, iv, callback) {
|
||||
var ct;
|
||||
|
||||
try {
|
||||
|
@ -33,9 +31,9 @@ define(function(require) {
|
|||
}
|
||||
|
||||
callback(null, ct);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Decrypt ciphertext suing AES-GCM
|
||||
* @param {String} ciphertext The base64 encoded ciphertext
|
||||
* @param {String} key The base64 encoded key
|
||||
|
@ -43,7 +41,7 @@ define(function(require) {
|
|||
* @param {Function} callback(error, plaintext)
|
||||
* @return {String} The decrypted plaintext in UTF-16
|
||||
*/
|
||||
Crypto.prototype.decrypt = function(ciphertext, key, iv, callback) {
|
||||
Crypto.prototype.decrypt = function(ciphertext, key, iv, callback) {
|
||||
var pt;
|
||||
|
||||
try {
|
||||
|
@ -54,14 +52,14 @@ define(function(require) {
|
|||
}
|
||||
|
||||
callback(null, pt);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Do PBKDF2 key derivation in a WebWorker thread
|
||||
*/
|
||||
Crypto.prototype.deriveKey = function(password, salt, keySize, callback) {
|
||||
Crypto.prototype.deriveKey = function(password, salt, keySize, callback) {
|
||||
startWorker({
|
||||
script: PBKDF2_WORKER,
|
||||
script: config.workerPath + '/pbkdf2-worker.min.js',
|
||||
args: {
|
||||
password: password,
|
||||
salt: salt,
|
||||
|
@ -72,17 +70,17 @@ define(function(require) {
|
|||
return pbkdf2.getKey(password, salt, keySize);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// helper functions
|
||||
//
|
||||
//
|
||||
// helper functions
|
||||
//
|
||||
|
||||
function startWorker(options) {
|
||||
function startWorker(options) {
|
||||
// check for WebWorker support
|
||||
if (window.Worker) {
|
||||
// init webworker thread
|
||||
var worker = new Worker(config.workerPath + options.script);
|
||||
var worker = new Worker(options.script);
|
||||
worker.onmessage = function(e) {
|
||||
if (e.data.err) {
|
||||
options.callback(e.data.err);
|
||||
|
@ -117,7 +115,6 @@ define(function(require) {
|
|||
return;
|
||||
}
|
||||
options.callback(null, result);
|
||||
}
|
||||
}
|
||||
|
||||
return Crypto;
|
||||
});
|
||||
module.exports = Crypto;
|
|
@ -1,22 +1,14 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
// import web worker dependencies
|
||||
importScripts('../../lib/require.js');
|
||||
importScripts('forge.min.js');
|
||||
|
||||
/**
|
||||
var pbkdf2 = require('./pbkdf2');
|
||||
|
||||
/**
|
||||
* In the web worker thread context, 'this' and 'self' can be used as a global
|
||||
* variable namespace similar to the 'window' object in the main thread
|
||||
*/
|
||||
self.onmessage = function(e) {
|
||||
// fetch dependencies via require.js
|
||||
require(['../../require-config'], function() {
|
||||
require.config({
|
||||
baseUrl: '../../lib'
|
||||
});
|
||||
|
||||
require(['js/crypto/pbkdf2'], function(pbkdf2) {
|
||||
|
||||
self.onmessage = function(e) {
|
||||
var i = e.data,
|
||||
key = null;
|
||||
|
||||
|
@ -30,9 +22,4 @@
|
|||
|
||||
// pass output back to main thread
|
||||
self.postMessage(key);
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}());
|
||||
};
|
|
@ -1,25 +1,24 @@
|
|||
/**
|
||||
* A Wrapper for Forge's PBKDF2 function
|
||||
*/
|
||||
define(['forge'], function(forge) {
|
||||
'use strict';
|
||||
|
||||
var self = {};
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
var pbkdf2 = {};
|
||||
|
||||
/**
|
||||
* PBKDF2-HMAC-SHA256 key derivation with a random salt and 10000 iterations
|
||||
* @param {String} password The password in UTF8
|
||||
* @param {String} salt The base64 encoded salt
|
||||
* @param {String} keySize The key size in bits
|
||||
* @return {String} The base64 encoded key
|
||||
*/
|
||||
self.getKey = function(password, salt, keySize) {
|
||||
pbkdf2.getKey = function(password, salt, keySize) {
|
||||
var saltUtf8 = forge.util.decode64(salt);
|
||||
var md = forge.md.sha256.create();
|
||||
var key = forge.pkcs5.pbkdf2(password, saltUtf8, 10000, keySize / 8, md);
|
||||
|
||||
return forge.util.encode64(key);
|
||||
};
|
||||
};
|
||||
|
||||
return self;
|
||||
});
|
||||
module.exports = pbkdf2;
|
|
@ -1,22 +1,21 @@
|
|||
/**
|
||||
* High level crypto api that handles all calls to OpenPGP.js
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var openpgp = require('openpgp'),
|
||||
util = require('openpgp').util,
|
||||
config = require('js/app-config').config;
|
||||
'use strict';
|
||||
|
||||
var PGP = function() {
|
||||
var util = openpgp.util,
|
||||
config = require('../app-config').config;
|
||||
|
||||
var PGP = function() {
|
||||
openpgp.config.prefer_hash_algorithm = openpgp.enums.hash.sha256;
|
||||
openpgp.initWorker(config.workerPath + '/../lib/openpgp/openpgp.worker.js');
|
||||
};
|
||||
openpgp.initWorker(config.workerPath + '/openpgp.worker.js');
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Generate a key pair for the user
|
||||
*/
|
||||
PGP.prototype.generateKeys = function(options, callback) {
|
||||
PGP.prototype.generateKeys = function(options, callback) {
|
||||
var userId, passphrase;
|
||||
|
||||
if (!util.emailRegEx.test(options.emailAddress) || !options.keySize) {
|
||||
|
@ -46,12 +45,12 @@ define(function(require) {
|
|||
publicKeyArmored: keys.publicKeyArmored
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Show a user's fingerprint
|
||||
*/
|
||||
PGP.prototype.getFingerprint = function(keyArmored) {
|
||||
PGP.prototype.getFingerprint = function(keyArmored) {
|
||||
function fingerprint(key) {
|
||||
return key.primaryKey.getFingerprint().toUpperCase();
|
||||
}
|
||||
|
@ -67,12 +66,12 @@ define(function(require) {
|
|||
|
||||
// get local fingerpring
|
||||
return fingerprint(this._publicKey);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Show a user's key id.
|
||||
*/
|
||||
PGP.prototype.getKeyId = function(keyArmored) {
|
||||
PGP.prototype.getKeyId = function(keyArmored) {
|
||||
var key, pubKeyId, privKeyId;
|
||||
|
||||
// process armored key input
|
||||
|
@ -94,12 +93,12 @@ define(function(require) {
|
|||
}
|
||||
|
||||
return pubKeyId;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Read all relevant params of an armored key.
|
||||
*/
|
||||
PGP.prototype.getKeyParams = function(keyArmored) {
|
||||
PGP.prototype.getKeyParams = function(keyArmored) {
|
||||
var key, packet, userIds;
|
||||
|
||||
// process armored key input
|
||||
|
@ -131,23 +130,23 @@ define(function(require) {
|
|||
bitSize: packet.getBitSize(),
|
||||
created: packet.created,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Extract a public key from a private key
|
||||
* @param {String} privateKeyArmored The private PGP key block
|
||||
* @return {String} The publick PGP key block
|
||||
*/
|
||||
PGP.prototype.extractPublicKey = function(privateKeyArmored) {
|
||||
PGP.prototype.extractPublicKey = function(privateKeyArmored) {
|
||||
var privkey = openpgp.key.readArmored(privateKeyArmored).keys[0];
|
||||
var pubkey = privkey.toPublic();
|
||||
return pubkey.armor();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Import the user's key pair
|
||||
*/
|
||||
PGP.prototype.importKeys = function(options, callback) {
|
||||
PGP.prototype.importKeys = function(options, callback) {
|
||||
var pubKeyId, privKeyId, self = this;
|
||||
|
||||
// check options
|
||||
|
@ -188,12 +187,12 @@ define(function(require) {
|
|||
}
|
||||
|
||||
callback();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Export the user's key pair
|
||||
*/
|
||||
PGP.prototype.exportKeys = function(callback) {
|
||||
PGP.prototype.exportKeys = function(callback) {
|
||||
if (!this._publicKey || !this._privateKey) {
|
||||
callback(new Error('Could not export keys!'));
|
||||
return;
|
||||
|
@ -204,12 +203,12 @@ define(function(require) {
|
|||
privateKeyArmored: this._privateKey.armor(),
|
||||
publicKeyArmored: this._publicKey.armor()
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Change the passphrase of an ascii armored private key.
|
||||
*/
|
||||
PGP.prototype.changePassphrase = function(options, callback) {
|
||||
PGP.prototype.changePassphrase = function(options, callback) {
|
||||
var privKey, packets, newPassphrase, newKeyArmored;
|
||||
|
||||
// set undefined instead of empty string as passphrase
|
||||
|
@ -259,12 +258,12 @@ define(function(require) {
|
|||
}
|
||||
|
||||
callback(null, newKeyArmored);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Encrypt and sign a pgp message for a list of receivers
|
||||
*/
|
||||
PGP.prototype.encrypt = function(plaintext, publicKeysArmored, callback) {
|
||||
PGP.prototype.encrypt = function(plaintext, publicKeysArmored, callback) {
|
||||
var publicKeys;
|
||||
|
||||
// check keys
|
||||
|
@ -293,15 +292,15 @@ define(function(require) {
|
|||
// if no public keys are available encrypt for myself
|
||||
openpgp.signAndEncryptMessage([this._publicKey], this._privateKey, plaintext, callback);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Decrypts a ciphertext
|
||||
* @param {String} ciphertext The encrypted PGP message block
|
||||
* @param {String} publicKeyArmored The public key used to sign the message
|
||||
* @param {Function} callback(error, plaintext, signaturesValid) signaturesValid is undefined in case there are no signature, null in case there are signatures but the wrong public key or no key was used to verify, true if the signature was successfully verified, or false if the signataure verification failed.
|
||||
*/
|
||||
PGP.prototype.decrypt = function(ciphertext, publicKeyArmored, callback) {
|
||||
PGP.prototype.decrypt = function(ciphertext, publicKeyArmored, callback) {
|
||||
var publicKeys, message;
|
||||
|
||||
// check keys
|
||||
|
@ -337,15 +336,15 @@ define(function(require) {
|
|||
// return decrypted plaintext
|
||||
callback(null, decrypted.text, checkSignatureValidity(decrypted.signatures));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Verifies a clearsigned message
|
||||
* @param {String} clearSignedText The clearsigned text, usually from a signed pgp/inline message
|
||||
* @param {String} publicKeyArmored The public key used to signed the message
|
||||
* @param {Function} callback(error, signaturesValid) signaturesValid is undefined in case there are no signature, null in case there are signatures but the wrong public key or no key was used to verify, true if the signature was successfully verified, or false if the signataure verification failed.
|
||||
*/
|
||||
PGP.prototype.verifyClearSignedMessage = function(clearSignedText, publicKeyArmored, callback) {
|
||||
PGP.prototype.verifyClearSignedMessage = function(clearSignedText, publicKeyArmored, callback) {
|
||||
var publicKeys,
|
||||
message;
|
||||
|
||||
|
@ -378,16 +377,16 @@ define(function(require) {
|
|||
|
||||
callback(null, checkSignatureValidity(result.signatures));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Verifies a message with a detached signature
|
||||
* @param {String} message The signed text, usually from a signed pgp/mime message
|
||||
* @param {String} pgpSignature The detached signature, usually from a signed pgp/mime message
|
||||
* @param {String} publicKeyArmored The public key used to signed the message
|
||||
* @param {Function} callback(error, signaturesValid) signaturesValid is undefined in case there are no signature, null in case there are signatures but the wrong public key or no key was used to verify, true if the signature was successfully verified, or false if the signataure verification failed.
|
||||
*/
|
||||
PGP.prototype.verifySignedMessage = function(message, pgpSignature, publicKeyArmored, callback) {
|
||||
PGP.prototype.verifySignedMessage = function(message, pgpSignature, publicKeyArmored, callback) {
|
||||
var publicKeys;
|
||||
|
||||
// check keys
|
||||
|
@ -420,9 +419,9 @@ define(function(require) {
|
|||
}
|
||||
|
||||
callback(null, checkSignatureValidity(signatures));
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks signature validity
|
||||
* @param {Object} decrypted OpenPGP.js Signature array
|
||||
* @return {undefined|null|true|false}
|
||||
|
@ -431,7 +430,7 @@ define(function(require) {
|
|||
* If signatures are invalid, returns false.
|
||||
* If everything is in order, returns true
|
||||
*/
|
||||
function checkSignatureValidity(signatures) {
|
||||
function checkSignatureValidity(signatures) {
|
||||
if (!signatures.length) {
|
||||
// signatures array is empty (the message was not signed)
|
||||
return;
|
||||
|
@ -446,7 +445,6 @@ define(function(require) {
|
|||
|
||||
// everything is in order
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return PGP;
|
||||
});
|
||||
module.exports = PGP;
|
|
@ -1,18 +1,17 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var AdminDAO = function(restDao) {
|
||||
var AdminDAO = function(restDao) {
|
||||
this._restDao = restDao;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Create a new email account.
|
||||
* @param {String} options.emailAddress The desired email address
|
||||
* @param {String} options.password The password to be used for the account.
|
||||
* @param {String} options.phone The user's mobile phone number (required for verification and password reset).
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
AdminDAO.prototype.createUser = function(options, callback) {
|
||||
AdminDAO.prototype.createUser = function(options, callback) {
|
||||
var uri;
|
||||
|
||||
if (!options.emailAddress || !options.password || !options.phone) {
|
||||
|
@ -32,15 +31,15 @@ define(function() {
|
|||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Verify a user's phone number by confirming a token to the server.
|
||||
* @param {String} options.emailAddress The desired email address
|
||||
* @param {String} options.token The validation token.
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
AdminDAO.prototype.validateUser = function(options, callback) {
|
||||
AdminDAO.prototype.validateUser = function(options, callback) {
|
||||
var uri;
|
||||
|
||||
if (!options.emailAddress || !options.token) {
|
||||
|
@ -57,7 +56,6 @@ define(function() {
|
|||
callback(new Error('Validation failed!'));
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return AdminDAO;
|
||||
});
|
||||
module.exports = AdminDAO;
|
|
@ -1,26 +1,23 @@
|
|||
/**
|
||||
* High level storage api that handles all persistence on the device. If
|
||||
* SQLcipher/SQLite is available, all data is securely persisted there,
|
||||
* through transparent encryption. If not, the crypto API is
|
||||
* used to encrypt data on the fly before persisting via a JSON store.
|
||||
* High level storage api that handles all persistence on the device.
|
||||
*/
|
||||
define(function() {
|
||||
'use strict';
|
||||
|
||||
var DeviceStorageDAO = function(localDbDao) {
|
||||
'use strict';
|
||||
|
||||
var DeviceStorageDAO = function(localDbDao) {
|
||||
this._localDbDao = localDbDao;
|
||||
};
|
||||
};
|
||||
|
||||
DeviceStorageDAO.prototype.init = function(emailAddress, callback) {
|
||||
DeviceStorageDAO.prototype.init = function(emailAddress, callback) {
|
||||
this._localDbDao.init(emailAddress, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Stores a list of encrypted items in the object store
|
||||
* @param list [Array] The list of items to be persisted
|
||||
* @param type [String] The type of item to be persisted e.g. 'email'
|
||||
*/
|
||||
DeviceStorageDAO.prototype.storeList = function(list, type, callback) {
|
||||
DeviceStorageDAO.prototype.storeList = function(list, type, callback) {
|
||||
var key, items = [];
|
||||
|
||||
// nothing to store
|
||||
|
@ -47,38 +44,38 @@ define(function() {
|
|||
});
|
||||
|
||||
this._localDbDao.batch(items, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Deletes items of a certain type from storage
|
||||
*/
|
||||
DeviceStorageDAO.prototype.removeList = function(type, callback) {
|
||||
DeviceStorageDAO.prototype.removeList = function(type, callback) {
|
||||
this._localDbDao.removeList(type, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* List stored items of a given type
|
||||
* @param type [String] The type of item e.g. 'email'
|
||||
* @param offset [Number] The offset of items to fetch (0 is the last stored item)
|
||||
* @param num [Number] The number of items to fetch (null means fetch all)
|
||||
*/
|
||||
DeviceStorageDAO.prototype.listItems = function(type, offset, num, callback) {
|
||||
DeviceStorageDAO.prototype.listItems = function(type, offset, num, callback) {
|
||||
// fetch all items of a certain type from the data-store
|
||||
this._localDbDao.list(type, offset, num, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Clear the whole device data-store
|
||||
*/
|
||||
DeviceStorageDAO.prototype.clear = function(callback) {
|
||||
DeviceStorageDAO.prototype.clear = function(callback) {
|
||||
this._localDbDao.clear(callback);
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// helper functions
|
||||
//
|
||||
//
|
||||
// helper functions
|
||||
//
|
||||
|
||||
function createKey(i, type) {
|
||||
function createKey(i, type) {
|
||||
var key;
|
||||
|
||||
// put uid in key if available... for easy querying
|
||||
|
@ -91,7 +88,6 @@ define(function() {
|
|||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return DeviceStorageDAO;
|
||||
});
|
||||
module.exports = DeviceStorageDAO;
|
|
@ -1,44 +1,41 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var util = require('js/crypto/util'),
|
||||
_ = require('underscore'),
|
||||
config = require('js/app-config').config,
|
||||
str = require('js/app-config').string;
|
||||
var util = require('crypto-lib').util,
|
||||
config = require('../app-config').config,
|
||||
str = require('../app-config').string;
|
||||
|
||||
//
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
//
|
||||
|
||||
//
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
//
|
||||
var FOLDER_DB_TYPE = 'folders';
|
||||
|
||||
var FOLDER_DB_TYPE = 'folders';
|
||||
var SYNC_TYPE_NEW = 'new';
|
||||
var SYNC_TYPE_DELETED = 'deleted';
|
||||
var SYNC_TYPE_MSGS = 'messages';
|
||||
|
||||
var SYNC_TYPE_NEW = 'new';
|
||||
var SYNC_TYPE_DELETED = 'deleted';
|
||||
var SYNC_TYPE_MSGS = 'messages';
|
||||
var FOLDER_TYPE_INBOX = 'Inbox';
|
||||
var FOLDER_TYPE_SENT = 'Sent';
|
||||
var FOLDER_TYPE_DRAFTS = 'Drafts';
|
||||
var FOLDER_TYPE_TRASH = 'Trash';
|
||||
|
||||
var FOLDER_TYPE_INBOX = 'Inbox';
|
||||
var FOLDER_TYPE_SENT = 'Sent';
|
||||
var FOLDER_TYPE_DRAFTS = 'Drafts';
|
||||
var FOLDER_TYPE_TRASH = 'Trash';
|
||||
var MSG_ATTR_UID = 'uid';
|
||||
var MSG_PART_ATTR_CONTENT = 'content';
|
||||
var MSG_PART_TYPE_ATTACHMENT = 'attachment';
|
||||
var MSG_PART_TYPE_ENCRYPTED = 'encrypted';
|
||||
var MSG_PART_TYPE_SIGNED = 'signed';
|
||||
var MSG_PART_TYPE_TEXT = 'text';
|
||||
var MSG_PART_TYPE_HTML = 'html';
|
||||
|
||||
var MSG_ATTR_UID = 'uid';
|
||||
var MSG_PART_ATTR_CONTENT = 'content';
|
||||
var MSG_PART_TYPE_ATTACHMENT = 'attachment';
|
||||
var MSG_PART_TYPE_ENCRYPTED = 'encrypted';
|
||||
var MSG_PART_TYPE_SIGNED = 'signed';
|
||||
var MSG_PART_TYPE_TEXT = 'text';
|
||||
var MSG_PART_TYPE_HTML = 'html';
|
||||
//
|
||||
//
|
||||
// Email Dao
|
||||
//
|
||||
//
|
||||
|
||||
//
|
||||
//
|
||||
// Email Dao
|
||||
//
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* High-level data access object that orchestrates everything around the handling of encrypted mails:
|
||||
* PGP de-/encryption, receiving via IMAP, sending via SMTP, MIME parsing, local db persistence
|
||||
*
|
||||
|
@ -48,23 +45,23 @@ define(function(require) {
|
|||
* @param {Object} pgpbuilder Generates and encrypts MIME and SMTP messages
|
||||
* @param {Object} mailreader Parses MIME messages received from IMAP
|
||||
*/
|
||||
var EmailDAO = function(keychain, pgp, devicestorage, pgpbuilder, mailreader) {
|
||||
var EmailDAO = function(keychain, pgp, devicestorage, pgpbuilder, mailreader) {
|
||||
this._keychain = keychain;
|
||||
this._pgp = pgp;
|
||||
this._devicestorage = devicestorage;
|
||||
this._pgpbuilder = pgpbuilder;
|
||||
this._mailreader = mailreader;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Public API
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// Public API
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Initializes the email dao:
|
||||
* - validates the email address
|
||||
* - retrieves the user's key pair (if available)
|
||||
|
@ -74,7 +71,7 @@ define(function(require) {
|
|||
* @param {String} options.account.emailAddress The user's id
|
||||
* @param {Function} callback(error, keypair) Invoked with the keypair or error information when the email dao is initialized
|
||||
*/
|
||||
EmailDAO.prototype.init = function(options, callback) {
|
||||
EmailDAO.prototype.init = function(options, callback) {
|
||||
var self = this,
|
||||
keypair;
|
||||
|
||||
|
@ -120,14 +117,14 @@ define(function(require) {
|
|||
callback(null, keypair);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Unlocks the keychain by either decrypting an existing private key or generating a new keypair
|
||||
* @param {String} options.passphrase The passphrase to decrypt the private key
|
||||
* @param {Function} callback(error) Invoked when the the keychain is unlocked or when an error occurred buring unlocking
|
||||
*/
|
||||
EmailDAO.prototype.unlock = function(options, callback) {
|
||||
EmailDAO.prototype.unlock = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
if (options.keypair) {
|
||||
|
@ -233,9 +230,9 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Opens a folder in IMAP so that we can receive updates for it.
|
||||
* Please note that this is a no-op if you try to open the outbox, since it is not an IMAP folder
|
||||
* but a virtual folder that only exists on disk.
|
||||
|
@ -243,7 +240,7 @@ define(function(require) {
|
|||
* @param {Object} options.folder The folder to be opened
|
||||
* @param {Function} callback(error) Invoked when the folder has been opened
|
||||
*/
|
||||
EmailDAO.prototype.openFolder = function(options, callback) {
|
||||
EmailDAO.prototype.openFolder = function(options, callback) {
|
||||
var self = this,
|
||||
err;
|
||||
|
||||
|
@ -261,9 +258,9 @@ define(function(require) {
|
|||
this._imapClient.selectMailbox({
|
||||
path: options.folder.path
|
||||
}, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Synchronizes a folder's contents from disk to memory, i.e. if
|
||||
* a message has disappeared from the disk, this method will remove it from folder.messages, and
|
||||
* it adds any messages from disk to memory the are not yet in folder.messages
|
||||
|
@ -271,7 +268,7 @@ define(function(require) {
|
|||
* @param {Object} options.folder The folder to synchronize
|
||||
* @param {Function} callback [description]
|
||||
*/
|
||||
EmailDAO.prototype.refreshFolder = function(options, callback) {
|
||||
EmailDAO.prototype.refreshFolder = function(options, callback) {
|
||||
var self = this,
|
||||
folder = options.folder;
|
||||
|
||||
|
@ -320,9 +317,9 @@ define(function(require) {
|
|||
updateUnreadCount(folder); // update the unread count
|
||||
callback(err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Fetches a message's headers from IMAP.
|
||||
*
|
||||
* NB! If we fetch a message whose subject line correspond's to that of a verification message,
|
||||
|
@ -331,7 +328,7 @@ define(function(require) {
|
|||
* @param {Object} options.folder The folder for which to fetch the message
|
||||
* @param {Function} callback(error) Invoked when the message is persisted and added to folder.messages
|
||||
*/
|
||||
EmailDAO.prototype.fetchMessages = function(options, callback) {
|
||||
EmailDAO.prototype.fetchMessages = function(options, callback) {
|
||||
var self = this,
|
||||
folder = options.folder;
|
||||
|
||||
|
@ -469,9 +466,9 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Delete a message from IMAP, disk and folder.messages.
|
||||
*
|
||||
* Please note that this deletes from disk only if you delete from the outbox,
|
||||
|
@ -482,7 +479,7 @@ define(function(require) {
|
|||
* @param {Boolean} options.localOnly Indicated if the message should not be removed from IMAP
|
||||
* @param {Function} callback(error) Invoked when the message was delete, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.deleteMessage = function(options, callback) {
|
||||
EmailDAO.prototype.deleteMessage = function(options, callback) {
|
||||
var self = this,
|
||||
folder = options.folder,
|
||||
message = options.message;
|
||||
|
@ -539,9 +536,9 @@ define(function(require) {
|
|||
updateUnreadCount(folder); // update the unread count, if necessary
|
||||
callback(err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Updates a message's 'unread' and 'answered' flags
|
||||
*
|
||||
* Please note if you set flags on disk only if you delete from the outbox,
|
||||
|
@ -550,7 +547,7 @@ define(function(require) {
|
|||
* @param {[type]} options [description]
|
||||
* @param {Function} callback [description]
|
||||
*/
|
||||
EmailDAO.prototype.setFlags = function(options, callback) {
|
||||
EmailDAO.prototype.setFlags = function(options, callback) {
|
||||
var self = this,
|
||||
folder = options.folder,
|
||||
message = options.message;
|
||||
|
@ -630,15 +627,15 @@ define(function(require) {
|
|||
updateUnreadCount(folder); // update the unread count
|
||||
callback(err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Streams message content
|
||||
* @param {Object} options.message The message for which to retrieve the body
|
||||
* @param {Object} options.folder The IMAP folder
|
||||
* @param {Function} callback(error, message) Invoked when the message is streamed, or provides information if an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.getBody = function(options, callback) {
|
||||
EmailDAO.prototype.getBody = function(options, callback) {
|
||||
var self = this,
|
||||
message = options.message,
|
||||
folder = options.folder;
|
||||
|
@ -821,9 +818,9 @@ define(function(require) {
|
|||
message.loadingBody = false;
|
||||
callback(err, err ? undefined : message);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
EmailDAO.prototype._checkSignatures = function(message, callback) {
|
||||
EmailDAO.prototype._checkSignatures = function(message, callback) {
|
||||
var self = this;
|
||||
|
||||
self._keychain.getReceiverPublicKey(message.from[0].address, function(err, senderPublicKey) {
|
||||
|
@ -842,9 +839,9 @@ define(function(require) {
|
|||
callback(null, undefined);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Retrieves an attachment matching a body part for a given uid and a folder
|
||||
*
|
||||
* @param {Object} options.folder The folder where to find the attachment
|
||||
|
@ -852,7 +849,7 @@ define(function(require) {
|
|||
* @param {Object} options.attachment The attachment body part to fetch and parse from IMAP
|
||||
* @param {Function} callback(error, attachment) Invoked when the attachment body part was retrieved and parsed, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.getAttachment = function(options, callback) {
|
||||
EmailDAO.prototype.getAttachment = function(options, callback) {
|
||||
var self = this,
|
||||
attachment = options.attachment;
|
||||
|
||||
|
@ -873,16 +870,16 @@ define(function(require) {
|
|||
attachment.content = parsedBodyParts[0].content;
|
||||
callback(err, err ? undefined : attachment);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Decrypts a message and replaces sets the decrypted plaintext as the message's body, html, or attachment, respectively.
|
||||
* The first encrypted body part's ciphertext (in the content property) will be decrypted.
|
||||
*
|
||||
* @param {Object} options.message The message
|
||||
* @param {Function} callback(error, message)
|
||||
*/
|
||||
EmailDAO.prototype.decryptBody = function(options, callback) {
|
||||
EmailDAO.prototype.decryptBody = function(options, callback) {
|
||||
var self = this,
|
||||
message = options.message;
|
||||
|
||||
|
@ -994,15 +991,15 @@ define(function(require) {
|
|||
message.decryptingBody = false;
|
||||
callback(err, err ? undefined : message);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Encrypted (if necessary) and sends a message with a predefined clear text greeting.
|
||||
*
|
||||
* @param {Object} options.email The message to be sent
|
||||
* @param {Function} callback(error) Invoked when the message was sent, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.sendEncrypted = function(options, callback) {
|
||||
EmailDAO.prototype.sendEncrypted = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
if (!self._account.online) {
|
||||
|
@ -1043,15 +1040,15 @@ define(function(require) {
|
|||
callback(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Sends a signed message in the plain
|
||||
*
|
||||
* @param {Object} options.email The message to be sent
|
||||
* @param {Function} callback(error) Invoked when the message was sent, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.sendPlaintext = function(options, callback) {
|
||||
EmailDAO.prototype.sendPlaintext = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
if (!self._account.online) {
|
||||
|
@ -1093,15 +1090,15 @@ define(function(require) {
|
|||
callback(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Signs and encrypts a message
|
||||
*
|
||||
* @param {Object} options.email The message to be encrypted
|
||||
* @param {Function} callback(error, message) Invoked when the message was encrypted, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.encrypt = function(options, callback) {
|
||||
EmailDAO.prototype.encrypt = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
self.busy();
|
||||
|
@ -1110,17 +1107,17 @@ define(function(require) {
|
|||
callback(err);
|
||||
});
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Event Handlers
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// Event Handlers
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* This handler should be invoked when navigator.onLine === true. It will try to connect a
|
||||
* given instance of the imap client. If the connection attempt was successful, it will
|
||||
* update the locally available folders with the newly received IMAP folder listing.
|
||||
|
@ -1129,7 +1126,7 @@ define(function(require) {
|
|||
* @param {Object} options.pgpMailer The SMTP client used to send messages
|
||||
* @param {Function} callback [description]
|
||||
*/
|
||||
EmailDAO.prototype.onConnect = function(options, callback) {
|
||||
EmailDAO.prototype.onConnect = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
self._account.loggingIn = true;
|
||||
|
@ -1203,13 +1200,13 @@ define(function(require) {
|
|||
}, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* This handler should be invoked when navigator.onLine === false.
|
||||
* It will discard the imap client and pgp mailer
|
||||
*/
|
||||
EmailDAO.prototype.onDisconnect = function(callback) {
|
||||
EmailDAO.prototype.onDisconnect = function(callback) {
|
||||
var self = this;
|
||||
|
||||
// logout of imap-client
|
||||
|
@ -1224,9 +1221,9 @@ define(function(require) {
|
|||
self._account.online = false;
|
||||
self._imapClient = undefined;
|
||||
self._pgpMailer = undefined;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* The are updates in the IMAP folder of the following type
|
||||
* - 'new': a list of uids that are newly available
|
||||
* - 'deleted': a list of uids that were deleted from IMAP available
|
||||
|
@ -1236,7 +1233,7 @@ define(function(require) {
|
|||
* @param {String} options.path The mailbox for which updates are available
|
||||
* @param {Array} options.list Array containing update information. Number (uid) or mail with Object (uid and flags), respectively
|
||||
*/
|
||||
EmailDAO.prototype._onSyncUpdate = function(options) {
|
||||
EmailDAO.prototype._onSyncUpdate = function(options) {
|
||||
var self = this;
|
||||
|
||||
var folder = _.findWhere(self._account.folders, {
|
||||
|
@ -1300,23 +1297,23 @@ define(function(require) {
|
|||
}, self.onError.bind(self));
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Internal API
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// Internal API
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Updates the folder information from memory, and adds/removes folders in account.folders.
|
||||
* The locally available messages are loaded from memory
|
||||
*
|
||||
* @param {Function} callback Invoked when the folders are up to date
|
||||
*/
|
||||
EmailDAO.prototype._initFoldersFromDisk = function(callback) {
|
||||
EmailDAO.prototype._initFoldersFromDisk = function(callback) {
|
||||
var self = this;
|
||||
|
||||
self.busy(); // start the spinner
|
||||
|
@ -1335,16 +1332,16 @@ define(function(require) {
|
|||
self.done(); // stop the spinner
|
||||
callback(err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Updates the folder information from imap (if we're online). Adds/removes folders in account.folders,
|
||||
* if we added/removed folder in IMAP. If we have an uninitialized folder that lacks folder.messages,
|
||||
* all the locally available messages are loaded from memory.
|
||||
*
|
||||
* @param {Function} callback Invoked when the folders are up to date
|
||||
*/
|
||||
EmailDAO.prototype._initFoldersFromImap = function(callback) {
|
||||
EmailDAO.prototype._initFoldersFromImap = function(callback) {
|
||||
var self = this;
|
||||
|
||||
self.busy(); // start the spinner
|
||||
|
@ -1434,14 +1431,14 @@ define(function(require) {
|
|||
self.done(); // stop the spinner
|
||||
callback(err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Fill uninitialized folders with the locally available messages.
|
||||
*
|
||||
* @param {Function} callback Invoked when the folders are filled with messages
|
||||
*/
|
||||
EmailDAO.prototype._initMessagesFromDisk = function(callback) {
|
||||
EmailDAO.prototype._initMessagesFromDisk = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (!self._account.folders || self._account.folders.length === 0) {
|
||||
|
@ -1467,27 +1464,27 @@ define(function(require) {
|
|||
after();
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
EmailDAO.prototype.busy = function() {
|
||||
EmailDAO.prototype.busy = function() {
|
||||
this._account.busy++;
|
||||
};
|
||||
};
|
||||
|
||||
EmailDAO.prototype.done = function() {
|
||||
EmailDAO.prototype.done = function() {
|
||||
if (this._account.busy > 0) {
|
||||
this._account.busy--;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// IMAP API
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// IMAP API
|
||||
//
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Mark messages as un-/read or un-/answered on IMAP
|
||||
*
|
||||
* @param {Object} options.folder The folder where to find the message
|
||||
|
@ -1495,7 +1492,7 @@ define(function(require) {
|
|||
* @param {Number} options.unread Un-/Read flag
|
||||
* @param {Number} options.answered Un-/Answered flag
|
||||
*/
|
||||
EmailDAO.prototype._imapMark = function(options, callback) {
|
||||
EmailDAO.prototype._imapMark = function(options, callback) {
|
||||
if (!this._account.online) {
|
||||
callback({
|
||||
errMsg: 'Client is currently offline!',
|
||||
|
@ -1506,9 +1503,9 @@ define(function(require) {
|
|||
|
||||
options.path = options.folder.path;
|
||||
this._imapClient.updateFlags(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* If we're in the trash folder or no trash folder is available, this deletes a message from IMAP.
|
||||
* Otherwise, it moves a message to the trash folder.
|
||||
*
|
||||
|
@ -1516,7 +1513,7 @@ define(function(require) {
|
|||
* @param {Number} options.uid The uid of the message
|
||||
* @param {Function} callback(error) Callback with an error object in case something went wrong.
|
||||
*/
|
||||
EmailDAO.prototype._imapDeleteMessage = function(options, callback) {
|
||||
EmailDAO.prototype._imapDeleteMessage = function(options, callback) {
|
||||
if (!this._account.online) {
|
||||
callback({
|
||||
errMsg: 'Client is currently offline!',
|
||||
|
@ -1545,9 +1542,9 @@ define(function(require) {
|
|||
destination: trash.path,
|
||||
uid: options.uid
|
||||
}, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get list messsage headers without the body
|
||||
*
|
||||
* @param {String} options.folder The folder
|
||||
|
@ -1555,7 +1552,7 @@ define(function(require) {
|
|||
* @param {Number} options.lastUid The upper bound of the uid range (inclusive)
|
||||
* @param {Function} callback (error, messages) The callback when the imap client is done fetching message metadata
|
||||
*/
|
||||
EmailDAO.prototype._imapListMessages = function(options, callback) {
|
||||
EmailDAO.prototype._imapListMessages = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
if (!this._account.online) {
|
||||
|
@ -1568,16 +1565,16 @@ define(function(require) {
|
|||
|
||||
options.path = options.folder.path;
|
||||
self._imapClient.listMessages(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Stream an email messsage's body
|
||||
* @param {String} options.folder The folder
|
||||
* @param {String} options.uid the message's uid
|
||||
* @param {Object} options.bodyParts The message, as retrieved by _imapListMessages
|
||||
* @param {Function} callback (error, message) The callback when the imap client is done streaming message text content
|
||||
*/
|
||||
EmailDAO.prototype._getBodyParts = function(options, callback) {
|
||||
EmailDAO.prototype._getBodyParts = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
if (!self._account.online) {
|
||||
|
@ -1597,17 +1594,17 @@ define(function(require) {
|
|||
// interpret the raw content of the email
|
||||
self._mailreader.parse(options, callback);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Local Storage API
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// Local Storage API
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* List the locally available items form the indexed db stored under "email_[FOLDER PATH]_[MESSAGE UID]" (if a message was provided),
|
||||
* or "email_[FOLDER PATH]", respectively
|
||||
*
|
||||
|
@ -1615,31 +1612,31 @@ define(function(require) {
|
|||
* @param {Object} options.uid A specific uid to look up locally in the folder
|
||||
* @param {Function} callback(error, list) Invoked with the results of the query, or further information, if an error occurred
|
||||
*/
|
||||
EmailDAO.prototype._localListMessages = function(options, callback) {
|
||||
EmailDAO.prototype._localListMessages = function(options, callback) {
|
||||
var dbType = 'email_' + options.folder.path + (options.uid ? '_' + options.uid : '');
|
||||
this._devicestorage.listItems(dbType, 0, null, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Stores a bunch of messages to the indexed db. The messages are stored under "email_[FOLDER PATH]_[MESSAGE UID]"
|
||||
*
|
||||
* @param {Object} options.folder The folder for which to list the content
|
||||
* @param {Array} options.messages The messages to store
|
||||
* @param {Function} callback(error, list) Invoked with the results of the query, or further information, if an error occurred
|
||||
*/
|
||||
EmailDAO.prototype._localStoreMessages = function(options, callback) {
|
||||
EmailDAO.prototype._localStoreMessages = function(options, callback) {
|
||||
var dbType = 'email_' + options.folder.path;
|
||||
this._devicestorage.storeList(options.emails, dbType, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Stores a bunch of messages to the indexed db. The messages are stored under "email_[FOLDER PATH]_[MESSAGE UID]"
|
||||
*
|
||||
* @param {Object} options.folder The folder for which to list the content
|
||||
* @param {Array} options.messages The messages to store
|
||||
* @param {Function} callback(error, list) Invoked with the results of the query, or further information, if an error occurred
|
||||
*/
|
||||
EmailDAO.prototype._localDeleteMessage = function(options, callback) {
|
||||
EmailDAO.prototype._localDeleteMessage = function(options, callback) {
|
||||
var path = options.folder.path,
|
||||
uid = options.uid,
|
||||
id = options.id;
|
||||
|
@ -1653,38 +1650,38 @@ define(function(require) {
|
|||
|
||||
var dbType = 'email_' + path + '_' + (uid || id);
|
||||
this._devicestorage.removeList(dbType, callback);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Helper Functions
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// Helper Functions
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Updates a folder's unread count:
|
||||
* - For the outbox, that's the total number of messages,
|
||||
* - For every other folder, it's the number of unread messages
|
||||
*/
|
||||
function updateUnreadCount(folder) {
|
||||
function updateUnreadCount(folder) {
|
||||
var allMsgs = folder.messages.length,
|
||||
unreadMsgs = _.filter(folder.messages, function(msg) {
|
||||
return msg.unread;
|
||||
}).length;
|
||||
|
||||
folder.count = folder.path === config.outboxMailboxPath ? allMsgs : unreadMsgs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Helper function that recursively traverses the body parts tree. Looks for bodyParts that match the provided type and aggregates them
|
||||
*
|
||||
* @param {Array} bodyParts The bodyParts array
|
||||
* @param {String} type The type to look up
|
||||
* @param {undefined} result Leave undefined, only used for recursion
|
||||
*/
|
||||
function filterBodyParts(bodyParts, type, result) {
|
||||
function filterBodyParts(bodyParts, type, result) {
|
||||
result = result || [];
|
||||
bodyParts.forEach(function(part) {
|
||||
if (part.type === type) {
|
||||
|
@ -1694,9 +1691,9 @@ define(function(require) {
|
|||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Helper function that looks through the HTML content for <img src="cid:..."> and
|
||||
* inlines the images linked internally. Manipulates message.html as a side-effect.
|
||||
* If no attachment matching the internal reference is found, or constructing a data
|
||||
|
@ -1704,7 +1701,7 @@ define(function(require) {
|
|||
*
|
||||
* @param {Object} message DTO
|
||||
*/
|
||||
function inlineExternalImages(message) {
|
||||
function inlineExternalImages(message) {
|
||||
message.html = message.html.replace(/(<img[^>]+\bsrc=['"])cid:([^'">]+)(['"])/ig, function(match, prefix, src, suffix) {
|
||||
var localSource = '',
|
||||
payload = '';
|
||||
|
@ -1725,7 +1722,6 @@ define(function(require) {
|
|||
|
||||
return prefix + localSource + suffix;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return EmailDAO;
|
||||
});
|
||||
module.exports = EmailDAO;
|
|
@ -1,33 +1,32 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
/**
|
||||
* The InvitationDAO is a high level Data Access Object that access the invitation service REST endpoint.
|
||||
* @param {Object} restDao The REST Data Access Object abstraction
|
||||
*/
|
||||
var InvitationDAO = function(restDao) {
|
||||
var InvitationDAO = function(restDao) {
|
||||
this._restDao = restDao;
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
|
||||
InvitationDAO.INVITE_MISSING = 1;
|
||||
InvitationDAO.INVITE_PENDING = 2;
|
||||
InvitationDAO.INVITE_SUCCESS = 4;
|
||||
InvitationDAO.INVITE_MISSING = 1;
|
||||
InvitationDAO.INVITE_PENDING = 2;
|
||||
InvitationDAO.INVITE_SUCCESS = 4;
|
||||
|
||||
//
|
||||
// API
|
||||
//
|
||||
//
|
||||
// API
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Notes an invite for the recipient by the sender in the invitation web service
|
||||
* @param {String} options.recipient User ID of the recipient
|
||||
* @param {String} options.sender User ID of the sender
|
||||
* @param {Function} callback(error, status) Returns information if the invitation worked (INVITE_SUCCESS), if an invitation is already pendin (INVITE_PENDING), or information if an error occurred.
|
||||
*/
|
||||
InvitationDAO.prototype.invite = function(options, callback) {
|
||||
InvitationDAO.prototype.invite = function(options, callback) {
|
||||
if (typeof options !== 'object' || typeof options.recipient !== 'string' || typeof options.recipient !== 'string') {
|
||||
callback({
|
||||
errMsg: 'erroneous usage of api: incorrect parameters!'
|
||||
|
@ -56,7 +55,6 @@ define(function() {
|
|||
errMsg: 'unexpected invitation state'
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return InvitationDAO;
|
||||
});
|
||||
module.exports = InvitationDAO;
|
|
@ -2,46 +2,45 @@
|
|||
* A high-level Data-Access Api for handling Keypair synchronization
|
||||
* between the cloud service and the device's local storage
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore'),
|
||||
util = require('js/crypto/util'),
|
||||
config = require('js/app-config').config;
|
||||
'use strict';
|
||||
|
||||
var DB_PUBLICKEY = 'publickey',
|
||||
var util = require('crypto-lib').util,
|
||||
config = require('../app-config').config;
|
||||
|
||||
var DB_PUBLICKEY = 'publickey',
|
||||
DB_PRIVATEKEY = 'privatekey',
|
||||
DB_DEVICENAME = 'devicename',
|
||||
DB_DEVICE_SECRET = 'devicesecret';
|
||||
|
||||
var KeychainDAO = function(localDbDao, publicKeyDao, privateKeyDao, crypto, pgp) {
|
||||
var KeychainDAO = function(localDbDao, publicKeyDao, privateKeyDao, crypto, pgp) {
|
||||
this._localDbDao = localDbDao;
|
||||
this._publicKeyDao = publicKeyDao;
|
||||
this._privateKeyDao = privateKeyDao;
|
||||
this._crypto = crypto;
|
||||
this._pgp = pgp;
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Public key functions
|
||||
//
|
||||
//
|
||||
// Public key functions
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Verifies the public key of a user o nthe public key store
|
||||
* @param {String} uuid The uuid to verify the key
|
||||
* @param {Function} callback(error) Callback with an optional error object when the verification is done. If the was an error, the error object contains the information for it.
|
||||
*/
|
||||
KeychainDAO.prototype.verifyPublicKey = function(uuid, callback) {
|
||||
KeychainDAO.prototype.verifyPublicKey = function(uuid, callback) {
|
||||
this._publicKeyDao.verify(uuid, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get an array of public keys by looking in local storage and
|
||||
* fetching missing keys from the cloud service.
|
||||
* @param ids [Array] the key ids as [{_id, userId}]
|
||||
* @return [PublicKeyCollection] The requiested public keys
|
||||
*/
|
||||
KeychainDAO.prototype.getPublicKeys = function(ids, callback) {
|
||||
KeychainDAO.prototype.getPublicKeys = function(ids, callback) {
|
||||
var self = this,
|
||||
after, already, pubkeys = [];
|
||||
|
||||
|
@ -78,14 +77,14 @@ define(function(require) {
|
|||
after(); // asynchronously iterate through objects
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks for public key updates of a given user id
|
||||
* @param {String} userId The user id (email address) for which to check the key
|
||||
* @param {Function} callback(error, key) Invoked when the key has been updated or an error occurred
|
||||
*/
|
||||
KeychainDAO.prototype.refreshKeyForUserId = function(userId, callback) {
|
||||
KeychainDAO.prototype.refreshKeyForUserId = function(userId, callback) {
|
||||
var self = this;
|
||||
|
||||
// get the public key corresponding to the userId
|
||||
|
@ -174,13 +173,13 @@ define(function(require) {
|
|||
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Look up a reveiver's public key by user id
|
||||
* @param userId [String] the receiver's email address
|
||||
*/
|
||||
KeychainDAO.prototype.getReceiverPublicKey = function(userId, callback) {
|
||||
KeychainDAO.prototype.getReceiverPublicKey = function(userId, callback) {
|
||||
var self = this;
|
||||
|
||||
// search local keyring for public key
|
||||
|
@ -246,32 +245,32 @@ define(function(require) {
|
|||
callback(null, cloudPubkey);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Device registration functions
|
||||
//
|
||||
//
|
||||
// Device registration functions
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Set the device's memorable name e.g 'iPhone Work'
|
||||
* @param {String} deviceName The device name
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
KeychainDAO.prototype.setDeviceName = function(deviceName, callback) {
|
||||
KeychainDAO.prototype.setDeviceName = function(deviceName, callback) {
|
||||
if (!deviceName) {
|
||||
callback(new Error('Please set a device name!'));
|
||||
return;
|
||||
}
|
||||
|
||||
this._localDbDao.persist(DB_DEVICENAME, deviceName, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the device' memorable name from local storage. Throws an error if not set
|
||||
* @param {Function} callback(error, deviceName)
|
||||
* @return {String} The device name
|
||||
*/
|
||||
KeychainDAO.prototype.getDeviceName = function(callback) {
|
||||
KeychainDAO.prototype.getDeviceName = function(callback) {
|
||||
// check if deviceName is already persisted in storage
|
||||
this._localDbDao.read(DB_DEVICENAME, function(err, deviceName) {
|
||||
if (err) {
|
||||
|
@ -286,13 +285,13 @@ define(function(require) {
|
|||
|
||||
callback(null, deviceName);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Geneate a device specific key and secret to authenticate to the private key service.
|
||||
* @param {Function} callback(error, deviceSecret:[base64 encoded string])
|
||||
*/
|
||||
KeychainDAO.prototype.getDeviceSecret = function(callback) {
|
||||
KeychainDAO.prototype.getDeviceSecret = function(callback) {
|
||||
var self = this;
|
||||
|
||||
// generate random deviceSecret or get from storage
|
||||
|
@ -320,14 +319,14 @@ define(function(require) {
|
|||
callback(null, deviceSecret);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Register the device on the private key server. This will give the device access to upload an encrypted private key.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
KeychainDAO.prototype.registerDevice = function(options, callback) {
|
||||
KeychainDAO.prototype.registerDevice = function(options, callback) {
|
||||
var self = this,
|
||||
devName;
|
||||
|
||||
|
@ -414,19 +413,19 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Private key functions
|
||||
//
|
||||
//
|
||||
// Private key functions
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Authenticate to the private key server (required before private PGP key upload).
|
||||
* @param {String} userId The user's email address
|
||||
* @param {Function} callback(error, authSessionKey)
|
||||
* @return {Object} {sessionId:String, sessionKey:[base64 encoded]}
|
||||
*/
|
||||
KeychainDAO.prototype._authenticateToPrivateKeyServer = function(userId, callback) {
|
||||
KeychainDAO.prototype._authenticateToPrivateKeyServer = function(userId, callback) {
|
||||
var self = this,
|
||||
sessionId;
|
||||
|
||||
|
@ -535,15 +534,15 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Encrypt and upload the private PGP key to the server.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.code The randomly generated or self selected code used to derive the key for the encryption of the private PGP key
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
KeychainDAO.prototype.uploadPrivateKey = function(options, callback) {
|
||||
KeychainDAO.prototype.uploadPrivateKey = function(options, callback) {
|
||||
var self = this,
|
||||
keySize = config.symKeySize,
|
||||
salt;
|
||||
|
@ -629,40 +628,40 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Request downloading the user's encrypted private key. This will initiate the server to send the recovery token via email/sms to the user.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.keyId The private PGP key id
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
KeychainDAO.prototype.requestPrivateKeyDownload = function(options, callback) {
|
||||
KeychainDAO.prototype.requestPrivateKeyDownload = function(options, callback) {
|
||||
this._privateKeyDao.requestDownload(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Query if an encrypted private PGP key exists on the server without initializing the recovery procedure
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.keyId The private PGP key id
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
KeychainDAO.prototype.hasPrivateKey = function(options, callback) {
|
||||
KeychainDAO.prototype.hasPrivateKey = function(options, callback) {
|
||||
this._privateKeyDao.hasPrivateKey(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Download the encrypted private PGP key from the server using the recovery token.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.keyId The user's email address
|
||||
* @param {String} options.recoveryToken The recovery token acquired via email/sms from the key server
|
||||
* @param {Function} callback(error, encryptedPrivateKey)
|
||||
*/
|
||||
KeychainDAO.prototype.downloadPrivateKey = function(options, callback) {
|
||||
KeychainDAO.prototype.downloadPrivateKey = function(options, callback) {
|
||||
this._privateKeyDao.download(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* This is called after the encrypted private key has successfully been downloaded and it's ready to be decrypted and stored in localstorage.
|
||||
* @param {String} options._id The private PGP key id
|
||||
* @param {String} options.userId The user's email address
|
||||
|
@ -672,7 +671,7 @@ define(function(require) {
|
|||
* @param {String} options.iv The iv used to encrypt the private PGP key
|
||||
* @param {Function} callback(error, keyObject)
|
||||
*/
|
||||
KeychainDAO.prototype.decryptAndStorePrivateKeyLocally = function(options, callback) {
|
||||
KeychainDAO.prototype.decryptAndStorePrivateKeyLocally = function(options, callback) {
|
||||
var self = this,
|
||||
code = options.code,
|
||||
salt = options.salt,
|
||||
|
@ -735,19 +734,19 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Keypair functions
|
||||
//
|
||||
//
|
||||
// Keypair functions
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Gets the local user's key either from local storage
|
||||
* or fetches it from the cloud. The private key is encrypted.
|
||||
* If no key pair exists, null is returned.
|
||||
* return [Object] The user's key pair {publicKey, privateKey}
|
||||
*/
|
||||
KeychainDAO.prototype.getUserKeyPair = function(userId, callback) {
|
||||
KeychainDAO.prototype.getUserKeyPair = function(userId, callback) {
|
||||
var self = this;
|
||||
|
||||
// search for user's public key locally
|
||||
|
@ -817,14 +816,14 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks to see if the user's key pair is stored both
|
||||
* locally and in the cloud and persist arccordingly
|
||||
* @param [Object] The user's key pair {publicKey, privateKey}
|
||||
*/
|
||||
KeychainDAO.prototype.putUserKeyPair = function(keypair, callback) {
|
||||
KeychainDAO.prototype.putUserKeyPair = function(keypair, callback) {
|
||||
var self = this;
|
||||
|
||||
// validate input
|
||||
|
@ -857,13 +856,13 @@ define(function(require) {
|
|||
self.saveLocalPrivateKey(keypair.privateKey, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Helper functions
|
||||
//
|
||||
//
|
||||
// Helper functions
|
||||
//
|
||||
|
||||
KeychainDAO.prototype.lookupPublicKey = function(id, callback) {
|
||||
KeychainDAO.prototype.lookupPublicKey = function(id, callback) {
|
||||
var self = this;
|
||||
|
||||
if (!id) {
|
||||
|
@ -903,36 +902,35 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* List all the locally stored public keys
|
||||
*/
|
||||
KeychainDAO.prototype.listLocalPublicKeys = function(callback) {
|
||||
KeychainDAO.prototype.listLocalPublicKeys = function(callback) {
|
||||
// search local keyring for public key
|
||||
this._localDbDao.list(DB_PUBLICKEY, 0, null, callback);
|
||||
};
|
||||
};
|
||||
|
||||
KeychainDAO.prototype.removeLocalPublicKey = function(id, callback) {
|
||||
KeychainDAO.prototype.removeLocalPublicKey = function(id, callback) {
|
||||
this._localDbDao.remove(DB_PUBLICKEY + '_' + id, callback);
|
||||
};
|
||||
};
|
||||
|
||||
KeychainDAO.prototype.lookupPrivateKey = function(id, callback) {
|
||||
KeychainDAO.prototype.lookupPrivateKey = function(id, callback) {
|
||||
// lookup in local storage
|
||||
this._localDbDao.read(DB_PRIVATEKEY + '_' + id, callback);
|
||||
};
|
||||
};
|
||||
|
||||
KeychainDAO.prototype.saveLocalPublicKey = function(pubkey, callback) {
|
||||
KeychainDAO.prototype.saveLocalPublicKey = function(pubkey, callback) {
|
||||
// persist public key (email, _id)
|
||||
var pkLookupKey = DB_PUBLICKEY + '_' + pubkey._id;
|
||||
this._localDbDao.persist(pkLookupKey, pubkey, callback);
|
||||
};
|
||||
};
|
||||
|
||||
KeychainDAO.prototype.saveLocalPrivateKey = function(privkey, callback) {
|
||||
KeychainDAO.prototype.saveLocalPrivateKey = function(privkey, callback) {
|
||||
// persist private key (email, _id)
|
||||
var prkLookupKey = DB_PRIVATEKEY + '_' + privkey._id;
|
||||
this._localDbDao.persist(prkLookupKey, privkey, callback);
|
||||
};
|
||||
};
|
||||
|
||||
return KeychainDAO;
|
||||
});
|
||||
module.exports = KeychainDAO;
|
|
@ -1,17 +1,12 @@
|
|||
/**
|
||||
* Handles generic caching of JSON objects in a lawnchair adapter
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore'),
|
||||
Lawnchair = require('lawnchair');
|
||||
require('lawnchairSQL');
|
||||
require('lawnchairIDB');
|
||||
'use strict';
|
||||
|
||||
var LawnchairDAO = function() {};
|
||||
var LawnchairDAO = function() {};
|
||||
|
||||
LawnchairDAO.prototype.init = function(dbName, callback) {
|
||||
LawnchairDAO.prototype.init = function(dbName, callback) {
|
||||
if (!dbName) {
|
||||
callback({
|
||||
errMsg: 'Lawnchair DB name must be specified!'
|
||||
|
@ -31,12 +26,12 @@ define(function(require) {
|
|||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Create or update an object
|
||||
*/
|
||||
LawnchairDAO.prototype.persist = function(key, object, callback) {
|
||||
LawnchairDAO.prototype.persist = function(key, object, callback) {
|
||||
if (!key || !object) {
|
||||
callback({
|
||||
errMsg: 'Key and Object must be set!'
|
||||
|
@ -57,12 +52,12 @@ define(function(require) {
|
|||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Persist a bunch of items at once
|
||||
*/
|
||||
LawnchairDAO.prototype.batch = function(list, callback) {
|
||||
LawnchairDAO.prototype.batch = function(list, callback) {
|
||||
if (!(list instanceof Array)) {
|
||||
callback({
|
||||
errMsg: 'Input must be of type Array!'
|
||||
|
@ -80,12 +75,12 @@ define(function(require) {
|
|||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Read a single item by its key
|
||||
*/
|
||||
LawnchairDAO.prototype.read = function(key, callback) {
|
||||
LawnchairDAO.prototype.read = function(key, callback) {
|
||||
if (!key) {
|
||||
callback({
|
||||
errMsg: 'Key must be specified!'
|
||||
|
@ -100,15 +95,15 @@ define(function(require) {
|
|||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* List all the items of a certain type
|
||||
* @param type [String] The type of item e.g. 'email'
|
||||
* @param offset [Number] The offset of items to fetch (0 is the last stored item)
|
||||
* @param num [Number] The number of items to fetch (null means fetch all)
|
||||
*/
|
||||
LawnchairDAO.prototype.list = function(type, offset, num, callback) {
|
||||
LawnchairDAO.prototype.list = function(type, offset, num, callback) {
|
||||
var self = this,
|
||||
i, from, to,
|
||||
matchingKeys = [],
|
||||
|
@ -164,19 +159,19 @@ define(function(require) {
|
|||
});
|
||||
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Removes an object liter from local storage by its key (delete)
|
||||
*/
|
||||
LawnchairDAO.prototype.remove = function(key, callback) {
|
||||
LawnchairDAO.prototype.remove = function(key, callback) {
|
||||
this._db.remove(key, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Removes an object liter from local storage by its key (delete)
|
||||
*/
|
||||
LawnchairDAO.prototype.removeList = function(type, callback) {
|
||||
LawnchairDAO.prototype.removeList = function(type, callback) {
|
||||
var self = this,
|
||||
matchingKeys = [],
|
||||
after;
|
||||
|
@ -209,14 +204,13 @@ define(function(require) {
|
|||
self._db.remove(key, after);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Clears the whole local storage cache
|
||||
*/
|
||||
LawnchairDAO.prototype.clear = function(callback) {
|
||||
LawnchairDAO.prototype.clear = function(callback) {
|
||||
this._db.nuke(callback);
|
||||
};
|
||||
};
|
||||
|
||||
return LawnchairDAO;
|
||||
});
|
||||
module.exports = LawnchairDAO;
|
|
@ -1,22 +1,21 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var PrivateKeyDAO = function(restDao) {
|
||||
var PrivateKeyDAO = function(restDao) {
|
||||
this._restDao = restDao;
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Device registration functions
|
||||
//
|
||||
//
|
||||
// Device registration functions
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Request registration of a new device by fetching registration session key.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.deviceName The device's memorable name
|
||||
* @param {Function} callback(error, regSessionKey)
|
||||
* @return {Object} {encryptedRegSessionKey:[base64]}
|
||||
*/
|
||||
PrivateKeyDAO.prototype.requestDeviceRegistration = function(options, callback) {
|
||||
PrivateKeyDAO.prototype.requestDeviceRegistration = function(options, callback) {
|
||||
var uri;
|
||||
|
||||
if (!options.userId || !options.deviceName) {
|
||||
|
@ -26,9 +25,9 @@ define(function() {
|
|||
|
||||
uri = '/device/user/' + options.userId + '/devicename/' + options.deviceName;
|
||||
this._restDao.post(undefined, uri, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Authenticate device registration by uploading the deviceSecret encrypted with the regSessionKeys.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.deviceName The device's memorable name
|
||||
|
@ -36,7 +35,7 @@ define(function() {
|
|||
* @param {String} options.iv The iv used for encryption
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
PrivateKeyDAO.prototype.uploadDeviceSecret = function(options, callback) {
|
||||
PrivateKeyDAO.prototype.uploadDeviceSecret = function(options, callback) {
|
||||
var uri;
|
||||
|
||||
if (!options.userId || !options.deviceName || !options.encryptedDeviceSecret || !options.iv) {
|
||||
|
@ -46,19 +45,19 @@ define(function() {
|
|||
|
||||
uri = '/device/user/' + options.userId + '/devicename/' + options.deviceName;
|
||||
this._restDao.put(options, uri, callback);
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Private key functions
|
||||
//
|
||||
//
|
||||
// Private key functions
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Request authSessionKeys required for upload the encrypted private PGP key.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {Function} callback(error, authSessionKey)
|
||||
* @return {Object} {sessionId, encryptedAuthSessionKey:[base64 encoded], encryptedChallenge:[base64 encoded]}
|
||||
*/
|
||||
PrivateKeyDAO.prototype.requestAuthSessionKey = function(options, callback) {
|
||||
PrivateKeyDAO.prototype.requestAuthSessionKey = function(options, callback) {
|
||||
var uri;
|
||||
|
||||
if (!options.userId) {
|
||||
|
@ -68,9 +67,9 @@ define(function() {
|
|||
|
||||
uri = '/auth/user/' + options.userId;
|
||||
this._restDao.post(undefined, uri, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Verifiy authentication by uploading the challenge and deviceSecret encrypted with the authSessionKeys as a response.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.encryptedChallenge The server's base64 encoded challenge encrypted using the authSessionKey
|
||||
|
@ -78,7 +77,7 @@ define(function() {
|
|||
* @param {String} options.iv The iv used for encryption
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
PrivateKeyDAO.prototype.verifyAuthentication = function(options, callback) {
|
||||
PrivateKeyDAO.prototype.verifyAuthentication = function(options, callback) {
|
||||
var uri;
|
||||
|
||||
if (!options.userId || !options.sessionId || !options.encryptedChallenge || !options.encryptedDeviceSecret || !options.iv) {
|
||||
|
@ -88,9 +87,9 @@ define(function() {
|
|||
|
||||
uri = '/auth/user/' + options.userId + '/session/' + options.sessionId;
|
||||
this._restDao.put(options, uri, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Upload the encrypted private PGP key.
|
||||
* @param {String} options._id The hex encoded capital 16 char key id
|
||||
* @param {String} options.userId The user's email address
|
||||
|
@ -98,7 +97,7 @@ define(function() {
|
|||
* @param {String} options.sessionId The session id
|
||||
* @param {Function} callback(error)
|
||||
*/
|
||||
PrivateKeyDAO.prototype.upload = function(options, callback) {
|
||||
PrivateKeyDAO.prototype.upload = function(options, callback) {
|
||||
var uri;
|
||||
|
||||
if (!options._id || !options.userId || !options.encryptedPrivateKey || !options.sessionId || !options.salt || !options.iv) {
|
||||
|
@ -108,16 +107,16 @@ define(function() {
|
|||
|
||||
uri = '/privatekey/user/' + options.userId + '/session/' + options.sessionId;
|
||||
this._restDao.post(options, uri, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Query if an encrypted private PGP key exists on the server without initializing the recovery procedure.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.keyId The private PGP key id
|
||||
* @param {Function} callback(error, found)
|
||||
* @return {Boolean} whether the key was found on the server or not.
|
||||
*/
|
||||
PrivateKeyDAO.prototype.hasPrivateKey = function(options, callback) {
|
||||
PrivateKeyDAO.prototype.hasPrivateKey = function(options, callback) {
|
||||
if (!options.userId || !options.keyId) {
|
||||
callback(new Error('Incomplete arguments!'));
|
||||
return;
|
||||
|
@ -139,16 +138,16 @@ define(function() {
|
|||
|
||||
callback(null, true);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Request download for the encrypted private PGP key.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.keyId The private PGP key id
|
||||
* @param {Function} callback(error, found)
|
||||
* @return {Boolean} whether the key was found on the server or not.
|
||||
*/
|
||||
PrivateKeyDAO.prototype.requestDownload = function(options, callback) {
|
||||
PrivateKeyDAO.prototype.requestDownload = function(options, callback) {
|
||||
if (!options.userId || !options.keyId) {
|
||||
callback(new Error('Incomplete arguments!'));
|
||||
return;
|
||||
|
@ -170,9 +169,9 @@ define(function() {
|
|||
|
||||
callback(null, true);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Verify the download request for the private PGP key using the recovery token sent via email. This downloads the actual encrypted private key.
|
||||
* @param {String} options.userId The user's email address
|
||||
* @param {String} options.keyId The private key id
|
||||
|
@ -180,7 +179,7 @@ define(function() {
|
|||
* @param {Function} callback(error, encryptedPrivateKey)
|
||||
* @return {Object} {_id:[hex encoded capital 16 char key id], encryptedPrivateKey:[base64 encoded], encryptedUserId: [base64 encoded]}
|
||||
*/
|
||||
PrivateKeyDAO.prototype.download = function(options, callback) {
|
||||
PrivateKeyDAO.prototype.download = function(options, callback) {
|
||||
var uri;
|
||||
|
||||
if (!options.userId || !options.keyId || !options.recoveryToken) {
|
||||
|
@ -192,7 +191,6 @@ define(function() {
|
|||
this._restDao.get({
|
||||
uri: uri
|
||||
}, callback);
|
||||
};
|
||||
};
|
||||
|
||||
return PrivateKeyDAO;
|
||||
});
|
||||
module.exports = PrivateKeyDAO;
|
|
@ -1,14 +1,13 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var PublicKeyDAO = function(restDao) {
|
||||
var PublicKeyDAO = function(restDao) {
|
||||
this._restDao = restDao;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Verify the public key behind the given uuid
|
||||
*/
|
||||
PublicKeyDAO.prototype.verify = function(uuid, callback) {
|
||||
PublicKeyDAO.prototype.verify = function(uuid, callback) {
|
||||
var uri = '/verify/' + uuid;
|
||||
|
||||
this._restDao.get({
|
||||
|
@ -23,12 +22,12 @@ define(function() {
|
|||
|
||||
callback(err, res, status);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Find the user's corresponding public key
|
||||
*/
|
||||
PublicKeyDAO.prototype.get = function(keyId, callback) {
|
||||
PublicKeyDAO.prototype.get = function(keyId, callback) {
|
||||
var uri = '/publickey/key/' + keyId;
|
||||
|
||||
this._restDao.get({
|
||||
|
@ -46,12 +45,12 @@ define(function() {
|
|||
|
||||
callback(null, (key && key._id) ? key : undefined);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Find the user's corresponding public key by email
|
||||
*/
|
||||
PublicKeyDAO.prototype.getByUserId = function(userId, callback) {
|
||||
PublicKeyDAO.prototype.getByUserId = function(userId, callback) {
|
||||
var uri = '/publickey/user/' + userId;
|
||||
|
||||
this._restDao.get({
|
||||
|
@ -83,23 +82,22 @@ define(function() {
|
|||
|
||||
callback(null, keys[0]);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Persist the user's publc key
|
||||
*/
|
||||
PublicKeyDAO.prototype.put = function(pubkey, callback) {
|
||||
PublicKeyDAO.prototype.put = function(pubkey, callback) {
|
||||
var uri = '/publickey/user/' + pubkey.userId + '/key/' + pubkey._id;
|
||||
this._restDao.put(pubkey, uri, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Delete the public key from the cloud storage service
|
||||
*/
|
||||
PublicKeyDAO.prototype.remove = function(keyId, callback) {
|
||||
PublicKeyDAO.prototype.remove = function(keyId, callback) {
|
||||
var uri = '/publickey/key/' + keyId;
|
||||
this._restDao.remove(uri, callback);
|
||||
};
|
||||
};
|
||||
|
||||
return PublicKeyDAO;
|
||||
});
|
||||
module.exports = PublicKeyDAO;
|
|
@ -1,63 +1,62 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var config = require('js/app-config').config;
|
||||
var config = require('../app-config').config;
|
||||
|
||||
var RestDAO = function(baseUri) {
|
||||
var RestDAO = function(baseUri) {
|
||||
if (baseUri) {
|
||||
this._baseUri = baseUri;
|
||||
} else {
|
||||
this._baseUri = config.cloudUrl;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* GET (read) request
|
||||
* @param {String} options.uri URI relative to the base uri to perform the GET request with.
|
||||
* @param {String} options.type (optional) The type of data that you're expecting back from the server: json, xml, text. Default: json.
|
||||
*/
|
||||
RestDAO.prototype.get = function(options, callback) {
|
||||
RestDAO.prototype.get = function(options, callback) {
|
||||
options.method = 'GET';
|
||||
this._processRequest(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* POST (create) request
|
||||
*/
|
||||
RestDAO.prototype.post = function(item, uri, callback) {
|
||||
RestDAO.prototype.post = function(item, uri, callback) {
|
||||
this._processRequest({
|
||||
method: 'POST',
|
||||
payload: item,
|
||||
uri: uri
|
||||
}, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* PUT (update) request
|
||||
*/
|
||||
RestDAO.prototype.put = function(item, uri, callback) {
|
||||
RestDAO.prototype.put = function(item, uri, callback) {
|
||||
this._processRequest({
|
||||
method: 'PUT',
|
||||
payload: item,
|
||||
uri: uri
|
||||
}, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* DELETE (remove) request
|
||||
*/
|
||||
RestDAO.prototype.remove = function(uri, callback) {
|
||||
RestDAO.prototype.remove = function(uri, callback) {
|
||||
this._processRequest({
|
||||
method: 'DELETE',
|
||||
uri: uri
|
||||
}, callback);
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// helper functions
|
||||
//
|
||||
//
|
||||
// helper functions
|
||||
//
|
||||
|
||||
RestDAO.prototype._processRequest = function(options, callback) {
|
||||
RestDAO.prototype._processRequest = function(options, callback) {
|
||||
var xhr, format;
|
||||
|
||||
if (typeof options.uri === 'undefined') {
|
||||
|
@ -117,7 +116,6 @@ define(function(require) {
|
|||
};
|
||||
|
||||
xhr.send(options.payload ? JSON.stringify(options.payload) : undefined);
|
||||
};
|
||||
};
|
||||
|
||||
return RestDAO;
|
||||
});
|
||||
module.exports = RestDAO;
|
|
@ -1,10 +1,9 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var axe = require('axe'),
|
||||
var axe = require('axe-logger'),
|
||||
DEBUG_TAG = 'backbutton handler';
|
||||
|
||||
/**
|
||||
/**
|
||||
* The back button handler introduces meaningful behavior fo rthe back button:
|
||||
* if there's an open lightbox, close it;
|
||||
* if the reader is open in mobile mode, close it;
|
||||
|
@ -13,7 +12,7 @@ define(function(require) {
|
|||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var backBtnHandler = {
|
||||
var backBtnHandler = {
|
||||
attachHandler: function(scope) {
|
||||
this.scope = scope;
|
||||
},
|
||||
|
@ -23,9 +22,9 @@ define(function(require) {
|
|||
stop: function() {
|
||||
document.removeEventListener("backbutton", handleBackButton, false);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function handleBackButton(event) {
|
||||
function handleBackButton(event) {
|
||||
axe.debug(DEBUG_TAG, 'back button pressed');
|
||||
|
||||
// this disarms the default behavior which we NEVER want
|
||||
|
@ -51,7 +50,6 @@ define(function(require) {
|
|||
// exits the app
|
||||
navigator.app.exitApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return backBtnHandler;
|
||||
});
|
||||
module.exports = backBtnHandler;
|
|
@ -1,41 +1,42 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var TCPSocket = require('tcp-socket'),
|
||||
appConfig = require('js/app-config'),
|
||||
var TCPSocket = require('tcp-socket'),
|
||||
appConfig = require('../app-config'),
|
||||
cfg = appConfig.config,
|
||||
strings = appConfig.string,
|
||||
ImapClient = require('imap-client'),
|
||||
SmtpClient = require('smtpclient');
|
||||
SmtpClient = require('wo-smtpclient');
|
||||
|
||||
/**
|
||||
/**
|
||||
* The connection doctor can check your connection. In essence, it reconstructs what happens when
|
||||
* the app goes online in an abbreviated way. You need to configure() the instance with the IMAP/SMTP
|
||||
* credentials before running check()!
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
var ConnectionDoctor = function() {};
|
||||
var ConnectionDoctor = function() {};
|
||||
|
||||
|
||||
//
|
||||
// Error codes
|
||||
//
|
||||
//
|
||||
// Error codes
|
||||
//
|
||||
|
||||
var OFFLINE = ConnectionDoctor.OFFLINE = 42;
|
||||
var TLS_WRONG_CERT = ConnectionDoctor.TLS_WRONG_CERT = 43;
|
||||
var HOST_UNREACHABLE = ConnectionDoctor.HOST_UNREACHABLE = 44;
|
||||
var HOST_TIMEOUT = ConnectionDoctor.HOST_TIMEOUT = 45;
|
||||
var AUTH_REJECTED = ConnectionDoctor.AUTH_REJECTED = 46;
|
||||
var NO_INBOX = ConnectionDoctor.NO_INBOX = 47;
|
||||
var GENERIC_ERROR = ConnectionDoctor.GENERIC_ERROR = 48;
|
||||
var OFFLINE = ConnectionDoctor.OFFLINE = 42;
|
||||
var TLS_WRONG_CERT = ConnectionDoctor.TLS_WRONG_CERT = 43;
|
||||
var HOST_UNREACHABLE = ConnectionDoctor.HOST_UNREACHABLE = 44;
|
||||
var HOST_TIMEOUT = ConnectionDoctor.HOST_TIMEOUT = 45;
|
||||
var AUTH_REJECTED = ConnectionDoctor.AUTH_REJECTED = 46;
|
||||
var NO_INBOX = ConnectionDoctor.NO_INBOX = 47;
|
||||
var GENERIC_ERROR = ConnectionDoctor.GENERIC_ERROR = 48;
|
||||
|
||||
|
||||
//
|
||||
// Public API
|
||||
//
|
||||
var WORKER_PATH = cfg.workerPath + '/tcp-socket-tls-worker.min.js';
|
||||
|
||||
/**
|
||||
//
|
||||
// Public API
|
||||
//
|
||||
|
||||
/**
|
||||
* Configures the connection doctor
|
||||
*
|
||||
* @param {Object} credentials.imap IMAP configuration (host:string, port:number, secure:boolean, ignoreTLS:boolean)
|
||||
|
@ -43,7 +44,7 @@ define(function(require) {
|
|||
* @param {String} credentials.username
|
||||
* @param {String} credentials.password
|
||||
*/
|
||||
ConnectionDoctor.prototype.configure = function(credentials) {
|
||||
ConnectionDoctor.prototype.configure = function(credentials) {
|
||||
this.credentials = credentials;
|
||||
|
||||
// internal members
|
||||
|
@ -53,6 +54,7 @@ define(function(require) {
|
|||
secure: this.credentials.imap.secure,
|
||||
ignoreTLS: this.credentials.imap.ignoreTLS,
|
||||
ca: this.credentials.imap.ca,
|
||||
tlsWorkerPath: WORKER_PATH,
|
||||
auth: {
|
||||
user: this.credentials.username,
|
||||
pass: this.credentials.password,
|
||||
|
@ -64,15 +66,16 @@ define(function(require) {
|
|||
useSecureTransport: this.credentials.smtp.secure,
|
||||
ignoreTLS: this.credentials.smtp.ignoreTLS,
|
||||
ca: this.credentials.smtp.ca,
|
||||
tlsWorkerPath: WORKER_PATH,
|
||||
auth: {
|
||||
user: this.credentials.username,
|
||||
pass: this.credentials.password,
|
||||
xoauth2: this.credentials.xoauth2
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* It conducts the following tests for IMAP and SMTP, respectively:
|
||||
* 1) Check if browser is online
|
||||
* 2) Connect to host:port via TCP/TLS
|
||||
|
@ -82,7 +85,7 @@ define(function(require) {
|
|||
*
|
||||
* @param {Function} callback(error) Invoked when the test suite passed, or with an error object if something went wrong
|
||||
*/
|
||||
ConnectionDoctor.prototype.check = function(callback) {
|
||||
ConnectionDoctor.prototype.check = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (!self.credentials) {
|
||||
|
@ -114,27 +117,27 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Internal API
|
||||
//
|
||||
//
|
||||
// Internal API
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks if the browser is online
|
||||
*
|
||||
* @param {Function} callback(error) Invoked when the test suite passed, or with an error object if browser is offline
|
||||
*/
|
||||
ConnectionDoctor.prototype._checkOnline = function(callback) {
|
||||
ConnectionDoctor.prototype._checkOnline = function(callback) {
|
||||
if (navigator.onLine) {
|
||||
callback();
|
||||
} else {
|
||||
callback(createError(OFFLINE, strings.connDocOffline));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks if a host is reachable via TCP
|
||||
*
|
||||
* @param {String} options.host
|
||||
|
@ -142,7 +145,7 @@ define(function(require) {
|
|||
* @param {Boolean} options.secure
|
||||
* @param {Function} callback(error) Invoked when the test suite passed, or with an error object if something went wrong
|
||||
*/
|
||||
ConnectionDoctor.prototype._checkReachable = function(options, callback) {
|
||||
ConnectionDoctor.prototype._checkReachable = function(options, callback) {
|
||||
var socket,
|
||||
error, // remember the error message
|
||||
timeout, // remember the timeout object
|
||||
|
@ -157,7 +160,8 @@ define(function(require) {
|
|||
socket = TCPSocket.open(options.host, options.port, {
|
||||
binaryType: 'arraybuffer',
|
||||
useSecureTransport: options.secure,
|
||||
ca: options.ca
|
||||
ca: options.ca,
|
||||
tlsWorkerPath: WORKER_PATH
|
||||
});
|
||||
|
||||
socket.ondata = function() {}; // we don't actually care about the data
|
||||
|
@ -191,15 +195,15 @@ define(function(require) {
|
|||
callback(error);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks if an IMAP server is reachable, accepts the credentials, can list folders and has an inbox and logs out.
|
||||
* Adds the certificate to the IMAP settings if not provided.
|
||||
*
|
||||
* @param {Function} callback(error) Invoked when the test suite passed, or with an error object if something went wrong
|
||||
*/
|
||||
ConnectionDoctor.prototype._checkImap = function(callback) {
|
||||
ConnectionDoctor.prototype._checkImap = function(callback) {
|
||||
var self = this,
|
||||
loggedIn = false,
|
||||
host = self.credentials.imap.host + ':' + self.credentials.imap.port;
|
||||
|
@ -239,15 +243,15 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Checks if an SMTP server is reachable and accepts the credentials and logs out.
|
||||
* Adds the certificate to the SMTP settings if not provided.
|
||||
*
|
||||
* @param {Function} callback(error) Invoked when the test suite passed, or with an error object if something went wrong
|
||||
*/
|
||||
ConnectionDoctor.prototype._checkSmtp = function(callback) {
|
||||
ConnectionDoctor.prototype._checkSmtp = function(callback) {
|
||||
var self = this,
|
||||
host = self.credentials.smtp.host + ':' + self.credentials.smtp.port,
|
||||
errored = false; // tracks if we need to invoke the callback at onclose or not
|
||||
|
@ -276,20 +280,19 @@ define(function(require) {
|
|||
};
|
||||
|
||||
self._smtp.connect();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Helper Functions
|
||||
//
|
||||
//
|
||||
// Helper Functions
|
||||
//
|
||||
|
||||
function createError(code, message, underlyingError) {
|
||||
function createError(code, message, underlyingError) {
|
||||
var error = new Error(message);
|
||||
error.code = code;
|
||||
error.underlyingError = underlyingError;
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
return ConnectionDoctor;
|
||||
});
|
||||
module.exports = ConnectionDoctor;
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var util = require('js/crypto/util');
|
||||
var util = require('crypto-lib').util;
|
||||
|
||||
var dl = {};
|
||||
var dl = {};
|
||||
|
||||
dl.createDownload = function(options) {
|
||||
dl.createDownload = function(options) {
|
||||
var contentType = options.contentType || 'application/octet-stream';
|
||||
var filename = options.filename || 'file';
|
||||
var content = options.content;
|
||||
|
@ -54,7 +53,6 @@ define(function(require) {
|
|||
}
|
||||
window.open('data:' + contentType + ';base64,' + btoa(content), "_blank");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return dl;
|
||||
});
|
||||
module.exports = dl;
|
|
@ -1,10 +1,9 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var axe = require('axe');
|
||||
var axe = require('axe-logger');
|
||||
|
||||
var er = {};
|
||||
er.attachHandler = function(scope) {
|
||||
var er = {};
|
||||
er.attachHandler = function(scope) {
|
||||
scope.onError = function(options) {
|
||||
if (!options) {
|
||||
scope.$apply();
|
||||
|
@ -29,7 +28,6 @@ define(function(require) {
|
|||
scope.$apply();
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return er;
|
||||
});
|
||||
module.exports = er;
|
|
@ -1,15 +1,14 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var cfg = require('js/app-config').config;
|
||||
var cfg = require('../app-config').config;
|
||||
|
||||
var self = {};
|
||||
var notif = {};
|
||||
|
||||
if (window.Notification) {
|
||||
self.hasPermission = Notification.permission === "granted";
|
||||
}
|
||||
if (window.Notification) {
|
||||
notif.hasPermission = Notification.permission === "granted";
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Creates a notification. Requests permission if not already granted
|
||||
*
|
||||
* @param {String} options.title The notification title
|
||||
|
@ -18,18 +17,18 @@ define(function(require) {
|
|||
* @param {Function} options.onClick (optional) callback when the notification is clicked
|
||||
* @returns {Notification} A notification instance
|
||||
*/
|
||||
self.create = function(options) {
|
||||
notif.create = function(options) {
|
||||
options.onClick = options.onClick || function() {};
|
||||
|
||||
if (!window.Notification) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.hasPermission) {
|
||||
if (!notif.hasPermission) {
|
||||
// don't wait until callback returns
|
||||
Notification.requestPermission(function(permission) {
|
||||
if (permission === "granted") {
|
||||
self.hasPermission = true;
|
||||
notif.hasPermission = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -50,11 +49,10 @@ define(function(require) {
|
|||
}
|
||||
|
||||
return notification;
|
||||
};
|
||||
};
|
||||
|
||||
self.close = function(notification) {
|
||||
notif.close = function(notification) {
|
||||
notification.close();
|
||||
};
|
||||
};
|
||||
|
||||
return self;
|
||||
});
|
||||
module.exports = notif;
|
|
@ -1,23 +1,22 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var OAuth = function(googleApi) {
|
||||
var OAuth = function(googleApi) {
|
||||
this._googleApi = googleApi;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check if chrome.identity api is supported
|
||||
* @return {Boolean} If is supported
|
||||
*/
|
||||
OAuth.prototype.isSupported = function() {
|
||||
OAuth.prototype.isSupported = function() {
|
||||
return !!(window.chrome && chrome.identity);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Request an OAuth token from chrome for gmail users
|
||||
* @param {String} emailAddress The user's email address (optional)
|
||||
*/
|
||||
OAuth.prototype.getOAuthToken = function(emailAddress, callback) {
|
||||
OAuth.prototype.getOAuthToken = function(emailAddress, callback) {
|
||||
var idOptions = {
|
||||
interactive: true
|
||||
};
|
||||
|
@ -46,14 +45,14 @@ define(function() {
|
|||
callback(null, token);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Remove an old OAuth token and get a new one.
|
||||
* @param {String} options.oldToken The old token to be removed
|
||||
* @param {String} options.emailAddress The user's email address (optional)
|
||||
*/
|
||||
OAuth.prototype.refreshToken = function(options, callback) {
|
||||
OAuth.prototype.refreshToken = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
if (!options.oldToken) {
|
||||
|
@ -68,13 +67,13 @@ define(function() {
|
|||
// get a new token
|
||||
self.getOAuthToken(options.emailAddress, callback);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get email address from google api
|
||||
* @param {String} token The oauth token
|
||||
*/
|
||||
OAuth.prototype.queryEmailAddress = function(token, callback) {
|
||||
OAuth.prototype.queryEmailAddress = function(token, callback) {
|
||||
if (!token) {
|
||||
callback({
|
||||
errMsg: 'Invalid OAuth token!'
|
||||
|
@ -95,7 +94,6 @@ define(function() {
|
|||
|
||||
callback(null, info.email);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return OAuth;
|
||||
});
|
||||
module.exports = OAuth;
|
|
@ -1,29 +1,28 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var axe = require('axe'),
|
||||
cfg = require('js/app-config').config,
|
||||
updateV1 = require('js/util/update/update-v1'),
|
||||
updateV2 = require('js/util/update/update-v2'),
|
||||
updateV3 = require('js/util/update/update-v3'),
|
||||
updateV4 = require('js/util/update/update-v4'),
|
||||
updateV5 = require('js/util/update/update-v5');
|
||||
var axe = require('axe-logger'),
|
||||
cfg = require('../../app-config').config,
|
||||
updateV1 = require('./update-v1'),
|
||||
updateV2 = require('./update-v2'),
|
||||
updateV3 = require('./update-v3'),
|
||||
updateV4 = require('./update-v4'),
|
||||
updateV5 = require('./update-v5');
|
||||
|
||||
/**
|
||||
/**
|
||||
* Handles database migration
|
||||
*/
|
||||
var UpdateHandler = function(appConfigStorage, userStorage, auth) {
|
||||
var UpdateHandler = function(appConfigStorage, userStorage, auth) {
|
||||
this._appConfigStorage = appConfigStorage;
|
||||
this._userStorage = userStorage;
|
||||
this._updateScripts = [updateV1, updateV2, updateV3, updateV4, updateV5];
|
||||
this._auth = auth;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Executes all the necessary updates
|
||||
* @param {Function} callback(error) Invoked when all the database updates were executed, or if an error occurred
|
||||
*/
|
||||
UpdateHandler.prototype.update = function(callback) {
|
||||
UpdateHandler.prototype.update = function(callback) {
|
||||
var self = this,
|
||||
currentVersion = 0,
|
||||
targetVersion = cfg.dbVersion,
|
||||
|
@ -45,12 +44,12 @@ define(function(require) {
|
|||
targetVersion: targetVersion
|
||||
}, callback);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Schedules necessary updates and executes thom in order
|
||||
*/
|
||||
UpdateHandler.prototype._applyUpdate = function(options, callback) {
|
||||
UpdateHandler.prototype._applyUpdate = function(options, callback) {
|
||||
var self = this,
|
||||
scriptOptions,
|
||||
queue = [];
|
||||
|
@ -91,12 +90,12 @@ define(function(require) {
|
|||
}
|
||||
|
||||
executeNextUpdate();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check application version and update correspondingly
|
||||
*/
|
||||
UpdateHandler.prototype.checkForUpdate = function(dialog) {
|
||||
UpdateHandler.prototype.checkForUpdate = function(dialog) {
|
||||
// Chrome Packaged App
|
||||
if (typeof window.chrome !== 'undefined' && chrome.runtime && chrome.runtime.onUpdateAvailable) {
|
||||
// check for Chrome app update and restart
|
||||
|
@ -126,7 +125,6 @@ define(function(require) {
|
|||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return UpdateHandler;
|
||||
});
|
||||
module.exports = UpdateHandler;
|
|
@ -1,14 +1,13 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
/**
|
||||
* Update handler for transition database version 0 -> 1
|
||||
*
|
||||
* In database version 1, the stored email objects have to be purged, otherwise
|
||||
* every non-prefixed mail in the IMAP folders would be nuked due to the implementation
|
||||
* of the delta sync.
|
||||
*/
|
||||
function updateV1(options, callback) {
|
||||
function updateV1(options, callback) {
|
||||
var emailDbType = 'email_',
|
||||
versionDbType = 'dbVersion',
|
||||
postUpdateDbVersion = 1;
|
||||
|
@ -23,7 +22,6 @@ define(function() {
|
|||
// update the database version to postUpdateDbVersion
|
||||
options.appConfigStorage.storeList([postUpdateDbVersion], versionDbType, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return updateV1;
|
||||
});
|
||||
module.exports = updateV1;
|
|
@ -1,13 +1,12 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
/**
|
||||
* Update handler for transition database version 1 -> 2
|
||||
*
|
||||
* In database version 2, the stored email objects have to be purged, because the
|
||||
* new data model stores information about the email structure in the property 'bodyParts'.
|
||||
*/
|
||||
function updateV2(options, callback) {
|
||||
function updateV2(options, callback) {
|
||||
var emailDbType = 'email_',
|
||||
versionDbType = 'dbVersion',
|
||||
postUpdateDbVersion = 2;
|
||||
|
@ -22,7 +21,6 @@ define(function() {
|
|||
// update the database version to postUpdateDbVersion
|
||||
options.appConfigStorage.storeList([postUpdateDbVersion], versionDbType, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return updateV2;
|
||||
});
|
||||
module.exports = updateV2;
|
|
@ -1,13 +1,12 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
/**
|
||||
* Update handler for transition database version 2 -> 3
|
||||
*
|
||||
* In database version 3, we introduced new flags to the messages, also
|
||||
* the outbox uses artificial uids
|
||||
*/
|
||||
function update(options, callback) {
|
||||
function update(options, callback) {
|
||||
var emailDbType = 'email_',
|
||||
versionDbType = 'dbVersion',
|
||||
postUpdateDbVersion = 3;
|
||||
|
@ -22,7 +21,6 @@ define(function() {
|
|||
// update the database version to postUpdateDbVersion
|
||||
options.appConfigStorage.storeList([postUpdateDbVersion], versionDbType, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return update;
|
||||
});
|
||||
module.exports = update;
|
|
@ -1,17 +1,16 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var config = require('js/app-config').config;
|
||||
var config = require('../../app-config').config;
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Update handler for transition database version 3 -> 4
|
||||
*
|
||||
* In database version 4, we need to add a "provider" flag to the
|
||||
* indexeddb. only gmail was allowed as a mail service provider before,
|
||||
* so let's add this...
|
||||
*/
|
||||
function update(options, callback) {
|
||||
function update(options, callback) {
|
||||
var VERSION_DB_TYPE = 'dbVersion',
|
||||
EMAIL_ADDR_DB_KEY = 'emailaddress',
|
||||
USERNAME_DB_KEY = 'username',
|
||||
|
@ -99,7 +98,6 @@ define(function(require) {
|
|||
callback(err, (!err && cachedItems && cachedItems[0]));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return update;
|
||||
});
|
||||
module.exports = update;
|
|
@ -1,23 +1,22 @@
|
|||
define(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var FOLDER_TYPE_INBOX = 'Inbox';
|
||||
var FOLDER_TYPE_SENT = 'Sent';
|
||||
var FOLDER_TYPE_DRAFTS = 'Drafts';
|
||||
var FOLDER_TYPE_TRASH = 'Trash';
|
||||
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 FOLDER_DB_TYPE = 'folders';
|
||||
var VERSION_DB_TYPE = 'dbVersion';
|
||||
|
||||
var POST_UPDATE_DB_VERSION = 5;
|
||||
var POST_UPDATE_DB_VERSION = 5;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Update handler for transition database version 4 -> 5
|
||||
*
|
||||
* Due to an overlooked issue, there may be multiple folders, e.g. for sent mails.
|
||||
* This removes the "duplicate" folders.
|
||||
*/
|
||||
function update(options, callback) {
|
||||
function update(options, callback) {
|
||||
|
||||
// remove the emails
|
||||
options.userStorage.listItems(FOLDER_DB_TYPE, 0, null, function(err, stored) {
|
||||
|
@ -50,7 +49,6 @@ define(function() {
|
|||
options.appConfigStorage.storeList([POST_UPDATE_DB_VERSION], VERSION_DB_TYPE, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return update;
|
||||
});
|
||||
module.exports = update;
|
File diff suppressed because one or more lines are too long
|
@ -1,245 +0,0 @@
|
|||
// uuid.js
|
||||
//
|
||||
// (c) 2010-2012 Robert Kieffer
|
||||
// MIT License
|
||||
// https://github.com/broofa/node-uuid
|
||||
(function() {
|
||||
var _global = this;
|
||||
|
||||
// Unique ID creation requires a high quality random # generator. We feature
|
||||
// detect to determine the best RNG source, normalizing to a function that
|
||||
// returns 128-bits of randomness, since that's what's usually required
|
||||
var _rng;
|
||||
|
||||
// Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
|
||||
//
|
||||
// Moderately fast, high quality
|
||||
if (typeof(require) == 'function') {
|
||||
try {
|
||||
var _rb = require('crypto').randomBytes;
|
||||
_rng = _rb && function() {return _rb(16);};
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
if (!_rng && _global.crypto && crypto.getRandomValues) {
|
||||
// WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
|
||||
//
|
||||
// Moderately fast, high quality
|
||||
var _rnds8 = new Uint8Array(16);
|
||||
_rng = function whatwgRNG() {
|
||||
crypto.getRandomValues(_rnds8);
|
||||
return _rnds8;
|
||||
};
|
||||
}
|
||||
|
||||
if (!_rng) {
|
||||
// Math.random()-based (RNG)
|
||||
//
|
||||
// If all else fails, use Math.random(). It's fast, but is of unspecified
|
||||
// quality.
|
||||
var _rnds = new Array(16);
|
||||
_rng = function() {
|
||||
for (var i = 0, r; i < 16; i++) {
|
||||
if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
|
||||
_rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
|
||||
}
|
||||
|
||||
return _rnds;
|
||||
};
|
||||
}
|
||||
|
||||
// Buffer class to use
|
||||
var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array;
|
||||
|
||||
// Maps for number <-> hex string conversion
|
||||
var _byteToHex = [];
|
||||
var _hexToByte = {};
|
||||
for (var i = 0; i < 256; i++) {
|
||||
_byteToHex[i] = (i + 0x100).toString(16).substr(1);
|
||||
_hexToByte[_byteToHex[i]] = i;
|
||||
}
|
||||
|
||||
// **`parse()` - Parse a UUID into it's component bytes**
|
||||
function parse(s, buf, offset) {
|
||||
var i = (buf && offset) || 0, ii = 0;
|
||||
|
||||
buf = buf || [];
|
||||
s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
|
||||
if (ii < 16) { // Don't overflow!
|
||||
buf[i + ii++] = _hexToByte[oct];
|
||||
}
|
||||
});
|
||||
|
||||
// Zero out remaining bytes if string was short
|
||||
while (ii < 16) {
|
||||
buf[i + ii++] = 0;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
// **`unparse()` - Convert UUID byte array (ala parse()) into a string**
|
||||
function unparse(buf, offset) {
|
||||
var i = offset || 0, bth = _byteToHex;
|
||||
return bth[buf[i++]] + bth[buf[i++]] +
|
||||
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
||||
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
||||
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
||||
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
||||
bth[buf[i++]] + bth[buf[i++]] +
|
||||
bth[buf[i++]] + bth[buf[i++]] +
|
||||
bth[buf[i++]] + bth[buf[i++]];
|
||||
}
|
||||
|
||||
// **`v1()` - Generate time-based UUID**
|
||||
//
|
||||
// Inspired by https://github.com/LiosK/UUID.js
|
||||
// and http://docs.python.org/library/uuid.html
|
||||
|
||||
// random #'s we need to init node and clockseq
|
||||
var _seedBytes = _rng();
|
||||
|
||||
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
|
||||
var _nodeId = [
|
||||
_seedBytes[0] | 0x01,
|
||||
_seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
|
||||
];
|
||||
|
||||
// Per 4.2.2, randomize (14 bit) clockseq
|
||||
var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
|
||||
|
||||
// Previous uuid creation time
|
||||
var _lastMSecs = 0, _lastNSecs = 0;
|
||||
|
||||
// See https://github.com/broofa/node-uuid for API details
|
||||
function v1(options, buf, offset) {
|
||||
var i = buf && offset || 0;
|
||||
var b = buf || [];
|
||||
|
||||
options = options || {};
|
||||
|
||||
var clockseq = options.clockseq != null ? options.clockseq : _clockseq;
|
||||
|
||||
// UUID timestamps are 100 nano-second units since the Gregorian epoch,
|
||||
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
|
||||
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
|
||||
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
|
||||
var msecs = options.msecs != null ? options.msecs : new Date().getTime();
|
||||
|
||||
// Per 4.2.1.2, use count of uuid's generated during the current clock
|
||||
// cycle to simulate higher resolution clock
|
||||
var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1;
|
||||
|
||||
// Time since last uuid creation (in msecs)
|
||||
var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
|
||||
|
||||
// Per 4.2.1.2, Bump clockseq on clock regression
|
||||
if (dt < 0 && options.clockseq == null) {
|
||||
clockseq = clockseq + 1 & 0x3fff;
|
||||
}
|
||||
|
||||
// Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
|
||||
// time interval
|
||||
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
|
||||
nsecs = 0;
|
||||
}
|
||||
|
||||
// Per 4.2.1.2 Throw error if too many uuids are requested
|
||||
if (nsecs >= 10000) {
|
||||
throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
|
||||
}
|
||||
|
||||
_lastMSecs = msecs;
|
||||
_lastNSecs = nsecs;
|
||||
_clockseq = clockseq;
|
||||
|
||||
// Per 4.1.4 - Convert from unix epoch to Gregorian epoch
|
||||
msecs += 12219292800000;
|
||||
|
||||
// `time_low`
|
||||
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
|
||||
b[i++] = tl >>> 24 & 0xff;
|
||||
b[i++] = tl >>> 16 & 0xff;
|
||||
b[i++] = tl >>> 8 & 0xff;
|
||||
b[i++] = tl & 0xff;
|
||||
|
||||
// `time_mid`
|
||||
var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
|
||||
b[i++] = tmh >>> 8 & 0xff;
|
||||
b[i++] = tmh & 0xff;
|
||||
|
||||
// `time_high_and_version`
|
||||
b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
|
||||
b[i++] = tmh >>> 16 & 0xff;
|
||||
|
||||
// `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
|
||||
b[i++] = clockseq >>> 8 | 0x80;
|
||||
|
||||
// `clock_seq_low`
|
||||
b[i++] = clockseq & 0xff;
|
||||
|
||||
// `node`
|
||||
var node = options.node || _nodeId;
|
||||
for (var n = 0; n < 6; n++) {
|
||||
b[i + n] = node[n];
|
||||
}
|
||||
|
||||
return buf ? buf : unparse(b);
|
||||
}
|
||||
|
||||
// **`v4()` - Generate random UUID**
|
||||
|
||||
// See https://github.com/broofa/node-uuid for API details
|
||||
function v4(options, buf, offset) {
|
||||
// Deprecated - 'format' argument, as supported in v1.2
|
||||
var i = buf && offset || 0;
|
||||
|
||||
if (typeof(options) == 'string') {
|
||||
buf = options == 'binary' ? new BufferClass(16) : null;
|
||||
options = null;
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
var rnds = options.random || (options.rng || _rng)();
|
||||
|
||||
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
||||
rnds[6] = (rnds[6] & 0x0f) | 0x40;
|
||||
rnds[8] = (rnds[8] & 0x3f) | 0x80;
|
||||
|
||||
// Copy bytes to buffer, if provided
|
||||
if (buf) {
|
||||
for (var ii = 0; ii < 16; ii++) {
|
||||
buf[i + ii] = rnds[ii];
|
||||
}
|
||||
}
|
||||
|
||||
return buf || unparse(rnds);
|
||||
}
|
||||
|
||||
// Export public API
|
||||
var uuid = v4;
|
||||
uuid.v1 = v1;
|
||||
uuid.v4 = v4;
|
||||
uuid.parse = parse;
|
||||
uuid.unparse = unparse;
|
||||
uuid.BufferClass = BufferClass;
|
||||
|
||||
if (_global.define && define.amd) {
|
||||
// Publish as AMD module
|
||||
define(function() {return uuid;});
|
||||
} else if (typeof(module) != 'undefined' && module.exports) {
|
||||
// Publish as node.js module
|
||||
module.exports = uuid;
|
||||
} else {
|
||||
// Publish as global (in browsers)
|
||||
var _previousRoot = _global.uuid;
|
||||
|
||||
// **`noConflict()` - (browser only) to reset global 'uuid' var**
|
||||
uuid.noConflict = function() {
|
||||
_global.uuid = _previousRoot;
|
||||
return uuid;
|
||||
};
|
||||
|
||||
_global.uuid = uuid;
|
||||
}
|
||||
}());
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "Whiteout Mail",
|
||||
"version": "0.0.1",
|
||||
"main": "index.html",
|
||||
"window": {
|
||||
"toolbar": false,
|
||||
"width": 1024,
|
||||
"height": 768
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
|
||||
requirejs.config({
|
||||
nodeRequire: (typeof module !== 'undefined' && module.exports) ? require : undefined,
|
||||
baseUrl: 'lib',
|
||||
paths: {
|
||||
js: '../js',
|
||||
test: '../../test',
|
||||
jquery: 'jquery.min',
|
||||
underscore: 'underscore/underscore-min',
|
||||
lawnchair: 'lawnchair/lawnchair-git',
|
||||
lawnchairSQL: 'lawnchair/lawnchair-adapter-webkit-sqlite-git',
|
||||
lawnchairIDB: 'lawnchair/lawnchair-adapter-indexed-db-git',
|
||||
angular: 'angular/angular.min',
|
||||
angularRoute: 'angular/angular-route.min',
|
||||
angularAnimate: 'angular/angular-animate.min',
|
||||
ngInfiniteScroll: 'ng-infinite-scroll.min',
|
||||
ngTagsInput: 'ngtagsinput/ng-tags-input.min',
|
||||
uuid: 'uuid/uuid',
|
||||
forge: 'forge/forge.min',
|
||||
punycode: 'punycode.min',
|
||||
openpgp: 'openpgp/openpgp',
|
||||
fastclick: 'fastclick/fastclick'
|
||||
},
|
||||
shim: {
|
||||
forge: {
|
||||
exports: 'forge'
|
||||
},
|
||||
jquery: {
|
||||
exports: '$'
|
||||
},
|
||||
angular: {
|
||||
exports: 'angular',
|
||||
deps: ['jquery']
|
||||
},
|
||||
angularRoute: {
|
||||
exports: 'angular',
|
||||
deps: ['angular']
|
||||
},
|
||||
angularAnimate: {
|
||||
exports: 'angular',
|
||||
deps: ['angular']
|
||||
},
|
||||
ngInfiniteScroll: {
|
||||
exports: 'angular',
|
||||
deps: ['jquery', 'angular']
|
||||
},
|
||||
ngTagsInput: {
|
||||
exports: 'angular',
|
||||
deps: ['angular']
|
||||
},
|
||||
lawnchair: {
|
||||
exports: 'Lawnchair'
|
||||
},
|
||||
lawnchairSQL: {
|
||||
deps: ['lawnchair']
|
||||
},
|
||||
lawnchairIDB: {
|
||||
deps: ['lawnchair', 'lawnchairSQL']
|
||||
},
|
||||
underscore: {
|
||||
exports: '_'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}());
|
|
@ -5,8 +5,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" media="all" href="../css/read-sandbox.min.css" type="text/css">
|
||||
<script src="../lib/purify.js"></script>
|
||||
<script src="../js/controller/read-sandbox.js"></script>
|
||||
<script src="../js/read-sandbox.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body></body>
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
chrome.app.runtime.onLaunched.addListener(function() {
|
||||
chrome.app.window.create('integration/index.html', {
|
||||
'bounds': {
|
||||
'width': 1024,
|
||||
'height': 768
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,21 +1,18 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var expect = chai.expect,
|
||||
ImapClient = require('imap-client'),
|
||||
var ImapClient = require('imap-client'),
|
||||
BrowserCrow = require('browsercrow'),
|
||||
BrowserSMTP = require('browsersmtp'),
|
||||
SmtpClient = require('smtpclient'),
|
||||
LawnchairDAO = require('js/dao/lawnchair-dao'),
|
||||
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||
appController = require('js/app-controller'),
|
||||
SmtpClient = require('wo-smtpclient'),
|
||||
LawnchairDAO = require('../../src/js/dao/lawnchair-dao'),
|
||||
DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'),
|
||||
appController = require('../../src/js/app-controller'),
|
||||
mailreader = require('mailreader'),
|
||||
openpgp = require('openpgp'),
|
||||
PgpMailer = require('pgpmailer'),
|
||||
config = require('js/app-config').config,
|
||||
str = require('js/app-config').string;
|
||||
config = require('../../src/js/app-config').config,
|
||||
str = require('../../src/js/app-config').string;
|
||||
|
||||
describe('Email DAO integration tests', function() {
|
||||
describe('Email DAO integration tests', function() {
|
||||
this.timeout(100000);
|
||||
chai.Assertion.includeStack = true;
|
||||
|
||||
|
@ -272,6 +269,10 @@ define(function(require) {
|
|||
}, function(err) {
|
||||
expect(err).to.not.exist;
|
||||
|
||||
// stub rest request to key server
|
||||
sinon.stub(appController._emailDao._keychain._publicKeyDao, 'get').yields(null, mockKeyPair.publicKey);
|
||||
sinon.stub(appController._emailDao._keychain._publicKeyDao, 'getByUserId').yields(null, mockKeyPair.publicKey);
|
||||
|
||||
userStorage = appController._userStorage;
|
||||
|
||||
appController.init({
|
||||
|
@ -826,5 +827,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -2,7 +2,7 @@
|
|||
<html style="overflow-y: auto">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JavaScript Unit Tests</title>
|
||||
<title>JavaScript Integration Tests</title>
|
||||
<link rel="stylesheet" href="../lib/mocha.css" />
|
||||
|
||||
</head>
|
||||
|
@ -10,10 +10,24 @@
|
|||
<div id="mocha"></div>
|
||||
|
||||
<script src="../lib/chai.js"></script>
|
||||
<script src="../lib/sinon.js"></script>
|
||||
<script src="../lib/mocha.js"></script>
|
||||
<script src="../lib/sinon.js"></script>
|
||||
|
||||
<script data-main="main.js" src="../lib/require.js"></script>
|
||||
<script>
|
||||
window.expect = chai.expect;
|
||||
mocha.setup('bdd');
|
||||
</script>
|
||||
|
||||
<script src="../lib/openpgp.js"></script>
|
||||
<script src="../lib/forge.min.js"></script>
|
||||
<script src="index.js"></script>
|
||||
|
||||
<script>
|
||||
if (window.mochaPhantomJS) {
|
||||
mochaPhantomJS.run();
|
||||
} else {
|
||||
mocha.run();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,61 +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;
|
||||
};
|
||||
}
|
||||
|
||||
require(['src/require-config'], function() {
|
||||
require.config({
|
||||
baseUrl: 'src/lib',
|
||||
paths: {
|
||||
'browsercrow': '../../../lib/browsercrow',
|
||||
'browsercrow-envelope': '../../../lib/browsercrow-envelope',
|
||||
'browsercrow-bodystructure': '../../../lib/browsercrow-bodystructure',
|
||||
'browsercrow-mimeparser': '../../../lib/browsercrow-mimeparser',
|
||||
'browsersmtp': '../../../lib/browsersmtp'
|
||||
}
|
||||
});
|
||||
|
||||
// Start the main app logic.
|
||||
require(['js/app-config', 'axe'], function(app, axe) {
|
||||
window.Worker = undefined; // disable web workers since mocha doesn't support them
|
||||
|
||||
app.config.workerPath = '../../src/js';
|
||||
//app.config.cloudUrl = 'http://localhost:8888';
|
||||
|
||||
axe.removeAppender(axe.defaultAppender);
|
||||
|
||||
startTests();
|
||||
});
|
||||
});
|
||||
|
||||
function startTests() {
|
||||
mocha.setup('bdd');
|
||||
|
||||
require(
|
||||
[
|
||||
'../../email-dao-test'
|
||||
], function() {
|
||||
//Tests loaded, run tests
|
||||
mocha.run();
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
'use strict';
|
||||
|
||||
//
|
||||
// Polyfills
|
||||
//
|
||||
|
||||
// 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() {
|
||||
if (!window.CustomEvent) {
|
||||
var CustomEvent = function(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;
|
||||
}
|
||||
})();
|
||||
|
||||
// set worker path for tests
|
||||
require('../src/js/app-config').config.workerPath = '../lib';
|
|
@ -1,16 +1,13 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Account Controller unit test', function() {
|
||||
var scope, accountCtrl,
|
||||
dummyFingerprint, expectedFingerprint,
|
||||
dummyKeyId, expectedKeyId,
|
||||
|
@ -97,5 +94,4 @@ define(function(require) {
|
|||
scope.exportKeyFile();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,15 +1,12 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Add Account Controller unit test', function() {
|
||||
var scope, location, ctrl, authStub, origAuth, adminStub;
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -212,5 +209,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,11 +1,9 @@
|
|||
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',
|
||||
|
@ -141,6 +139,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,15 +1,13 @@
|
|||
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() {
|
||||
describe('App Controller unit tests', function() {
|
||||
var emailDaoStub, outboxStub, updateHandlerStub, appConfigStoreStub, devicestorageStub, isOnlineStub, authStub;
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -209,5 +207,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,13 +1,11 @@
|
|||
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() {
|
||||
describe('Auth unit tests', function() {
|
||||
// Constancts
|
||||
var EMAIL_ADDR_DB_KEY = 'emailaddress';
|
||||
var USERNAME_DB_KEY = 'username';
|
||||
|
@ -374,5 +372,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,10 +1,8 @@
|
|||
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() {
|
||||
describe('Backbutton Handler', function() {
|
||||
chai.Assertion.includeStack = true;
|
||||
|
||||
var scope, event;
|
||||
|
@ -63,5 +61,4 @@ define(function(require) {
|
|||
navigator.app.exitApp = done;
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,16 +1,14 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var ConnectionDoctor = require('js/util/connection-doctor'),
|
||||
TCPSocket = require('tcp-socket'),
|
||||
var TCPSocket = require('tcp-socket'),
|
||||
ImapClient = require('imap-client'),
|
||||
SmtpClient = require('smtpclient'),
|
||||
cfg = require('js/app-config').config,
|
||||
expect = chai.expect;
|
||||
SmtpClient = require('wo-smtpclient'),
|
||||
ConnectionDoctor = require('../../src/js/util/connection-doctor'),
|
||||
cfg = require('../../src/js/app-config').config;
|
||||
|
||||
describe('Connection Doctor', function() {
|
||||
describe('Connection Doctor', function() {
|
||||
var doctor;
|
||||
var socketStub, imapStub, smtpStub, credentials;
|
||||
var socketStub, imapStub, smtpStub, credentials, workerPath;
|
||||
|
||||
beforeEach(function() {
|
||||
//
|
||||
|
@ -24,6 +22,7 @@ define(function(require) {
|
|||
}
|
||||
};
|
||||
|
||||
workerPath = 'js/tcp-socket-tls-worker.min.js';
|
||||
imapStub = sinon.createStubInstance(ImapClient);
|
||||
smtpStub = sinon.createStubInstance(SmtpClient);
|
||||
|
||||
|
@ -86,7 +85,8 @@ define(function(require) {
|
|||
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
|
||||
binaryType: 'arraybuffer',
|
||||
useSecureTransport: credentials.imap.secure,
|
||||
ca: credentials.imap.ca
|
||||
ca: credentials.imap.ca,
|
||||
tlsWorkerPath: workerPath
|
||||
})).to.be.true;
|
||||
|
||||
done();
|
||||
|
@ -110,7 +110,8 @@ define(function(require) {
|
|||
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
|
||||
binaryType: 'arraybuffer',
|
||||
useSecureTransport: credentials.imap.secure,
|
||||
ca: credentials.imap.ca
|
||||
ca: credentials.imap.ca,
|
||||
tlsWorkerPath: workerPath
|
||||
})).to.be.true;
|
||||
|
||||
done();
|
||||
|
@ -127,7 +128,8 @@ define(function(require) {
|
|||
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
|
||||
binaryType: 'arraybuffer',
|
||||
useSecureTransport: credentials.imap.secure,
|
||||
ca: credentials.imap.ca
|
||||
ca: credentials.imap.ca,
|
||||
tlsWorkerPath: workerPath
|
||||
})).to.be.true;
|
||||
|
||||
done();
|
||||
|
@ -410,5 +412,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,15 +1,12 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Contacts Controller unit test', function() {
|
||||
var scope, contactsCtrl,
|
||||
origKeychain, keychainMock,
|
||||
origPgp, pgpMock;
|
||||
|
@ -186,5 +183,4 @@ define(function(require) {
|
|||
scope.removeKey(key);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,12 +1,10 @@
|
|||
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() {
|
||||
describe('Crypto unit tests', function() {
|
||||
this.timeout(20000);
|
||||
|
||||
var crypto,
|
||||
|
@ -54,5 +52,4 @@ define(function(require) {
|
|||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,13 +1,11 @@
|
|||
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;
|
||||
|
||||
|
@ -100,6 +98,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,12 +1,9 @@
|
|||
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.mock,
|
||||
DialogCtrl = require('../../src/js/controller/dialog');
|
||||
|
||||
describe('Dialog Controller unit test', function() {
|
||||
describe('Dialog Controller unit test', function() {
|
||||
var scope, dialogCtrl;
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -46,5 +43,4 @@ define(function(require) {
|
|||
scope.confirm(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,19 +1,17 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var EmailDAO = require('js/dao/email-dao'),
|
||||
KeychainDAO = require('js/dao/keychain-dao'),
|
||||
var mailreader = require('mailreader'),
|
||||
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;
|
||||
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() {
|
||||
describe('Email DAO unit tests', function() {
|
||||
// show the stack trace when an error occurred
|
||||
chai.Assertion.includeStack = true;
|
||||
|
||||
|
@ -2300,5 +2298,4 @@ define(function(require) {
|
|||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -10,10 +10,27 @@
|
|||
<div id="mocha"></div>
|
||||
|
||||
<script src="../lib/chai.js"></script>
|
||||
<script src="../lib/sinon.js"></script>
|
||||
<script src="../lib/mocha.js"></script>
|
||||
<script src="../lib/sinon.js"></script>
|
||||
|
||||
<script data-main="main.js" src="../../src/lib/require.js"></script>
|
||||
<script>
|
||||
window.expect = chai.expect;
|
||||
mocha.setup('bdd');
|
||||
</script>
|
||||
|
||||
<script src="../lib/openpgp.js"></script>
|
||||
<script src="../lib/forge.min.js"></script>
|
||||
<script src="index.js"></script>
|
||||
|
||||
<script>
|
||||
mocha.checkLeaks();
|
||||
mocha.globals(['chrome']);
|
||||
|
||||
if (window.mochaPhantomJS) {
|
||||
mochaPhantomJS.run();
|
||||
} else {
|
||||
mocha.run();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
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() {
|
||||
describe('Invitation DAO unit tests', function() {
|
||||
var restDaoStub, invitationDao,
|
||||
alice = 'zuhause@aol.com',
|
||||
bob = 'manfred.mustermann@musterdomain.com',
|
||||
|
@ -104,5 +102,4 @@ define(function(require) {
|
|||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,17 +1,15 @@
|
|||
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;
|
||||
|
||||
|
@ -1381,6 +1379,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,25 +1,23 @@
|
|||
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 = {
|
||||
var key = 'type_1';
|
||||
var data = {
|
||||
name: 'testName1',
|
||||
type: 'testType1'
|
||||
};
|
||||
};
|
||||
|
||||
var key2 = 'type_2';
|
||||
var data2 = {
|
||||
var key2 = 'type_2';
|
||||
var data2 = {
|
||||
name: 'testName2',
|
||||
type: 'testType2'
|
||||
};
|
||||
};
|
||||
|
||||
describe('Lawnchair DAO unit tests', function() {
|
||||
describe('Lawnchair DAO unit tests', function() {
|
||||
var lawnchairDao;
|
||||
|
||||
beforeEach(function(done) {
|
||||
|
@ -147,6 +145,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,16 +1,13 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Login Controller unit test', function() {
|
||||
var scope, location, ctrl,
|
||||
origEmailDao, emailDaoMock,
|
||||
origKeychain, keychainMock,
|
||||
|
@ -234,5 +231,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,16 +1,13 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Login (existing user) Controller unit test', function() {
|
||||
var scope, location, ctrl, origEmailDao, emailDaoMock,
|
||||
origAuth, authMock,
|
||||
emailAddress = 'fred@foo.com',
|
||||
|
@ -113,5 +110,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,16 +1,13 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Login (initial user) Controller unit test', function() {
|
||||
var scope, ctrl, location, origEmailDao, emailDaoMock,
|
||||
origAuth, authMock,
|
||||
emailAddress = 'fred@foo.com',
|
||||
|
@ -197,6 +194,4 @@ define(function(require) {
|
|||
scope.generateKey();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,16 +1,13 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Login (new device) Controller unit test', function() {
|
||||
var scope, ctrl, origEmailDao, emailDaoMock, pgpMock,
|
||||
emailAddress = 'fred@foo.com',
|
||||
passphrase = 'asd',
|
||||
|
@ -186,5 +183,4 @@ define(function(require) {
|
|||
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,16 +1,13 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Login Private Key Download Controller unit test', function() {
|
||||
var scope, location, ctrl,
|
||||
origEmailDao, emailDaoMock,
|
||||
origAuth, authMock,
|
||||
|
@ -260,5 +257,4 @@ define(function(require) {
|
|||
scope.goTo('/desktop');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,15 +1,12 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Login (Set Credentials) Controller unit test', function() {
|
||||
// Angular parameters
|
||||
var scope, location, provider;
|
||||
|
||||
|
@ -97,5 +94,4 @@ define(function(require) {
|
|||
expect(auth.setCredentials.calledOnce).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,19 +1,16 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Mail List controller unit test', function() {
|
||||
var scope, ctrl, origEmailDao, emailDaoMock, keychainMock, deviceStorageMock,
|
||||
emailAddress, emails,
|
||||
hasChrome, hasSocket, hasRuntime, hasIdentity;
|
||||
|
@ -447,5 +444,4 @@ define(function(require) {
|
|||
expect(scope.state.mailList.selected).to.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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();
|
||||
}
|
||||
);
|
||||
}
|
|
@ -1,15 +1,12 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Navigation Controller unit test', function() {
|
||||
var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, outboxFolder, onConnectStub;
|
||||
|
||||
beforeEach(function(done) {
|
||||
|
@ -97,5 +94,4 @@ define(function(require) {
|
|||
expect(outboxFolder.count).to.equal(5);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,11 +1,9 @@
|
|||
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() {
|
||||
describe('OAuth unit tests', function() {
|
||||
var oauth, googleApiStub, identityStub, getPlatformInfoStub, removeCachedStub,
|
||||
testEmail = 'test@example.com';
|
||||
|
||||
|
@ -197,5 +195,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,15 +1,13 @@
|
|||
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() {
|
||||
describe('Outbox Business Object unit test', function() {
|
||||
var outbox, emailDaoStub, devicestorageStub, keychainStub,
|
||||
dummyUser = 'spiderpig@springfield.com';
|
||||
|
||||
|
@ -276,5 +274,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,11 +1,8 @@
|
|||
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() {
|
||||
describe('PGP Crypto Api unit tests', function() {
|
||||
this.timeout(20000);
|
||||
|
||||
var pgp,
|
||||
|
@ -460,5 +457,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,11 +1,9 @@
|
|||
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',
|
||||
|
@ -221,6 +219,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,15 +1,12 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Private Key Upload Controller unit test', function() {
|
||||
var scope, location, ctrl,
|
||||
origEmailDao, emailDaoMock,
|
||||
origKeychain, keychainMock,
|
||||
|
@ -281,6 +278,4 @@ define(function(require) {
|
|||
scope.goForward();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,11 +1,9 @@
|
|||
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;
|
||||
|
||||
|
@ -72,7 +70,7 @@ define(function(require) {
|
|||
|
||||
pubkeyDao.verify(uuid, function(err) {
|
||||
expect(err).to.not.exist;
|
||||
expect(restDaoStub.get.calledWith(sinon.match(function(arg){
|
||||
expect(restDaoStub.get.calledWith(sinon.match(function(arg) {
|
||||
return arg.uri === '/verify/' + uuid && arg.type === 'text';
|
||||
}))).to.be.true;
|
||||
done();
|
||||
|
@ -160,6 +158,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,17 +1,14 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Read Controller unit test', function() {
|
||||
var scope, ctrl,
|
||||
origKeychain, keychainMock,
|
||||
origInvitation, invitationMock,
|
||||
|
@ -193,5 +190,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,10 +1,8 @@
|
|||
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;
|
||||
|
||||
|
@ -220,6 +218,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,15 +1,12 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Set Passphrase Controller unit test', function() {
|
||||
var scope, setPassphraseCtrl,
|
||||
dummyFingerprint, expectedFingerprint,
|
||||
dummyKeyId, expectedKeyId,
|
||||
|
@ -122,5 +119,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,14 +1,12 @@
|
|||
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() {
|
||||
describe('UpdateHandler', function() {
|
||||
var updateHandler, appConfigStorageStub, authStub, userStorageStub, origDbVersion;
|
||||
|
||||
chai.Assertion.includeStack = true;
|
||||
|
@ -470,5 +468,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,16 +1,13 @@
|
|||
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.mock,
|
||||
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() {
|
||||
describe('Write controller unit test', function() {
|
||||
var ctrl, scope,
|
||||
origEmailDao, origOutbox, origKeychain,
|
||||
emailDaoMock, keychainMock, outboxMock, emailAddress, realname;
|
||||
|
@ -397,5 +394,4 @@ define(function(require) {
|
|||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue