mirror of
https://github.com/moparisthebest/mail
synced 2024-11-25 18:32:20 -05:00
Skip setting passphrase in setup
This commit is contained in:
parent
da246d4a03
commit
50f0bf951e
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@ test/integration/src/
|
||||
src/lib/*.js
|
||||
src/js/crypto/aes-gcm.js
|
||||
src/js/crypto/util.js
|
||||
.elasticbeanstalk/
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -21,28 +21,12 @@
|
||||
|
||||
<div>
|
||||
<button wo-touch="importKey()" class="btn btn-alt">Import existing key</button>
|
||||
<button type="submit" wo-touch="setPassphrase()" class="btn"tabindex="3">Generate new key</button>
|
||||
<button type="submit" wo-touch="generateKey()" class="btn"tabindex="3">Generate new key</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div ng-show="state.ui === 2">
|
||||
<p><b>Set passphrase.</b> 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.</p>
|
||||
|
||||
<form>
|
||||
<div>
|
||||
<label class="input-error-message" ng-class="{'passphrase-label-ok': passphraseRating >= 2}">{{passphraseMsg}}</label><br>
|
||||
<input class="input-text" type="password" ng-model="state.passphrase" ng-change="checkPassphraseQuality()" placeholder="Enter passphrase" tabindex="1" focus-me="true">
|
||||
<input class="input-text" type="password" ng-model="state.confirmation" ng-class="{'input-text-error': (state.confirmation || state.passphrase) && state.confirmation !== state.passphrase}" placeholder="Confirm passphrase" tabindex="2">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit" wo-touch="confirmPassphrase()" class="btn" ng-disabled="(state.confirmation || state.passphrase) && state.confirmation !== state.passphrase" tabindex="3">Continue</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div ng-show="state.ui === 3">
|
||||
<p><b>Generating key.</b> Please stand by. This can take a while...</p>
|
||||
<div class="working">
|
||||
<span class="spinner"></span>
|
||||
|
@ -6,16 +6,21 @@
|
||||
|
||||
<div class="content">
|
||||
<div class="dialog view-set-passphrase">
|
||||
<p>You can set a passphrase to protect your key on disk. This must be entered everytime you start the app.</p>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><label>Current passphrase</label></td>
|
||||
<td><input class="input-text" type="password" ng-model="oldPassphrase" ng-change="checkPassphraseQuality()" tabindex="1" focus-me="true"></td>
|
||||
<td><input class="input-text" type="password" ng-model="oldPassphrase" tabindex="1" focus-me="true"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label>New passphrase</label></td>
|
||||
<td><input class="input-text" type="password" ng-model="newPassphrase" ng-change="checkPassphraseQuality()" tabindex="2"></td>
|
||||
<td></td>
|
||||
<td><label class="input-error-message" ng-class="{'passphrase-label-ok': passphraseRating >= 2}">{{passphraseMsg}}</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="no-padding"><label>New passphrase</label></td>
|
||||
<td class="no-padding"><input class="input-text" type="password" ng-model="newPassphrase" ng-change="checkPassphraseQuality()" tabindex="2"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label>Confirm passphrase</label></td>
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user