diff --git a/.gitignore b/.gitignore
index da695ab..d9c457d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ test/integration/src/
src/lib/*.js
src/js/crypto/aes-gcm.js
src/js/crypto/util.js
+.elasticbeanstalk/
diff --git a/src/js/controller/login-initial.js b/src/js/controller/login-initial.js
index 02c896d..f2e2246 100644
--- a/src/js/controller/login-initial.js
+++ b/src/js/controller/login-initial.js
@@ -9,9 +9,8 @@ define(function(require) {
states = {
IDLE: 1,
- SET_PASSPHRASE: 2,
- PROCESSING: 3,
- DONE: 4
+ PROCESSING: 2,
+ DONE: 3
};
$scope.state.ui = states.IDLE; // initial state
@@ -37,9 +36,9 @@ define(function(require) {
};
/**
- * Continue to set passphrase screen for keygen
+ * Continue to keygen
*/
- $scope.setPassphrase = function() {
+ $scope.generateKey = function() {
if (!$scope.state.agree) {
$scope.onError({
message: termsMsg
@@ -49,8 +48,29 @@ define(function(require) {
// sing up to newsletter
$scope.signUpToNewsletter();
- // go to set passphrase screen
- $scope.setState(states.SET_PASSPHRASE);
+ // go to set keygen screen
+ $scope.setState(states.PROCESSING);
+
+ setTimeout(function() {
+ emailDao.unlock({
+ passphrase: undefined // generate key without passphrase
+ }, function(err) {
+ if (err) {
+ $scope.setState(states.IDLE);
+ $scope.onError(err);
+ return;
+ }
+
+ appController._auth.storeCredentials(function(err) {
+ if (err) {
+ return $scope.onError(err);
+ }
+
+ $location.path('/desktop');
+ $scope.$apply();
+ });
+ });
+ }, 500);
};
/**
@@ -87,86 +107,6 @@ define(function(require) {
xhr.send(formData);
};
- /*
- * Taken from jQuery validate.password plug-in 1.0
- * http://bassistance.de/jquery-plugins/jquery-plugin-validate.password/
- *
- * Copyright (c) 2009 Jörn Zaefferer
- *
- * Licensed under the MIT
- * http://www.opensource.org/licenses/mit-license.php
- */
- $scope.checkPassphraseQuality = function() {
- var passphrase = $scope.state.passphrase;
- $scope.passphraseRating = 0;
-
- var LOWER = /[a-z]/,
- UPPER = /[A-Z]/,
- DIGIT = /[0-9]/,
- DIGITS = /[0-9].*[0-9]/,
- SPECIAL = /[^a-zA-Z0-9]/,
- SAME = /^(.)\1+$/;
-
- function uncapitalize(str) {
- return str.substring(0, 1).toLowerCase() + str.substring(1);
- }
-
- if (!passphrase) {
- // no rating for empty passphrase
- $scope.passphraseMsg = '';
- return;
- }
-
- if (passphrase.length < 8 || SAME.test(passphrase)) {
- $scope.passphraseMsg = 'Very weak';
- return;
- }
-
- var lower = LOWER.test(passphrase),
- upper = UPPER.test(uncapitalize(passphrase)),
- digit = DIGIT.test(passphrase),
- digits = DIGITS.test(passphrase),
- special = SPECIAL.test(passphrase);
-
- if (lower && upper && digit || lower && digits || upper && digits || special) {
- $scope.passphraseMsg = 'Strong';
- $scope.passphraseRating = 3;
- } else if (lower && upper || lower && digit || upper && digit) {
- $scope.passphraseMsg = 'Good';
- $scope.passphraseRating = 2;
- } else {
- $scope.passphraseMsg = 'Weak';
- $scope.passphraseRating = 1;
- }
- };
-
- $scope.confirmPassphrase = function() {
- var passphrase = $scope.state.passphrase;
-
- $scope.setState(states.PROCESSING);
-
- setTimeout(function() {
- emailDao.unlock({
- passphrase: (passphrase) ? passphrase : undefined
- }, function(err) {
- if (err) {
- $scope.setState(states.SET_PASSPHRASE);
- $scope.onError(err);
- return;
- }
-
- appController._auth.storeCredentials(function(err) {
- if (err) {
- return $scope.onError(err);
- }
-
- $location.path('/desktop');
- $scope.$apply();
- });
- });
- }, 500);
- };
-
$scope.setState = function(state) {
$scope.state.ui = state;
};
diff --git a/src/js/controller/set-passphrase.js b/src/js/controller/set-passphrase.js
index 7b1a98b..726c78b 100644
--- a/src/js/controller/set-passphrase.js
+++ b/src/js/controller/set-passphrase.js
@@ -19,6 +19,7 @@ define(function(require) {
$scope.newPassphrase = undefined;
$scope.oldPassphrase = undefined;
$scope.confirmation = undefined;
+ $scope.passphraseMsg = undefined;
}
};
@@ -30,6 +31,59 @@ define(function(require) {
// scope functions
//
+ /*
+ * Taken from jQuery validate.password plug-in 1.0
+ * http://bassistance.de/jquery-plugins/jquery-plugin-validate.password/
+ *
+ * Copyright (c) 2009 Jörn Zaefferer
+ *
+ * Licensed under the MIT
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+ $scope.checkPassphraseQuality = function() {
+ var passphrase = $scope.newPassphrase;
+ $scope.passphraseRating = 0;
+
+ var LOWER = /[a-z]/,
+ UPPER = /[A-Z]/,
+ DIGIT = /[0-9]/,
+ DIGITS = /[0-9].*[0-9]/,
+ SPECIAL = /[^a-zA-Z0-9]/,
+ SAME = /^(.)\1+$/;
+
+ function uncapitalize(str) {
+ return str.substring(0, 1).toLowerCase() + str.substring(1);
+ }
+
+ if (!passphrase) {
+ // no rating for empty passphrase
+ $scope.passphraseMsg = '';
+ return;
+ }
+
+ if (passphrase.length < 8 || SAME.test(passphrase)) {
+ $scope.passphraseMsg = 'Very weak';
+ return;
+ }
+
+ var lower = LOWER.test(passphrase),
+ upper = UPPER.test(uncapitalize(passphrase)),
+ digit = DIGIT.test(passphrase),
+ digits = DIGITS.test(passphrase),
+ special = SPECIAL.test(passphrase);
+
+ if (lower && upper && digit || lower && digits || upper && digits || special) {
+ $scope.passphraseMsg = 'Strong';
+ $scope.passphraseRating = 3;
+ } else if (lower && upper || lower && digit || upper && digit) {
+ $scope.passphraseMsg = 'Good';
+ $scope.passphraseRating = 2;
+ } else {
+ $scope.passphraseMsg = 'Weak';
+ $scope.passphraseRating = 1;
+ }
+ };
+
$scope.setPassphrase = function() {
var keyId = pgp.getKeyParams()._id;
keychain.lookupPrivateKey(keyId, function(err, savedKey) {
diff --git a/src/sass/views/_login.scss b/src/sass/views/_login.scss
index 96c075c..361162a 100644
--- a/src/sass/views/_login.scss
+++ b/src/sass/views/_login.scss
@@ -104,10 +104,6 @@
}
}
- .passphrase-label-ok {
- color: green;
- }
-
.popover-info {
display: none; // hide on mobile
}
@@ -179,7 +175,7 @@
input[type="text"] {
flex: 2;
}
-
+
input[type="number"] {
flex: 1;
margin-right: 0;
diff --git a/src/sass/views/_set-passphrase.scss b/src/sass/views/_set-passphrase.scss
index 33d19a0..d7e5f6f 100644
--- a/src/sass/views/_set-passphrase.scss
+++ b/src/sass/views/_set-passphrase.scss
@@ -1,5 +1,14 @@
.view-set-passphrase {
+ p {
+ margin: 40px auto 0;
+ width: 90%;
+ }
+
+ .passphrase-label-ok {
+ color: green;
+ }
+
.inputs {
margin: 40px 60px 30px;
@@ -9,17 +18,21 @@
}
table {
- margin: 50px auto 60px auto;
-
+ margin: 40px auto 60px auto;
+
td {
- padding-top: 15px;
+ padding-top: 16px;
&:first-child {
text-align: right;
- padding-right: 15px;
+ padding-right: 16px;
font-weight: bold;
}
}
+
+ td.no-padding {
+ padding-top: 0;
+ }
}
}
\ No newline at end of file
diff --git a/src/tpl/login-initial.html b/src/tpl/login-initial.html
index 4d1c7ab..9db88d3 100644
--- a/src/tpl/login-initial.html
+++ b/src/tpl/login-initial.html
@@ -21,28 +21,12 @@
Import existing key
- Generate new key
+ Generate new key
-
Set passphrase. You can set a passphrase to protect your key on disk. This must be entered everytime you start the app. For no passphrase just press continue.
-
-
-
-
-
Generating key. Please stand by. This can take a while...
diff --git a/src/tpl/set-passphrase.html b/src/tpl/set-passphrase.html
index b98582d..34e5cbf 100644
--- a/src/tpl/set-passphrase.html
+++ b/src/tpl/set-passphrase.html
@@ -6,16 +6,21 @@
+
You can set a passphrase to protect your key on disk. This must be entered everytime you start the app.
Current passphrase
-
+
- New passphrase
-
+
+ {{passphraseMsg}}
+
+
+ New passphrase
+
Confirm passphrase
diff --git a/test/unit/login-initial-ctrl-test.js b/test/unit/login-initial-ctrl-test.js
index 4e0d70d..b6c6a87 100644
--- a/test/unit/login-initial-ctrl-test.js
+++ b/test/unit/login-initial-ctrl-test.js
@@ -14,7 +14,6 @@ define(function(require) {
var scope, ctrl, location, origEmailDao, emailDaoMock,
origAuth, authMock,
emailAddress = 'fred@foo.com',
- passphrase = 'asd',
keyId, expectedKeyId,
cryptoMock;
@@ -57,7 +56,6 @@ define(function(require) {
describe('initial state', function() {
it('should be well defined', function() {
- expect(scope.confirmPassphrase).to.exist;
expect(scope.state.ui).to.equal(1);
});
});
@@ -139,49 +137,7 @@ define(function(require) {
});
});
- describe('check passphrase quality', function() {
- it('should be too short', function() {
- scope.state.passphrase = '&§DG36';
- scope.checkPassphraseQuality();
-
- expect(scope.passphraseMsg).to.equal('Very weak');
- expect(scope.passphraseRating).to.equal(0);
- });
-
- it('should be very weak', function() {
- scope.state.passphrase = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
- scope.checkPassphraseQuality();
-
- expect(scope.passphraseMsg).to.equal('Very weak');
- expect(scope.passphraseRating).to.equal(0);
- });
-
- it('should be weak', function() {
- scope.state.passphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf';
- scope.checkPassphraseQuality();
-
- expect(scope.passphraseMsg).to.equal('Weak');
- expect(scope.passphraseRating).to.equal(1);
- });
-
- it('should be good', function() {
- scope.state.passphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf5';
- scope.checkPassphraseQuality();
-
- expect(scope.passphraseMsg).to.equal('Good');
- expect(scope.passphraseRating).to.equal(2);
- });
-
- it('should be strong', function() {
- scope.state.passphrase = '&§DG36abcd';
- scope.checkPassphraseQuality();
-
- expect(scope.passphraseMsg).to.equal('Strong');
- expect(scope.passphraseRating).to.equal(3);
- });
- });
-
- describe('setPassphrase', function() {
+ describe('generate key', function() {
var signUpToNewsletterStub;
beforeEach(function() {
signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter');
@@ -195,79 +151,49 @@ define(function(require) {
scope.onError = function(err) {
expect(err.message).to.contain('Terms');
+ expect(scope.state.ui).to.equal(1);
expect(signUpToNewsletterStub.called).to.be.false;
done();
};
- scope.setPassphrase();
+ scope.generateKey();
});
- it('should continue', function(done) {
+ it('should fail due to error in emailDao.unlock', function(done) {
scope.state.agree = true;
- var setStateStub = sinon.stub(scope, 'setState', function(state) {
- expect(setStateStub.calledOnce).to.be.true;
- expect(signUpToNewsletterStub.calledOnce).to.be.true;
- expect(state).to.equal(2);
+ emailDaoMock.unlock.withArgs({
+ passphrase: undefined
+ }).yields(new Error());
+ authMock.storeCredentials.yields();
+
+ scope.onError = function(err) {
+ expect(err).to.exist;
+ expect(scope.state.ui).to.equal(1);
+ expect(signUpToNewsletterStub.called).to.be.true;
done();
- });
+ };
- scope.setPassphrase();
+ scope.generateKey();
+ expect(scope.state.ui).to.equal(2);
});
- });
-
- describe('confirm passphrase', function() {
- var setStateStub;
it('should unlock crypto', function(done) {
- scope.state.passphrase = passphrase;
- scope.state.confirmation = passphrase;
+ scope.state.agree = true;
emailDaoMock.unlock.withArgs({
- passphrase: passphrase
+ passphrase: undefined
}).yields();
authMock.storeCredentials.yields();
scope.$apply = function() {
+ expect(scope.state.ui).to.equal(2);
expect(location.$$path).to.equal('/desktop');
expect(emailDaoMock.unlock.calledOnce).to.be.true;
done();
};
- scope.confirmPassphrase();
- });
-
- it('should not do anything matching passphrases', function() {
- scope.state.passphrase = 'a';
- scope.state.confirmation = 'b';
-
- scope.confirmPassphrase();
- });
-
- it('should not work when keypair generation fails', function(done) {
- scope.state.passphrase = passphrase;
- scope.state.confirmation = passphrase;
-
- emailDaoMock.unlock.withArgs({
- passphrase: passphrase
- }).yields(new Error('asd'));
-
- setStateStub = sinon.stub(scope, 'setState', function(state) {
- if (setStateStub.calledOnce) {
- expect(state).to.equal(3);
- } else if (setStateStub.calledTwice) {
- expect(state).to.equal(2);
- expect(emailDaoMock.unlock.calledOnce).to.be.true;
- scope.setState.restore();
- }
- });
-
- scope.onError = function(err) {
- expect(err.message).to.equal('asd');
- done();
- };
-
- scope.confirmPassphrase();
+ scope.generateKey();
});
});
diff --git a/test/unit/set-passphrase-ctrl-test.js b/test/unit/set-passphrase-ctrl-test.js
index 5c4062b..42e0f37 100644
--- a/test/unit/set-passphrase-ctrl-test.js
+++ b/test/unit/set-passphrase-ctrl-test.js
@@ -79,5 +79,48 @@ define(function(require) {
scope.setPassphrase();
});
});
+
+ describe('check passphrase quality', function() {
+ it('should be too short', function() {
+ scope.newPassphrase = '&§DG36';
+ scope.checkPassphraseQuality();
+
+ expect(scope.passphraseMsg).to.equal('Very weak');
+ expect(scope.passphraseRating).to.equal(0);
+ });
+
+ it('should be very weak', function() {
+ scope.newPassphrase = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
+ scope.checkPassphraseQuality();
+
+ expect(scope.passphraseMsg).to.equal('Very weak');
+ expect(scope.passphraseRating).to.equal(0);
+ });
+
+ it('should be weak', function() {
+ scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf';
+ scope.checkPassphraseQuality();
+
+ expect(scope.passphraseMsg).to.equal('Weak');
+ expect(scope.passphraseRating).to.equal(1);
+ });
+
+ it('should be good', function() {
+ scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf5';
+ scope.checkPassphraseQuality();
+
+ expect(scope.passphraseMsg).to.equal('Good');
+ expect(scope.passphraseRating).to.equal(2);
+ });
+
+ it('should be strong', function() {
+ scope.newPassphrase = '&§DG36abcd';
+ scope.checkPassphraseQuality();
+
+ expect(scope.passphraseMsg).to.equal('Strong');
+ expect(scope.passphraseRating).to.equal(3);
+ });
+ });
+
});
});
\ No newline at end of file