otp bugfixes

This commit is contained in:
antelle 2016-04-02 16:20:48 +03:00
parent 8b3e1e4f3c
commit 8252d72598
4 changed files with 85 additions and 14 deletions

View File

@ -6,7 +6,8 @@ var Timeouts = {
AutoHideHint: 3000,
FileChangeSync: 3000,
BeforeAutoLock: 300,
CheckWindowClosed: 300
CheckWindowClosed: 300,
OtpFadeDuration: 10000
};
module.exports = Timeouts;

View File

@ -371,7 +371,6 @@ var EntryModel = Backbone.Model.extend({
},
initOtpGenerator: function() {
this.otpGenerator = null;
var otpUrl;
if (this.fields.otp) {
otpUrl = this.fields.otp;
@ -391,8 +390,7 @@ var EntryModel = Backbone.Model.extend({
(args.size ? '&digits=' + args.size : '');
}
}
}
if (this.fields['TOTP Seed']) {
} else if (this.fields['TOTP Seed']) {
// TrayTOTP plugin format
var key = this.fields['TOTP Seed'];
if (key.isProtected) {
@ -417,17 +415,26 @@ var EntryModel = Backbone.Model.extend({
this.fields.otp = kdbxweb.ProtectedValue.fromString(otpUrl);
}
if (otpUrl) {
if (this.otpGenerator && this.otpGenerator.url === otpUrl) {
return;
}
try {
this.otpGenerator = Otp.parseUrl(otpUrl);
} catch (e) {
this.otpGenerator = null;
}
} else {
this.otpGenerator = null;
}
},
setOtp: function(otp) {
this.otpGenerator = otp;
this.setField('otp', kdbxweb.ProtectedValue.fromString(otp.url));
this.setOtpUrl(otp.url);
},
setOtpUrl: function(url) {
this.setField('otp', kdbxweb.ProtectedValue.fromString(url));
}
});

View File

@ -158,7 +158,7 @@ var DetailsView = Backbone.View.extend({
this.fieldViews.push(new FieldViewHistory({ model: { name: 'History', title: Locale.detHistory,
value: function() { return { length: model.historyLength, unsaved: model.unsaved }; } } }));
_.forEach(model.fields, function(value, field) {
if (field.toLowerCase() === 'otp' && this.model.otpGenerator) {
if (field === 'otp' && this.model.otpGenerator) {
this.fieldViews.push(new FieldViewOtp({ model: { name: '$' + field, title: field,
value: function() { return model.otpGenerator; } } }));
} else {
@ -434,7 +434,12 @@ var DetailsView = Backbone.View.extend({
if (e.field) {
if (e.field[0] === '$') {
var fieldName = e.field.substr(1);
if (e.newField) {
if (fieldName === 'otp') {
if (this.otpFieldChanged(e.val)) {
this.entryUpdated();
return;
}
} else if (e.newField) {
if (fieldName) {
this.model.setField(fieldName, undefined);
}
@ -478,6 +483,18 @@ var DetailsView = Backbone.View.extend({
}
},
otpFieldChanged: function(value) {
var oldValue = this.model.fields.otp;
if (oldValue && oldValue.isProtected) {
oldValue = oldValue.getText();
}
if (oldValue === value) {
return false;
}
this.model.setOtpUrl(value);
return true;
},
fieldCopied: function(e) {
if (this.fieldCopyTip) {
this.fieldCopyTip.hide();

View File

@ -1,15 +1,22 @@
'use strict';
var FieldViewText = require('./field-view-text');
var FieldViewText = require('./field-view-text'),
Timeouts = require('../../const/timeouts');
var MinOpacity = 0.2;
var FieldViewOtp = FieldViewText.extend({
otpTimeout: null,
otpTickInterval: null,
otpValue: null,
otpGenerator: null,
otpTimeLeft: 0,
otpValidUntil: 0,
fieldOpacity: null,
renderValue: function(value) {
this.resetOtpTimer();
if (!value) {
this.resetOtp();
return '';
}
if (value !== this.otpGenerator) {
@ -23,16 +30,29 @@ var FieldViewOtp = FieldViewText.extend({
return value && value.url;
},
render: function() {
FieldViewText.prototype.render.call(this);
this.fieldOpacity = null;
this.otpTick();
},
remove: function() {
this.resetOtpTimer();
this.value = null;
this.otpGenerator = null;
this.resetOtp();
FieldViewText.prototype.remove.apply(this, arguments);
},
resetOtpTimer: function() {
resetOtp: function() {
this.otpGenerator = null;
this.otpValue = null;
this.otpTimeLeft = 0;
this.otpValidUntil = 0;
if (this.otpTimeout) {
clearTimeout(this.otpTimeout);
this.otpTimeout = null;
}
if (this.otpTickInterval) {
clearInterval(this.otpTickInterval);
this.otpTickInterval = null;
}
},
@ -43,14 +63,40 @@ var FieldViewOtp = FieldViewText.extend({
},
otpUpdated: function(pass, timeLeft) {
if (!this.value) {
if (!this.value || !pass) {
this.resetOtp();
return;
}
this.otpValue = pass || '';
this.otpTimeLeft = timeLeft || 0;
this.otpValidUntil = Date.now() + timeLeft;
this.render();
if (this.otpValue && timeLeft) {
this.otpTimeout = setTimeout(this.requestOtpUpdate.bind(this), timeLeft);
if (!this.otpTickInterval) {
this.otpTickInterval = setInterval(this.otpTick.bind(this), 300);
}
}
},
otpTick: function() {
if (!this.value || !this.otpValidUntil) {
return;
}
var opacity;
var timeLeft = this.otpValidUntil - Date.now();
if (timeLeft >= Timeouts.OtpFadeDuration || this.editing) {
opacity = 1;
} else if (timeLeft <= 0) {
opacity = MinOpacity;
} else {
opacity = Math.max(MinOpacity, Math.pow(timeLeft / Timeouts.OtpFadeDuration, 2));
}
if (this.fieldOpacity === opacity) {
return;
}
this.fieldOpacity = opacity;
this.valueEl.css('opacity', opacity);
}
});