1
0
mirror of http://git.whoc.org.uk/git/password-manager.git synced 2025-10-25 17:47:34 +02:00

Merged all pending work done on the private repository

This commit is contained in:
Giulio Cesare Solaroli
2015-06-27 19:08:20 +02:00
parent 83b40aea50
commit e02ba2c20c
54 changed files with 4535 additions and 1659 deletions

View File

@@ -120,7 +120,8 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.DirectLogin, Object, {
'setLabelKeepingBackwardCompatibilityWithBeta': function (aValue) {
return Clipperz.Async.callbacks("DirectLogin.setLabelKeepingBackwardCompatibilityWithBeta", [
MochiKit.Base.method(this, 'setIndexDataForKey', 'label', aValue),
MochiKit.Base.method(this, 'setValue', 'label', aValue)
MochiKit.Base.method(this, 'setValue', 'label', aValue),
MochiKit.Base.partial(MochiKit.Async.succeed, this),
], {trace:false});
},
@@ -497,7 +498,8 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.DirectLogin, Object, {
MochiKit.Base.method(this, 'updateFormValuesAfterChangingBookmarkletConfiguration'),
MochiKit.Base.method(this, 'updateBindingsAfterChangingBookmarkletConfiguration'),
MochiKit.Base.noop
// MochiKit.Base.noop
MochiKit.Base.partial(MochiKit.Async.succeed, this),
], {trace:false});
},
@@ -607,6 +609,20 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.DirectLogin, Object, {
], {trace:false});
},
'setBindings': function (someBindings, originalFields) {
var self = this;
return Clipperz.Async.callbacks("DirectLogin.setBindings", [
function () {
return MochiKit.Base.map(function (aBindingInfo) {
return self.bindFormFieldWithLabelToRecordFieldWithLabel(aBindingInfo[0], originalFields[aBindingInfo[1]]['label']);
}, MochiKit.Base.zip(MochiKit.Base.keys(someBindings), MochiKit.Base.values(someBindings)));
},
Clipperz.Async.collectAll,
MochiKit.Base.partial(MochiKit.Async.succeed, this),
], {trace:false});
},
//-------------------------------------------------------------------------
/*
'bindingValues': function () {

View File

@@ -72,7 +72,7 @@ Clipperz.PM.DataModel.EncryptedRemoteObject = function(args) {
//
// getRemoteData
// unpackRemoteData
// getDecryptData [encryptedDataKeypath, encryptedVersionKeypath]
// getDecryptedData [encryptedDataKeypath, encryptedVersionKeypath]
// unpackData
//
//

View File

@@ -31,18 +31,13 @@ if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {};
Clipperz.PM.DataModel.OneTimePassword = function(args) {
args = args || {};
// this._user = args['user'];
this._username = args['username'];
this._passphraseCallback = args['passphraseCallback'];
this._reference = args['reference'] || Clipperz.PM.Crypto.randomKey();
this._password = args['password'];
this._passwordValue = Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(args['password']);
this._creationDate = args['created'] ? Clipperz.PM.Date.parseDateWithUTCFormat(args['created']) : new Date();
this._usageDate = args['used'] ? Clipperz.PM.Date.parseDateWithUTCFormat(args['used']) : null;
this._status = args['status'] || 'ACTIVE'; // 'REQUESTED', 'USED', 'DISABLED'
this._connectionInfo= null;
this._key = null;
this._keyChecksum = null;
this._label = args['label'] || "";
this._usageDate = args['usageDate'] || null; // Usage date is stored when the client is sure that the otp was used
return this;
}
@@ -52,19 +47,35 @@ Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.PM.DataModel.OneTimePassword";
},
/*
//-------------------------------------------------------------------------
'user': function() {
return this._user;
'username': function() {
return this._username;
},
//-------------------------------------------------------------------------
'passphraseCallback': function () {
return this._passphraseCallback;
},
'setPassphraseCallback': function(aPassphraseCallback) {
this._passphraseCallback = aPassphraseCallback;
},
'password': function() {
return this._password;
},
'label': function() {
return this._label;
},
'usageDate': function() {
return this._usageDate;
},
'setUsageDate': function(aDate) {
this._usageDate = aDate;
},
//-------------------------------------------------------------------------
'passwordValue': function() {
@@ -73,12 +84,6 @@ Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
//-------------------------------------------------------------------------
'creationDate': function() {
return this._creationDate;
},
//-------------------------------------------------------------------------
'reference': function() {
return this._reference;
},
@@ -86,51 +91,18 @@ Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
//-------------------------------------------------------------------------
'key': function() {
if (this._key == null) {
this._key = Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(this.user().username(), this.passwordValue());
}
return this._key;
return Clipperz.PM.DataModel.OneTimePassword.computeKeyWithPassword(this.passwordValue());
},
//-------------------------------------------------------------------------
'keyChecksum': function() {
if (this._keyChecksum == null) {
this._keyChecksum = Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(this.user().username(), this.passwordValue());
}
return this._keyChecksum;
},
*/
//-------------------------------------------------------------------------
'status': function() {
return this._status;
},
'setStatus': function(aValue) {
this._status = aValue;
},
//-------------------------------------------------------------------------
/*
'serializedData': function() {
var result;
result = {
'password': this.password(),
'created': this.creationDate() ? Clipperz.PM.Date.formatDateWithUTCFormat(this.creationDate()) : null,
'used': this.usageDate() ? Clipperz.PM.Date.formatDateWithUTCFormat(this.usageDate()) : null,
'status': this.status()
};
return result;
return Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(this.username(), this.passwordValue());
},
//-------------------------------------------------------------------------
'packedPassphrase': function() {
'packedPassphrase': function(aPassphrase) {
var result;
var packedPassphrase;
var encodedPassphrase;
@@ -140,32 +112,29 @@ Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
getRandomBytes = MochiKit.Base.method(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'getRandomBytes');
encodedPassphrase = new Clipperz.ByteArray(this.user().passphrase()).toBase64String();
//Clipperz.logDebug("--- encodedPassphrase.length: " + encodedPassphrase.length);
encodedPassphrase = new Clipperz.ByteArray(aPassphrase).toBase64String();
prefixPadding = getRandomBytes(getRandomBytes(1).byteAtIndex(0)).toBase64String();
//Clipperz.logDebug("--- prefixPadding.length: " + prefixPadding.length);
suffixPadding = getRandomBytes((500 - prefixPadding.length - encodedPassphrase.length) * 6 / 8).toBase64String();
//Clipperz.logDebug("--- suffixPadding.length: " + suffixPadding.length);
//Clipperz.logDebug("--- total.length: " + (prefixPadding.length + encodedPassphrase.length + suffixPadding.length));
packedPassphrase = {
'prefix': prefixPadding,
'passphrase': encodedPassphrase,
'suffix': suffixPadding
};
// result = Clipperz.Base.serializeJSON(packedPassphrase);
result = packedPassphrase;
//Clipperz.logDebug("===== OTP packedPassprase: [" + result.length + "]" + result);
//Clipperz.logDebug("<<< OneTimePassword.packedPassphrase");
return result;
},
//-------------------------------------------------------------------------
'encryptedPackedPassphrase': function() {
return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(this.passwordValue(), this.packedPassphrase())
'encryptedPackedPassphrase': function(aPassphrase) {
return Clipperz.PM.Crypto.deferredEncrypt({
'key': this.passwordValue(),
'value': this.packedPassphrase(aPassphrase),
'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion
})
},
//-------------------------------------------------------------------------
@@ -174,8 +143,6 @@ Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
var deferredResult;
var result;
//Clipperz.logDebug(">>> OneTimePassword.encryptedData");
//Clipperz.logDebug("--- OneTimePassword.encryptedData - id: " + this.reference());
result = {
'reference': this.reference(),
'key': this.key(),
@@ -183,116 +150,26 @@ Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
'data': "",
'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion
}
//Clipperz.logDebug("--- OneTimePassword.encryptedData - 2: " + Clipperz.Base.serializeJSON(result));
deferredResult = new MochiKit.Async.Deferred();
//Clipperz.logDebug("--- OneTimePassword.encryptedData - 3");
//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 1: " + res); return res;});
//# deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion, this.passwordValue(), this.packedPassphrase());
deferredResult = new Clipperz.Async.Deferred("OneTimePassword.encryptedData", {trace: false});
deferredResult.addCallback(this.passphraseCallback());
deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedPackedPassphrase'));
//Clipperz.logDebug("--- OneTimePassword.encryptedData - 4");
//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 2: [" + res.length + "]" + res); return res;});
deferredResult.addCallback(function(aResult, res) {
aResult['data'] = res;
return aResult;
}, result);
//Clipperz.logDebug("--- OneTimePassword.encryptedData - 5");
//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 3: " + Clipperz.Base.serializeJSON(res)); return res;});
deferredResult.callback();
//Clipperz.logDebug("--- OneTimePassword.encryptedData - 6");
return deferredResult;
},
//-------------------------------------------------------------------------
'saveChanges': function() {
var deferredResult;
var result;
//Clipperz.logDebug(">>> OneTimePassword.saveChanges");
result = {};
deferredResult = new MochiKit.Async.Deferred();
deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptUserData');
deferredResult.addCallback(MochiKit.Base.method(this.user(), 'encryptedData'));
deferredResult.addCallback(function(aResult, res) {
aResult['user'] = res;
return aResult;
}, result);
deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptOTPData');
deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedData'));
deferredResult.addCallback(function(aResult, res) {
aResult['oneTimePassword'] = res;
return aResult;
}, result);
deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_sendingData');
//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 1: " + Clipperz.Base.serializeJSON(res)); return res;});
deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'addNewOneTimePassword');
deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_updatingInterface');
//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 2: " + res); return res;});
deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'OTPUpdated');
deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'oneTimePassword_saveChanges_done', null);
//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 2: " + res); return res;});
deferredResult.callback();
//Clipperz.logDebug("<<< OneTimePassword.saveChanges");
return deferredResult;
},
//-------------------------------------------------------------------------
'usageDate': function() {
return this._usageDate;
},
'setUsageDate': function(aValue) {
this._usageDate = aValue;
},
//-------------------------------------------------------------------------
'connectionInfo': function() {
return this._connectionInfo;
},
'setConnectionInfo': function(aValue) {
this._connectionInfo = aValue;
},
//-------------------------------------------------------------------------
'isExpired': function() {
return (this.usageDate() != null);
},
//-------------------------------------------------------------------------
'updateStatusWithValues': function(someValues) {
var result;
result = false;
if (someValues['status'] != this.status()) {
result = true;
}
this.setStatus(someValues['status']);
this.setUsageDate(Clipperz.PM.Date.parseDateWithUTCFormat(someValues['requestDate']));
this.setConnectionInfo(someValues['connection']);
return result;
},
*/
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword = function(anUsername, aPassword) {
Clipperz.PM.DataModel.OneTimePassword.computeKeyWithPassword = function(aPassword) {
return Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aPassword)).toHexString().substring(2);
}
@@ -348,3 +225,32 @@ Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword = function(aPass
};
//#############################################################################
Clipperz.PM.DataModel.OneTimePassword.generateRandomBase32OTPValue = function() {
var randomValue;
var result;
randomValue = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(160/8);
result = randomValue.toBase32String();
result = result.replace(/.{4}\B/g, '$&' + ' ');
result = result.replace(/(.{4} ){2}/g, '$&' + '- ');
return result;
},
//#############################################################################
Clipperz.PM.DataModel.OneTimePassword.createNewOneTimePassword = function(aUsername, aPassphraseCallback) {
var result;
var password;
password = Clipperz.PM.DataModel.OneTimePassword.generateRandomBase32OTPValue();
result = new Clipperz.PM.DataModel.OneTimePassword({
'username': aUsername,
'passphraseCallback': aPassphraseCallback,
'password': password,
'label': ""
});
return result;
}

View File

@@ -175,7 +175,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record.Version.Field, Object, {
deferredResult.addMethod(this, 'actionType');
deferredResult.addCallback(function (aValue) { fieldValues['actionType'] = aValue; });
deferredResult.addMethod(this, 'isHidden');
deferredResult.addCallback(function (aValue) { fieldValues['isHidden'] = aValue; });
deferredResult.addCallback(function (aValue) { fieldValues['hidden'] = aValue; });
deferredResult.addCallback(function () { return fieldValues; });
deferredResult.callback();

View File

@@ -327,16 +327,15 @@ console.log("Record.Version.hasPendingChanges");
deferredResult = new Clipperz.Async.Deferred('Record.Version.export', {trace:false});
deferredResult.addMethod(this,'fields');
deferredResult.addCallback(MochiKit.Base.values);
deferredResult.addCallback(MochiKit.Base.map, function(fieldIn) {
deferredResult.addCallback(MochiKit.Base.map, function (fieldIn) {
return fieldIn.content();
});
deferredResult.addCallback(Clipperz.Async.collectAll);
deferredResult.addCallback(function(listIn) {
// return listIn.reduce(function(result, field) {
return MochiKit.Iter.reduce(function(result, field) {
var ref = field.reference;
var ref = field['reference'];
result[ref] = field;
delete result[ref].reference;
delete result[ref]['reference'];
return result;
}, listIn, {});
});

View File

@@ -170,7 +170,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
},
//............................................................................
'label': function () {
return Clipperz.Async.callbacks("Record.label", [
MochiKit.Base.method(this, 'fullLabel'),
@@ -1128,7 +1128,8 @@ console.log("Record.hasPendingChanges RESULT", result);
Clipperz.Async.collectAll,
MochiKit.Base.method(aRecord, 'directLogins'), MochiKit.Base.values,
//function (aValue) { console.log("-> DirectLogin Values", aValue); return aValue; },
//function (aValue) { console.log("-> SETUP WITH RECORD: DirectLogin Values", aValue); return aValue; },
// TODO: possibly broken implementation of direct login cloning
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addDirectLogin')),
//function (aValue) { console.log("-> DirectLogin Values", aValue); return aValue; },
// Clipperz.Async.collectAll,
@@ -1136,16 +1137,25 @@ console.log("Record.hasPendingChanges RESULT", result);
MochiKit.Base.bind(function () { return this; }, this)
], {trace:false});
},
'directLoginWithJsonData': function (someData) {
var result;
'setUpWithJSON': function(data) {
result = new Clipperz.PM.DataModel.DirectLogin({'record': this});
return result;
},
'setUpWithJSON': function(data, labelPostfix) {
return Clipperz.Async.callbacks("Record.setUpWithJSON", [
// TODO: proper tag handling
MochiKit.Base.method(this,'setLabel',data.label),
MochiKit.Base.method(this,'setNotes',data.data.notes),
MochiKit.Base.method(this,'setLabel', data['label'] + ((labelPostfix) ? labelPostfix : '')),
MochiKit.Base.method(this,'setNotes', data['data']['notes']),
// TODO: check whether fields' order is kept or not
function(){ return MochiKit.Base.values(data.currentVersion.fields); },
MochiKit.Base.partial(MochiKit.Base.map,MochiKit.Base.method(this, 'addField')),
Clipperz.Async.collectAll
MochiKit.Base.partial(MochiKit.Base.values, data['currentVersion']['fields']),
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addField')),
Clipperz.Async.collectAll,
MochiKit.Base.partial(MochiKit.Async.succeed, this),
], {trace:false});
},
@@ -1174,12 +1184,12 @@ console.log("Record.hasPendingChanges RESULT", result);
var label;
var data;
var currentVersion;
var directLogins;
// var directLogins;
var currentVersionObject;
data = {};
currentVersion = {};
directLogins = {};
// directLogins = {};
deferredResult = new Clipperz.Async.Deferred('Record.export', {trace:false});
deferredResult.addMethod(this, 'getCurrentRecordVersion');
deferredResult.addCallback(function(recordVersionIn) { currentVersionObject = recordVersionIn; })
@@ -1211,7 +1221,6 @@ console.log("Record.hasPendingChanges RESULT", result);
__syntaxFix__: "syntax fix"
});
Clipperz.PM.DataModel.Record.defaultCardInfo = {
'_rowObject': MochiKit.Async.succeed,
'_reference': MochiKit.Base.methodcaller('reference'),
@@ -1277,3 +1286,14 @@ Clipperz.PM.DataModel.Record.extractTagsFromFullLabel = function (aLabel) {
return result;
};
Clipperz.PM.DataModel.Record.labelContainsTag = function (aLabel, aTag) {
return MochiKit.Iter.some(
MochiKit.Base.keys(Clipperz.PM.DataModel.Record.extractTagsFromFullLabel(aLabel)),
MochiKit.Base.partial(MochiKit.Base.operator.eq, aTag)
);
}
Clipperz.PM.DataModel.Record.labelContainsArchiveTag = function (aLabel) {
return Clipperz.PM.DataModel.Record.labelContainsTag(aLabel, Clipperz.PM.DataModel.Record.archivedTag);
}

View File

@@ -31,7 +31,13 @@ if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.Data
Clipperz.PM.DataModel.User.Header.OneTimePasswords = function(args) {
Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.constructor.apply(this, arguments);
// TODO: there are still method calls around passing these values: should be cleared...
this._connection = args['connection'];
this._username = args['username'];
this._passphraseCallback = args['retrieveKeyFunction'];
this._oneTimePasswords = null;
this._oneTimePasswordsDetails = null;
return this;
}
@@ -45,55 +51,45 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.OneTimePasswords, Clipper
},
//-------------------------------------------------------------------------
/*
'packData': function (someData) { // ++
var result;
result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.packData.apply(this, arguments);
return result;
'connection': function() {
return this._connection;
},
*/
//-------------------------------------------------------------------------
/*
'packRemoteData': function (someData) {
var result;
result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.packRemoteData.apply(this, arguments);
return result;
'username': function() {
return this._username;
},
*/
//-------------------------------------------------------------------------
/*
'prepareRemoteDataWithKey': function (aKey) {
var result;
result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.prepareRemoteDataWithKey.apply(this, arguments);
return result;
'passphraseCallback': function() {
return this._passphraseCallback;
},
*/
//=========================================================================
'oneTimePasswords': function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.Header.OneTimePasswords.oneTimePasswords", {trace:false});
// TODO: change with transient state
// Also, OTPs created here don't store username, making it impossible to generate the key checksum (shouldn't be used anywhere, but probably the design should be changed)
if (this._oneTimePasswords == null) {
deferredResult.addMethod(this, 'values')
deferredResult.addMethod(this, 'values');
deferredResult.addCallback(MochiKit.Base.bind(function (someData) {
var otpKey;
this._oneTimePasswords = {};
for (otpKey in someData) {
var otp;
var otpParameters;
otpParameters = Clipperz.Base.deepClone(someData[otpKey]);
otpParameters['reference'] = otpKey;
otpParameters['username'] = this.username();
otpParameters['passphraseCallback'] = this.passphraseCallback();
otpParameters['usageDate'] = someData[otpKey]['usageDate'] || null;
otp = new Clipperz.PM.DataModel.OneTimePassword(otpParameters);
this._oneTimePasswords[otpKey] = otp;
}
@@ -109,6 +105,182 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.OneTimePasswords, Clipper
return deferredResult;
},
'oneTimePasswordsDetails': function() {
if (this._oneTimePasswordsDetails) {
return MochiKit.Async.succeed(this._oneTimePasswordsDetails);
} else {
return Clipperz.Async.callbacks("User.oneTimePasswordsDetails", [
MochiKit.Base.method(this.connection(), 'message', 'getOneTimePasswordsDetails'),
MochiKit.Base.bind(function(someData) {
this._oneTimePasswordsDetails = someData;
return someData;
}, this)
], {trace:false});
}
},
//=========================================================================
'getReferenceFromKey': function(aKey) {
return Clipperz.Async.callbacks("User.Header.OneTimePasswords.getReferenceFromKey", [
MochiKit.Base.method(this, 'values'),
function(someValues) {
var result;
var normalizedOTP;
var i;
result = null;
for (i in someValues) {
normalizedOTP = Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(someValues[i]['password']);
if (Clipperz.PM.DataModel.OneTimePassword.computeKeyWithPassword(normalizedOTP) == aKey) {
result = i;
}
}
return result;
}
], {trace:false});
},
//=========================================================================
'createNewOTP': function (aUsername, aPassphraseCallback) {
var newOneTimePassword;
newOneTimePassword = Clipperz.PM.DataModel.OneTimePassword.createNewOneTimePassword(aUsername, aPassphraseCallback);
// TODO: this is deferred --> change everything to deferred
// TestData include 'created' and 'status'
this.setValue(newOneTimePassword.reference(), {
// 'created': newOneTimePassword.creationDate().toString(), // won't work: creation date is no more stored in OTP
'password': newOneTimePassword.password(),
'label': newOneTimePassword.label()
// 'status': newOneTimePassword.status()
});
this._oneTimePasswords = null;
this._oneTimePasswordsDetails = null;
return newOneTimePassword;
},
//.........................................................................
'deleteOTPs': function (aList) {
this._oneTimePasswords = null;
this._oneTimePasswordsDetails = null;
return Clipperz.Async.callbacks("User.Header.OneTimePasswords.deleteOTPs", [
MochiKit.Base.method(this, 'values'),
MochiKit.Base.keys,
MochiKit.Base.bind(function(someKeys) {
var result;
result = [];
MochiKit.Base.map(MochiKit.Base.bind(function(aList, aKey) {
if (aList.indexOf(aKey) >= 0) {
this.removeValue(aKey);
} else {
result.push(aKey);
}
}, this, aList), someKeys);
return result; // Return a list of references of the remaining OTPs, needed for the 'updateOneTimePasswords' message
// Maybe this logic should be moved to another method
}, this),
], {trace:false});
},
//.........................................................................
'changeOTPLabel': function (aReference, aLabel) {
this._oneTimePasswords = null;
return Clipperz.Async.callbacks("User.Header.OneTimePasswords.changeOTPLabel", [
MochiKit.Base.method(this, 'getValue', aReference),
function(aValue) {
aValue['label'] = aLabel;
return aValue;
},
MochiKit.Base.method(this, 'setValue', aReference)
], {trace:false});
},
//.........................................................................
'markOTPAsUsed': function(aKey) {
var reference;
this._oneTimePasswords = null;
return Clipperz.Async.callbacks("User.Header.OneTimePasswords.markOTPAsUsed", [
MochiKit.Base.method(this, 'getReferenceFromKey', aKey),
function(aReference) {
reference = aReference;
return aReference;
},
MochiKit.Base.method(this, 'getValue'),
MochiKit.Base.bind(function(aValue) {
if (aValue) {
aValue['usageDate'] = new Date().toString();
this.setValue(reference, aValue);
}
}, this)
], {trace:false});
},
//=========================================================================
'getEncryptedOTPData': function(aPassphraseCallback) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.Header.OneTimePasswords.getEncryptedOTPData", {trace:false});
deferredResult.collectResults({
'oneTimePasswords': MochiKit.Base.method(this, 'oneTimePasswords'),
'oneTimePasswordsDetails': MochiKit.Base.method(this, 'oneTimePasswordsDetails')
});
deferredResult.addCallback(function (someData) {
var result;
var otpFilteredList;
var i;
var otpList = MochiKit.Base.values(someData['oneTimePasswords']);
otpFilteredList = MochiKit.Base.filter(function (aOTP) {
return (someData['oneTimePasswordsDetails'][aOTP.reference()]
&& someData['oneTimePasswordsDetails'][aOTP.reference()]['status'] == 'ACTIVE'
&& ! someData['oneTimePasswords'][aOTP.reference()].usageDate()
);
}, otpList);
result = MochiKit.Base.map(function (aOTP) {
aOTP.setPassphraseCallback(aPassphraseCallback);
return aOTP.encryptedData();
}, otpFilteredList);
return result;
});
deferredResult.addCallback(Clipperz.Async.collectAll);
deferredResult.addCallback(function (someData) {
var result;
var i;
result = {};
for (i in someData) {
result[someData[i].reference] = someData[i];
}
return result;
});
deferredResult.callback();
return deferredResult;
},
//=========================================================================
__syntaxFix__: "syntax fix"
});

View File

@@ -59,6 +59,8 @@ Clipperz.PM.DataModel.User = function (args) {
'__syntaxFix__': 'syntax fix'
};
this._usedOTP = null;
return this;
}
@@ -80,6 +82,40 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
//-------------------------------------------------------------------------
'setUsedOTP': function(aOTP) {
this._usedOTP = aOTP;
return aOTP;
},
'resetUsedOTP': function(aOTP) {
this._usedOTP = null;
},
'markUsedOTP': function(aOTP) {
var result;
var oneTimePasswordKey;
if (this._usedOTP) {
oneTimePasswordKey = Clipperz.PM.DataModel.OneTimePassword.computeKeyWithPassword(
Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(this._usedOTP)
);
result = Clipperz.Async.callbacks("User.markUsedOTP", [ // NOTE: fired also when passphrase looks exactly like OTP
MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
MochiKit.Base.methodcaller('markOTPAsUsed', oneTimePasswordKey),
MochiKit.Base.method(this,'saveChanges'), // Too 'heavy'?
MochiKit.Base.method(this, 'resetUsedOTP')
], {'trace': false});
} else {
result = MochiKit.Async.succeed();
}
return result;
},
//-------------------------------------------------------------------------
// this.setSubscription(new Clipperz.PM.DataModel.User.Subscription(someServerData['subscription']));
'accountInfo': function () {
return this._accountInfo;
@@ -138,21 +174,17 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
//-------------------------------------------------------------------------
'getPassphrase': function() {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.getPassphrase", {trace:false});
deferredResult.acquireLock(this.deferredLockForSection('passphrase'));
deferredResult.addMethod(this.data(), 'deferredGetOrSet', 'passphrase', this.getPassphraseFunction());
deferredResult.releaseLock(this.deferredLockForSection('passphrase'));
deferredResult.callback();
return deferredResult;
return this._getPassphraseFunction();
},
'getPassphraseFunction': function () {
return this._getPassphraseFunction;
},
'setPassphraseFunction': function(aFunction) {
this._getPassphraseFunction = aFunction;
},
//-------------------------------------------------------------------------
'getCredentials': function () {
@@ -164,26 +196,44 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
//-------------------------------------------------------------------------
'changePassphrase': function (aNewValue) {
return this.updateCredentials(this.username(), aNewValue);
'changePassphrase': function (aNewValueCallback) {
return this.updateCredentials(this.username(), aNewValueCallback);
},
//.........................................................................
'updateCredentials': function (aUsername, aPassphrase) {
'updateCredentials': function (aUsername, aPassphraseCallback) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.updateCredentials", {trace:false});
// deferredResult.addMethod(this, 'getPassphrase');
// deferredResult.setValue('currentPassphrase');
deferredResult.addMethod(this.connection(), 'ping');
deferredResult.addMethod(this, 'setUsername', aUsername)
deferredResult.acquireLock(this.deferredLockForSection('passphrase'));
deferredResult.addMethod(this.data(), 'deferredGetOrSet', 'passphrase', aPassphrase);
deferredResult.releaseLock(this.deferredLockForSection('passphrase'));
// deferredResult.getValue('currentPassphrase');
deferredResult.addMethod(this, 'prepareRemoteDataWithKey', aPassphrase);
deferredResult.addMethod(this.connection(), 'updateCredentials', aUsername, aPassphrase);
deferredResult.collectResults({
'newUsername': MochiKit.Base.partial(MochiKit.Async.succeed, aUsername),
'newPassphrase': aPassphraseCallback,
'user': MochiKit.Base.method(this, 'prepareRemoteDataWithKeyFunction', aPassphraseCallback),
'oneTimePasswords': [
MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
MochiKit.Base.methodcaller('getEncryptedOTPData', aPassphraseCallback),
function (otps) {
var result;
var otpRefs;
var i, c;
result = {};
otpRefs = MochiKit.Base.keys(otps);
c = otpRefs.length;
for (i=0; i<c; i++) {
result[otpRefs[i]] = {}
result[otpRefs[i]]['data'] = otps[otpRefs[i]]['data'];
result[otpRefs[i]]['version'] = otps[otpRefs[i]]['version'];
}
return result;
}
]
});
deferredResult.addMethod(this.connection(), 'updateCredentials');
deferredResult.callback();
return deferredResult;
@@ -212,8 +262,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
}),
'oneTimePasswords': new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
'name': 'preferences',
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
'connection': this.connection(),
'name': 'oneTimePasswords',
'username': this.username(),
'passphraseCallback': MochiKit.Base.method(this, 'getPassphrase')
})
}
};
@@ -227,18 +279,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.registerAsNewAccount", {trace:false});
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':3});
deferredResult.addMethod(this, 'initialSetupWithNoData')
deferredResult.addMethod(this, 'getPassphrase');
deferredResult.addMethod(this, 'prepareRemoteDataWithKey');
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
deferredResult.addMethod(this.connection(), 'register');
// deferredResult.addCallback(MochiKit.Base.itemgetter('lock'));
// deferredResult.addMethod(this, 'setServerLockValue');
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userSuccessfullyRegistered');
// deferredResult.addErrback (MochiKit.Base.method(this, 'handleRegistrationFailure'));
deferredResult.callback();
return deferredResult;
@@ -276,22 +320,44 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'login': function () {
var deferredResult;
var oneTimePasswordReference;
deferredResult = new Clipperz.Async.Deferred("User.login", {trace:false});
deferredResult.addMethod(this, 'getPassphrase');
deferredResult.addCallback(Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue);
deferredResult.addCallback(Clipperz.Async.deferredIf("Is the passphrase an OTP", [
MochiKit.Base.method(this,'getPassphrase'),
MochiKit.Base.method(this,'setUsedOTP'),
MochiKit.Base.method(this, 'getCredentials'),
MochiKit.Base.method(this.connection(), 'redeemOneTimePassword'),
MochiKit.Base.method(this.data(), 'setValue', 'passphrase')
function (aPassphrase) {
return MochiKit.Base.partial(MochiKit.Async.succeed, aPassphrase);
},
MochiKit.Base.method(this, 'setPassphraseFunction')
], []));
deferredResult.addErrback(MochiKit.Base.method(this, 'getPassphrase'));
deferredResult.addBoth(MochiKit.Base.method(this, 'loginWithPassphrase'));
deferredResult.addBoth(MochiKit.Base.method(this, 'resetUsedOTP'));
deferredResult.callback();
return deferredResult;
},
'loginWithPassphrase': function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.loginWithPassphrase", {trace:false});
deferredResult.addMethod(this, 'getPassphrase');
deferredResult.addMethod(this.connection(), 'login', false);
deferredResult.addMethod(this, 'setupAccountInfo');
deferredResult.addMethod(this, 'markUsedOTP');
deferredResult.addErrback (MochiKit.Base.method(this, 'handleConnectionFallback'));
deferredResult.callback();
return deferredResult;
},
@@ -300,21 +366,18 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'handleConnectionFallback': function(aValue) {
var result;
//console.log("USER - handleConnectionFallback", aValue, aValue['isPermanent']);
if (aValue instanceof MochiKit.Async.CancelledError) {
result = aValue;
} else if ((aValue['isPermanent'] === true) || (Clipperz.PM.Connection.communicationProtocol.fallbackVersions[this.connectionVersion()] == null)) {
result = Clipperz.Async.callbacks("User.handleConnectionFallback - failed", [
MochiKit.Base.method(this.data(), 'removeValue', 'passphrase'),
MochiKit.Base.method(this, 'setConnectionVersion', 'current'),
// MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userLoginFailed'),
// MochiKit.Base.partial(MochiKit.Async.fail, Clipperz.PM.DataModel.User.exception.LoginFailed)
MochiKit.Base.partial(MochiKit.Async.fail, aValue)
], {trace:false});
} else {
this.setConnectionVersion(Clipperz.PM.Connection.communicationProtocol.fallbackVersions[this.connectionVersion()]);
result = new Clipperz.Async.Deferred("User.handleConnectionFallback - retry");
result.addMethod(this, 'login');
result.addMethod(this, 'loginWithPassphrase');
result.callback();
}
@@ -324,8 +387,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
//-------------------------------------------------------------------------
'setupAccountInfo': function (aValue) {
//console.log("User.setupAccountInfo", aValue, aValue['accountInfo']);
// this.setLoginInfo(aValue['loginInfo']);
this.setAccountInfo(new Clipperz.PM.DataModel.User.AccountInfo(aValue['accountInfo']));
},
@@ -373,8 +434,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
var preferences;
var oneTimePasswords;
// this.setServerLockValue(someServerData['lock']);
headerVersion = this.headerFormatVersion(someServerData['header']);
switch (headerVersion) {
case 'LEGACY':
@@ -429,7 +488,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
if (typeof(headerData['oneTimePasswords']) != 'undefined') {
oneTimePasswords = new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
'name': 'preferences',
'name': 'oneTimePasswords',
'connection': this.connection(),
'username': this.username(),
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
'remoteData': {
'data': headerData['oneTimePasswords']['data'],
@@ -438,7 +499,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
});
} else {
oneTimePasswords = new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
'name': 'preferences',
'name': 'OneTimePasswords',
'connection': this.connection(),
'username': this.username(),
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
});
}
@@ -595,7 +658,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
*/
], {trace:false});
},
/*
'filterRecordsInfo': function (someArgs) {
var info = (someArgs.info ? someArgs.info : Clipperz.PM.DataModel.Record.defaultCardInfo);
@@ -688,8 +750,47 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
], {trace:false});
},
//.........................................................................
'createNewRecordFromJSON': function(someJSON) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.createNewRecordFromJSON", {trace:false});
deferredResult.collectResults({
'recordIndex': MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
'newRecord': [
MochiKit.Base.method(this, 'createNewRecord'),
MochiKit.Base.methodcaller('setUpWithJSON', someJSON),
]
});
deferredResult.addCallback(function (someInfo) {
var record = someInfo['newRecord'];
var recordIndex = someInfo['recordIndex'];
return MochiKit.Base.map(function (aDirectLogin) {
var configuration = JSON.stringify({
'page': {'title': aDirectLogin['label']},
'form': aDirectLogin['formData'],
'version': '0.2' // correct?
});
return Clipperz.Async.callbacks("User.createNewRecordFromJSON__inner", [
MochiKit.Base.method(recordIndex, 'createNewDirectLogin', record),
MochiKit.Base.methodcaller('setLabel', aDirectLogin['label']),
MochiKit.Base.methodcaller('setBookmarkletConfiguration', configuration),
MochiKit.Base.methodcaller('setBindings', aDirectLogin['bindingData'], someJSON['currentVersion']['fields']),
], {'trace': false});
}, MochiKit.Base.values(someJSON.data.directLogins));
});
deferredResult.addCallback(Clipperz.Async.collectAll);
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
'cloneRecord': function (aRecord) {
//console.log("USER.cloneRecord", aRecord);
var result;
var user = this;
@@ -700,9 +801,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
], [
MochiKit.Base.method(user, 'createNewRecord'),
MochiKit.Base.methodcaller('setUpWithRecord', aRecord),
// function (aValue) { result = aValue; return aValue; },
// MochiKit.Base.method(user, 'saveChanges'),
// function () { return result; }
])
], {trace:false});
},
@@ -731,6 +829,62 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
], {trace:false});
},
'getOneTimePasswordsDetails': function() {
return Clipperz.Async.callbacks("User.getOneTimePasswords", [
MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
MochiKit.Base.methodcaller('oneTimePasswordsDetails', this.connection()),
], {trace:false});
},
//-------------------------------------------------------------------------
'createNewOTP': function () {
var messageParameters;
messageParameters = {};
return Clipperz.Async.callbacks("User.createNewOTP", [
MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
MochiKit.Base.methodcaller('createNewOTP', this.username(), MochiKit.Base.method(this, 'getPassphrase')),
MochiKit.Base.methodcaller('encryptedData'),
MochiKit.Base.partial(function(someParameters, someOTPEncryptedData) {
someParameters['oneTimePassword'] = someOTPEncryptedData;
}, messageParameters),
MochiKit.Base.method(this, 'getPassphrase'),
MochiKit.Base.method(this, 'prepareRemoteDataWithKey'),
MochiKit.Base.partial(function(someParameters, someEncryptedRemoteData) {
someParameters['user'] = someEncryptedRemoteData;
}, messageParameters),
MochiKit.Base.method(this.connection(), 'message', 'addNewOneTimePassword', messageParameters)
], {trace:false});
},
'deleteOTPs': function (aList) {
var messageParameters;
messageParameters = {};
return Clipperz.Async.callbacks("User.deleteOTPs", [
MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
MochiKit.Base.methodcaller('deleteOTPs', aList),
MochiKit.Base.partial(function(someParameters, aList) {
someParameters['oneTimePasswords'] = aList
}, messageParameters),
MochiKit.Base.method(this, 'getPassphrase'),
MochiKit.Base.method(this, 'prepareRemoteDataWithKey'),
MochiKit.Base.partial(function(someParameters, someEncryptedRemoteData) {
someParameters['user'] = someEncryptedRemoteData;
}, messageParameters),
MochiKit.Base.method(this.connection(), 'message', 'updateOneTimePasswords', messageParameters)
], {trace:false});
},
'changeOTPLabel': function (aReference, aLabel) {
return Clipperz.Async.callbacks("User.changeOTPLabel", [
MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
MochiKit.Base.methodcaller('changeOTPLabel', aReference, aLabel),
MochiKit.Base.method(this,'saveChanges') // Too 'heavy'? Should be moved to MainController to prevent glitch in the UI?
], {trace:false});
},
//=========================================================================
'invokeMethodNamedOnHeader': function (aMethodName, aValue) {
@@ -804,13 +958,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'revertChanges': function () {
return Clipperz.Async.callbacks("User.revertChanges", [
//function (aValue) { console.log("User.revertChanges - 1"); return aValue; },
MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'revertChanges'),
//function (aValue) { console.log("User.revertChanges - 2"); return aValue; },
MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'revertChanges'),
//function (aValue) { console.log("User.revertChanges - 3"); return aValue; },
MochiKit.Base.method(this, 'resetTransientState', false),
//function (aValue) { console.log("User.revertChanges - 4"); return aValue; },
], {trace:false});
},
@@ -882,6 +1032,13 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
return deferredResult;
},
'prepareRemoteDataWithKeyFunction': function(aKeyFunction) {
return new Clipperz.Async.callbacks("User.prepareRemoteDataWithKeyFunction", [
aKeyFunction,
MochiKit.Base.method(this, 'prepareRemoteDataWithKey')
], {'trace': false})
},
//=========================================================================
'saveChanges': function () {
@@ -895,24 +1052,17 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
deferredResult.addMethod(this, 'getHeaderIndex', 'recordsIndex');
deferredResult.addCallback(MochiKit.Base.methodcaller('prepareRemoteDataForChangedRecords'));
deferredResult.addCallback(Clipperz.Async.setItem, messageParameters, 'records');
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
deferredResult.addMethod(this, 'getPassphrase');
deferredResult.addMethod(this, 'prepareRemoteDataWithKey');
deferredResult.addCallback(Clipperz.Async.setItem, messageParameters, 'user');
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
deferredResult.addCallback(MochiKit.Async.succeed, messageParameters);
deferredResult.addMethod(this.connection(), 'message', 'saveChanges');
deferredResult.addCallback(MochiKit.Base.update, this.transientState())
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
deferredResult.addMethod(this, 'commitTransientState');
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userDataSuccessfullySaved');
deferredResult.addErrbackPass(MochiKit.Base.method(this, 'revertChanges'));
// deferredResult.addErrbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'failureWhileSavingUserData');
deferredResult.callback();