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

BTC Certificate feature

Added the ability to register card content on the BTC blockchain in order to certify its existance/content
This commit is contained in:
Giulio Cesare Solaroli
2016-03-29 11:45:50 +02:00
parent f84d05240b
commit fbcd02dffd
102 changed files with 23275 additions and 8645 deletions

View File

@@ -104,18 +104,23 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Attachment, Object, {
},
'setFile': function (aFile) {
var hashValue;
//console.log("ATTACHMENT SET FILE", aFile);
this._file = aFile || null;
// hashValue = aFile ? npm.bitcoin.address.toBase58Check(npm.bitcoin.crypto.hash160(aFile), NETWORK.pubKeyHash) : null;
/* These ones will disappear when the application is closed */
this._name = aFile ? aFile['name'] : null;
this._contentType = aFile ? aFile['type'] : null;
this._size = aFile ? aFile['size'] : null;
// this._hash = hashValue;
/* These ones will be saved in the Record */
return Clipperz.Async.callbacks("Attachment.setFile", [
MochiKit.Base.method(this, 'setValue', 'name', aFile['name']),
MochiKit.Base.method(this, 'setValue', 'contentType', aFile['type']),
MochiKit.Base.method(this, 'setValue', 'size', aFile['size']),
// MochiKit.Base.method(this, 'setValue', 'hash', hashValue),
MochiKit.Base.partial(MochiKit.Async.succeed, this),
], {trace:false});
@@ -135,6 +140,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Attachment, Object, {
return this.getValue('size');
},
'hash': function () {
return this.getValue('hash');
},
'metadata': function () {
var deferredResult;
@@ -143,6 +152,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Attachment, Object, {
'name': MochiKit.Base.method(this, 'name'),
'type': MochiKit.Base.method(this, 'contentType'),
'size': MochiKit.Base.method(this, 'size'),
'hash': MochiKit.Base.method(this, 'hash'),
}, {trace:false});
deferredResult.callback();
@@ -346,6 +356,30 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Attachment, Object, {
},
//=========================================================================
/*
computeAttachmentCertificateInfo: function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("Attachment.computeAttachmentCertificateInfo", {trace:false});
deferredResult.collectResults({
'name': MochiKit.Base.method(this, 'name'),
'contentType': MochiKit.Base.method(this, 'contentType'),
'size': MochiKit.Base.method(this, 'size'),
'hash': [
MochiKit.Base.method(attachmentController, 'getAttachment', this),
function (aValue) { console.log("STEP 1", aValue); return aValue; },
// npm.bitcoin.crypto.hash160,
//function (aValue) { console.log("STEP 2", aValue); return aValue; },
// function (anHash160) { return npm.bitcoin.address.toBase58Check(anHash160, NETWORK.pubKeyHash);}
function () { return MochiKit.Async.succeed("bingo"); }
]
});
deferredResult.callback();
return deferredResult;
},
*/
//=========================================================================
__syntaxFix__: "syntax fix"
});

View File

@@ -69,16 +69,17 @@ Clipperz.PM.DataModel.EncryptedRemoteObject = function(args) {
//
// Basic data workflow
// =======================
//
// # READ
// getRemoteData
// unpackRemoteData
// getDecryptedData [encryptedDataKeypath, encryptedVersionKeypath]
// unpackData
//
//
// ?? packData
// ?? encryptDataWithKey
// ?? packRemoteData [encryptedDataKeypath (?), encryptedVersionKeypath (?)]
//
// # WRITE
// prepareRemoteDataWithKey
// packData
// [encryptDataWithKey]
// packRemoteData [encryptedDataKeypath (?), encryptedVersionKeypath (?)]
//
Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(null, {
@@ -284,7 +285,18 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul
//-------------------------------------------------------------------------
'setValue': function(aKey, aValue) {
'getOrSetValue': function (aKey, aGetValueFunction) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.setValue", {trace:false});
deferredResult.addMethod(this, '_getObjectDataStore');
deferredResult.addCallback(MochiKit.Base.methodcaller('deferredGetOrSet', aKey, aGetValueFunction));
deferredResult.callback();
return deferredResult;
},
'setValue': function (aKey, aValue) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.setValue", {trace:false});

View File

@@ -183,7 +183,7 @@ Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue = function(aPa
var result;
// "yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg"
if (aPassword.replace(/[\s\-]/g, '').length == 32) {
if (aPassword.replace(/[^a-zA-Z0-9]/g, '').length == 32) {
try {
var passwordByteArray;

View File

@@ -49,6 +49,7 @@ Clipperz.PM.DataModel.Record = function(args) {
this._createNewAttachmentFunction = args.createNewAttachmentFunction || null;
this._attachmentServerStatus = {};
this._certificateInfo = null;
this._tags = [];
this._directLogins = {};
@@ -63,7 +64,6 @@ Clipperz.PM.DataModel.Record = function(args) {
newVersion = new Clipperz.PM.DataModel.Record.Version({
'retrieveKeyFunction': MochiKit.Base.method(this, 'getVersionKey'),
'getVersion': MochiKit.Base.method(this, 'getVersion')
});
this._versions[newVersion.reference()] = newVersion;
this._currentVersionReference = newVersion.reference();
@@ -85,7 +85,288 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
// 'reference': function () {
// return this._reference;
// },
//=========================================================================
setID: function (anID) {
//console.log("RECORD - SET ID", this, anID);
return this.setValue('ID', anID);
},
getID: function () {
return this.getValue('ID');
},
//=========================================================================
collectFieldInfo: function (aField) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.collectFieldInfo', {trace:false});
deferredResult.setValue('_field');
deferredResult.addMethod(aField, 'reference');
deferredResult.setValue('_reference');
deferredResult.addMethod(aField, 'label');
deferredResult.setValue('label');
deferredResult.addMethod(aField, 'value');
deferredResult.setValue('value');
deferredResult.addMethod(aField, 'actionType');
deferredResult.setValue('actionType');
deferredResult.addMethod(aField, 'isHidden');
deferredResult.setValue('isHidden');
deferredResult.values();
deferredResult.callback(aField);
return deferredResult;
},
collectDirectLoginInfo: function (aDirectLogin) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.collectDirectLoginInfo', {trace:false});
deferredResult.addMethod(aDirectLogin, 'reference');
deferredResult.setValue('_reference');
deferredResult.addMethod(aDirectLogin, 'label');
deferredResult.setValue('label');
deferredResult.addMethod(aDirectLogin, 'favicon');
deferredResult.setValue('favicon');
deferredResult.values();
deferredResult.callback();
return deferredResult;
},
collectAttachmentInfo: function(anAttachment) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.collectAttachmentInfo', {trace:false});
deferredResult.setValue('_attachment'); // The object itself, maybe this should be the only value being passed
deferredResult.addMethod(anAttachment, 'reference');
deferredResult.setValue('_reference');
deferredResult.addMethod(anAttachment, 'name');
deferredResult.setValue('name');
deferredResult.addMethod(anAttachment, 'contentType');
deferredResult.setValue('contentType');
deferredResult.addMethod(anAttachment, 'size');
deferredResult.setValue('size');
deferredResult.addMethod(anAttachment, 'hash');
deferredResult.setValue('hash');
deferredResult.values();
deferredResult.callback(anAttachment);
return deferredResult;
},
collectRecordInfo: function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.collectRecordInfo', {trace:false});
deferredResult.setValue('_record');
deferredResult.addMethod(this, 'reference');
deferredResult.setValue('_reference');
deferredResult.addMethod(this, 'isArchived');
deferredResult.setValue('_isArchived');
deferredResult.addMethod(this, 'isBrandNew');
deferredResult.setValue('_isBrandNew');
deferredResult.addMethod(this, 'label');
deferredResult.setValue('label');
deferredResult.addMethod(this, 'notes');
deferredResult.setValue('notes');
deferredResult.addMethod(this, 'tags');
deferredResult.setValue('tags');
deferredResult.addMethod(this, 'getID');
deferredResult.setValue('ID');
deferredResult.addMethod(this, 'fields');
deferredResult.addCallback(MochiKit.Base.values);
deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'collectFieldInfo'));
deferredResult.addCallback(Clipperz.Async.collectAll);
deferredResult.setValue('fields');
deferredResult.addMethod(this, 'certificateInfo');
deferredResult.addCallback(MochiKit.Base.bind(function (someCertificateInfo) {
var result;
if ((someCertificateInfo) && (someCertificateInfo['status'] == 'requested')) {
result = this.updateCertificateInfo()
} else {
result = MochiKit.Async.succeed(someCertificateInfo);
}
return result;
}, this));
deferredResult.setValue('certificateInfo');
deferredResult.addMethod(this, 'attachmentsInfo');
deferredResult.setValue('attachments');
deferredResult.addMethod(this, 'directLogins');
deferredResult.addCallback(MochiKit.Base.values);
deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'collectDirectLoginInfo'));
deferredResult.addCallback(Clipperz.Async.collectAll);
deferredResult.setValue('directLogins');
deferredResult.addMethod(this, 'getAttachmentServerStatus');
deferredResult.setValue('attachmentServerStatus');
deferredResult.values();
deferredResult.callback(this);
return deferredResult;
},
//=========================================================================
certificateMetadata: function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.certificateMetadata', {trace:false});
deferredResult.addMethod(this, 'collectRecordInfo');
deferredResult.addCallback(function (someValues) {
var result = {};
var propertiesToCollect = ['label', 'notes'];
var fieldPropertiesToCollect = ['label', 'value'];
var attachmentPropertiesToCollect = ['name', 'contentType', 'size', 'hash'];
MochiKit.Iter.forEach(propertiesToCollect, function (aKey) { result[aKey] = someValues[aKey]});
result['fields'] = MochiKit.Base.map(function (aField) {
var fieldResult = {};
MochiKit.Iter.forEach(fieldPropertiesToCollect, function (aKey) { fieldResult[aKey] = aField[aKey]});
return fieldResult;
}, someValues['fields']);
result['attachments'] = MochiKit.Base.map(function (anAttachment) {
var attachmentResult = {};
MochiKit.Iter.forEach(attachmentPropertiesToCollect, function (aKey) { attachmentResult[aKey] = anAttachment[aKey]});
return attachmentResult;
}, someValues['attachments']);
if (result['notes'] == "") {
delete result['notes'];
}
return result;
});
deferredResult.addCallback(Clipperz.Base.serializeJSON);
//deferredResult.addCallback(function (aValue) { console.log("<<< CERTIFICATE METADATA", aValue); return aValue;});
deferredResult.callback();
return deferredResult;
},
//=========================================================================
/*
publicKeyBufferFromHash256: function (aBuffer) {
// var fixedBuffer;
//
// fixedBuffer = new npm.buffer.Buffer(33);
// fixedBuffer.writeUInt8(0x03, 0); // https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
// aBuffer.copy(fixedBuffer, 1);
//
// return npm.bitcoin.ECPair.fromPublicKeyBuffer(fixedBuffer, NETWORK);
return npm.bitcoin.HDNode.fromSeedHex(aBuffer.toString('hex')).getPublicKeyBuffer();
},
*/
keyFromHash256: function (aBuffer) {
// return npm.bitcoin.HDNode.fromSeedHex(aBuffer.toString('hex'), NETWORK);
var d = npm.BigInteger.fromHex(aBuffer.toString('hex'));
return new npm.bitcoin.ECPair(d, null, {'network':NETWORK, 'compressed':true})
},
computeAttachmentsCertificateInfo: function (attachmentController) {
var deferredResult;
var collectResultsInfo = {};
var shouldComputeResult = false;
var self = this;
MochiKit.Iter.forEach(MochiKit.Base.values(this.attachments()), function (anAttachment) {
shouldComputeResult = true;
collectResultsInfo[anAttachment.reference()] = [
MochiKit.Base.method(anAttachment, 'metadata'),
MochiKit.Base.itemgetter('hash'),
function (anHashValue) {
var hashBuffer = new npm.buffer.Buffer(anHashValue, 'hex');
var key = self.keyFromHash256(hashBuffer);
return {
'hash': anHashValue,
'publicKey': key.getPublicKeyBuffer().toString('hex'),
'address': key.getAddress(),
}
}
];
});
if (shouldComputeResult) {
deferredResult = new Clipperz.Async.Deferred("Record.computeAttachmentsCertificateInfo", {trace:false});
deferredResult.collectResults(collectResultsInfo);
deferredResult.callback();
} else {
deferredResult = MochiKit.Async.succeed(collectResultsInfo);
}
return deferredResult;
},
computeCertificateInfo: function (aWallet) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("Record.computeCertificateInfo", {trace:false});
deferredResult.collectResults({
'reference': MochiKit.Base.method(this, 'reference'),
'version': MochiKit.Base.partial(MochiKit.Async.succeed, "1.0"),
'card.publicKey': [
MochiKit.Base.method(this, 'getID'),
MochiKit.Base.method(aWallet, 'getKeyForDocumentWithID'),
MochiKit.Base.methodcaller('getPublicKeyBuffer'),
MochiKit.Base.methodcaller('toString', 'hex'),
],
'card.address': [
MochiKit.Base.method(this, 'getID'),
MochiKit.Base.method(aWallet, 'getKeyForDocumentWithID'),
MochiKit.Base.methodcaller('getAddress')
],
/*
'metadata': [
MochiKit.Base.method(this, 'certificateMetadata'),
function (aString) { return new npm.buffer.Buffer(aString, 'utf8') },
npm.bitcoin.crypto.hash160,
function (anHash160) { return npm.bitcoin.address.toBase58Check(anHash160, NETWORK.pubKeyHash);}
],
*/
'metadata.publicKey': [
MochiKit.Base.method(this, 'certificateMetadata'),
function (aString) { return new npm.buffer.Buffer(aString, 'utf8') },
npm.bitcoin.crypto.hash256,
MochiKit.Base.method(this, 'keyFromHash256'),
MochiKit.Base.methodcaller('getPublicKeyBuffer'),
MochiKit.Base.methodcaller('toString', 'hex'),
],
'metadata.address': [
MochiKit.Base.method(this, 'certificateMetadata'),
function (aString) { return new npm.buffer.Buffer(aString, 'utf8') },
npm.bitcoin.crypto.hash256,
MochiKit.Base.method(this, 'keyFromHash256'),
MochiKit.Base.methodcaller('getAddress')
],
'attachments': MochiKit.Base.method(this, 'computeAttachmentsCertificateInfo')
});
//deferredResult.addCallback(function (aValue) { console.log("=== CERTIFICATE INFO", MochiKit.Base.serializeJSON(aValue)); return aValue;});
deferredResult.callback();
return deferredResult;
},
//=========================================================================
'getIndexData': function () {
@@ -149,6 +430,33 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
return this._attachmentServerStatus;
},
updatedAttachmentServerStatus: function () {
return Clipperz.Async.callbacks("Record.updatedAttachmentServerStatus", [
MochiKit.Base.partial(this.retrieveRemoteDataFunction(), this),
MochiKit.Base.itemgetter('attachmentStatus'),
MochiKit.Base.method(this, 'setAttachmentServerStatus'),
], {trace:false});
},
//----------------------------------------------------------------------------
setCertificateInfo: function (aValue) {
this._certificateInfo = aValue;
return this._certificateInfo;
},
certificateInfo: function () {
return this._certificateInfo;
},
updateCertificateInfo: function () {
return Clipperz.Async.callbacks("Record.updateCertificateInfo", [
MochiKit.Base.partial(this.retrieveRemoteDataFunction(), this),
MochiKit.Base.itemgetter('certificateInfo'),
MochiKit.Base.method(this, 'setCertificateInfo'),
], {trace:false});
},
//============================================================================
/*
'key': function () {
@@ -302,8 +610,32 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
//=========================================================================
attachmentsCount: function() {
return MochiKit.Base.keys(this.attachments()).length;
certificateStatus: function() {
// TODO: FAKE IMPLEMENTATION, just enough to test the UI
var result;
// if (this.reference().charAt(0) == 'a') {
// result = 'published';
// } else if (this.reference().charAt(0) == '0') {
// result = 'requested';
// } else {
// result = '';
// }
result = '';
return result; // 'requested' | 'published' | ''
},
markAsCertified: function () {
return this.addTag(Clipperz.PM.DataModel.Record.certifiedTag);
},
hasBeenCertified: function () {
return Clipperz.Async.callbacks("Record.isArchived", [
MochiKit.Base.method(this, 'tags'),
function (someTags) { return MochiKit.Iter.some(someTags, MochiKit.Base.partial(MochiKit.Base.objEqual, Clipperz.PM.DataModel.Record.certifiedTag))},
], {trace:false});
},
//=========================================================================
@@ -486,6 +818,26 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
//=========================================================================
// TODO: !!!!
'attachmentsCount': function() {
return MochiKit.Base.keys(this.attachments()).length;
},
'attachmentsInfo': function () {
// deferredResult.addMethod(this, 'attachments');
// deferredResult.addCallback(MochiKit.Base.values);
// deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'collectAttachmentInfo'));
// deferredResult.addCallback(Clipperz.Async.collectAll);
return Clipperz.Async.callbacks("Record.attachmentsInfo", [
MochiKit.Base.method(this, 'attachments'),
MochiKit.Base.values,
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'collectAttachmentInfo')),
Clipperz.Async.collectAll
], {trace:false});
},
'attachments': function () {
return this._attachments;
},
@@ -527,7 +879,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
delete this._attachments[anAttachment.reference()]
}, this)
], {trace:false});
},
'attachmentReferences': function () {
@@ -563,16 +914,11 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
'unpackRemoteData': function (someData) {
var result;
/*
this._currentRecordVersion = new Clipperz.PM.DataModel.Record.Version({
'reference': someData['currentVersion']['reference'],
'retrieveKeyFunction': MochiKit.Base.method(this, 'getCurrentRecordVersionKey'),
'remoteData': someData['currentVersion'],
});
*/
var versionKey;
this.setAttachmentServerStatus(someData['attachmentStatus']);
this.setCertificateInfo(someData['certificateInfo']);
for (versionKey in someData['versions']) {
this._versions[versionKey] = new Clipperz.PM.DataModel.Record.Version({
'reference': versionKey,
@@ -581,8 +927,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
'getVersion': MochiKit.Base.method(this, 'getVersion')
})
}
// this._currentVersionReference = someData['currentVersion']['reference'];
this._currentVersionReference = someData['currentVersion'];
result = Clipperz.PM.DataModel.Record.superclass.unpackRemoteData.apply(this, arguments);
@@ -596,11 +940,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
var result;
result = Clipperz.PM.DataModel.Record.superclass.unpackData.apply(this, arguments);
if (MochiKit.Base.isUndefinedOrNull(result['notes'])) {
result['notes'] = ''
}
return result;
},
@@ -1218,6 +1561,12 @@ Clipperz.log("Warning: Record.fieldWithLabel('" + aLabel + "') is returning more
MochiKit.Base.method(aRecord, 'fullLabel'),
MochiKit.Base.method(aRecord, 'extractTagsFromFullLabel'),
//function (someValues) { console.log(">>> TAGS", someValues); return someValues; },
MochiKit.Base.keys,
MochiKit.Base.partial(MochiKit.Base.filter, Clipperz.PM.DataModel.Record.isRegularTag),
MochiKit.Base.partial(MochiKit.Base.filter, Clipperz.PM.DataModel.Record.isNotImportTag),
function (tags) { return MochiKit.Iter.reduce(function (result, value) { result[value] = true; return result; }, tags, {}); },
//function (someValues) { console.log("<<< TAGS", someValues); return someValues; },
MochiKit.Base.method(this, 'updateTags'),
MochiKit.Base.method(aRecord, 'notes'),
@@ -1333,6 +1682,7 @@ Clipperz.PM.DataModel.Record.defaultCardInfo = {
'label': MochiKit.Base.methodcaller('label'),
'favicon': MochiKit.Base.methodcaller('favicon'),
'attachmentsCount': MochiKit.Base.methodcaller('attachmentsCount'),
'hasBeenCertified': MochiKit.Base.methodcaller('hasBeenCertified'),
};
Clipperz.PM.DataModel.Record.defaultSearchField = '_searchableContent';
@@ -1342,7 +1692,9 @@ Clipperz.PM.DataModel.Record.specialTagChar = '\uE010';
Clipperz.PM.DataModel.Record.specialTagsConstructor = function (aTag) {
return Clipperz.PM.DataModel.Record.specialTagChar + aTag; //.replace(/\s/g, Clipperz.PM.DataModel.Record.tagSpace);
}
Clipperz.PM.DataModel.Record.archivedTag = Clipperz.PM.DataModel.Record.specialTagsConstructor('ARCH');
Clipperz.PM.DataModel.Record.archivedTag = Clipperz.PM.DataModel.Record.specialTagsConstructor('ARCH');
Clipperz.PM.DataModel.Record.certifiedTag = Clipperz.PM.DataModel.Record.specialTagsConstructor('CERT');
Clipperz.PM.DataModel.Record.regExpForTag = function (aTag) {
return new RegExp('\\' + Clipperz.PM.DataModel.Record.tagChar + aTag, 'g');
};
@@ -1355,6 +1707,9 @@ Clipperz.PM.DataModel.Record.isSpecialTag = function (aTag) {
Clipperz.PM.DataModel.Record.isRegularTag = function (aTag) {
return !Clipperz.PM.DataModel.Record.isSpecialTag(aTag);
};
Clipperz.PM.DataModel.Record.isNotImportTag = function (aTag) {
return aTag.indexOf('Import_') != 0;
};
Clipperz.PM.DataModel.Record.regExpForSearch = function (aSearch) {
return new RegExp(aSearch.replace(/[^A-Za-z0-9]/g, '\\$&'), 'i');
};

View File

@@ -456,27 +456,15 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stats associated
//-------------------------------------------------------------------------
'createNewAttachment': function (aRecord) {
// TODO:
// var newDirectLogin;
var newAttachment;
// var newDirectLoginIndexValue;
var newAttachmentIndexValue;
// newDirectLogin = new Clipperz.PM.DataModel.DirectLogin({record:aRecord});
newAttachment = new Clipperz.PM.DataModel.Attachment({'record':aRecord});
// newDirectLoginIndexValue = MochiKit.Base.listMax(MochiKit.Base.map(function (aValue) { return aValue * 1; }, MochiKit.Base.values(this.directLoginsIndex()))) + 1;
newAttachmentIndexValue = MochiKit.Base.listMax(MochiKit.Base.map(function (aValue) { return aValue * 1; }, MochiKit.Base.values(this.attachmentsIndex()))) + 1;
// this.transientState().setValue('newDirectLoginReferences' + '.' + newDirectLogin.reference(), newDirectLogin);
this.transientState().setValue('newAttachmentReferences' + '.' + newAttachment.reference(), newAttachment);
// this.directLoginsIndex()[newDirectLogin.reference()] = newDirectLoginIndexValue;
this.attachmentsIndex()[newAttachment.reference()] = newAttachmentIndexValue;
// this.directLoginsData().setValue(this.directLoginsIndex()[newDirectLogin.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
this.attachmentsData().setValue(this.attachmentsIndex()[newAttachment.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
// return newDirectLogin;
return newAttachment;
},

View File

@@ -0,0 +1,174 @@
/*
Copyright 2008-2015 Clipperz Srl
This file is part of Clipperz, the online password manager.
For further information about its features and functionalities please
refer to http://www.clipperz.com.
* Clipperz is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
* Clipperz is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
*/
try { if (typeof(Clipperz.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.PM.DataModel.User.Header.Wallet depends on Clipperz.PM.DataModel.User!";
}
if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
Clipperz.PM.DataModel.User.Header.Wallet = function(args) {
Clipperz.PM.DataModel.User.Header.Wallet.superclass.constructor.apply(this, arguments);
return this;
}
Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.Wallet, Clipperz.PM.DataModel.EncryptedRemoteObject, {
'toString': function() {
return "Clipperz.PM.DataModel.User.Header.Wallet";
},
//-------------------------------------------------------------------------
getRandomSeed: function () {
return Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(512/8).toHexString().substring(2);
},
getWalletSeed: function () {
return this.getOrSetValue('walletSeed', MochiKit.Base.method(this, 'getRandomSeed'));
},
userMasterKey: function () {
return Clipperz.Async.callbacks("User.Header.Wallet.userMasterKey", [
MochiKit.Base.method(this, 'getWalletSeed'),
function (aValue) {
return npm.bitcoin.HDNode.fromSeedHex(aValue, NETWORK);
}
], {trace:false});
},
getNextID: function (aKeyPath) {
//console.log("WALLET - getNextID", aKeyPath);
return Clipperz.Async.callbacks("User.Header.Wallet.userMasterKey", [
MochiKit.Base.method(this, 'getValue', aKeyPath),
function (aValue) {
var result;
if (aValue == null) {
result = 0;
} else {
result = aValue + 1;
}
return result;
},
MochiKit.Base.method(this, 'setValue', aKeyPath)
], {trace:false});
},
getKeyForDocumentWithID: function (anID) {
return Clipperz.Async.callbacks("User.Header.Wallet.getKeyForDocumentWithID", [
MochiKit.Base.method(this, 'userMasterKey'),
MochiKit.Base.methodcaller('derive', 0),
MochiKit.Base.methodcaller('derive', anID)
], {trace:false});
},
// getPublicKeyForDocumentWithID: function (anID) {
// return Clipperz.Async.callbacks("User.Header.Wallet.getPublicKeyForDocumentWithID", [
// MochiKit.Base.method(this, 'getKeyForDocumentWithID', anID),
// MochiKit.Base.methodcaller('getPublicKeyBuffer'),
// MochiKit.Base.methodcaller('toString', 'hex'),
// ], {trace:false});
// },
// getAddressForDocumentWithID: function (anID) {
//console.log("WALLET - address for document with ID", anID);
// return Clipperz.Async.callbacks("User.Header.Wallet.getAddressForDocumentWithID", [
// MochiKit.Base.method(this, 'getKeyForDocumentWithID', anID),
// MochiKit.Base.methodcaller('getAddress')
// ], {trace:false});
// },
//#########################################################################
// prepareRemoteDataWithKey
// packData
// encryptDataWithKey
// packRemoteData [encryptedDataKeypath (?), encryptedVersionKeypath (?)]
/*
prepareRemoteDataWithKey: function (aKey) {
console.log("USER HEADER WALLET - prepareRemoteDataWithKey", aKey);
//console.log("super", Clipperz.PM.DataModel.User.Header.Wallet.superclass.prepareRemoteDataWithKey);
return Clipperz.PM.DataModel.User.Header.Wallet.superclass.prepareRemoteDataWithKey.apply(this, arguments);
},
packData: function (someData) { // ++
console.log("USER HEADER WALLET - packData", someData);
return Clipperz.PM.DataModel.User.Header.Wallet.superclass.packData.apply(this, arguments);
},
packRemoteData: function (someData) {
console.log("USER HEADER WALLET - packRemoteData", someData);
return Clipperz.PM.DataModel.User.Header.Wallet.superclass.packRemoteData.apply(this, arguments);
},
*/
//#########################################################################
/*
'mergePreferences': function(somePreferences, someOtherPreferences) {
var result;
result = new Clipperz.KeyValueObjectStore();
result.setValues(MochiKit.Base.updatetree(
Clipperz.Base.deepClone(someOtherPreferences),
somePreferences
));
return result;
},
'mergeDefaultPreferences': function(somePreferences) {
return this.mergePreferences(somePreferences, Clipperz.PM.DataModel.User.Header.Preferences.defaultPreferences);
},
'mergeUserPreferences': function(somePreferences) {
return this.mergePreferences(somePreferences, this._objectDataStore.values());
},
'getPreferences': function() {
return Clipperz.Async.callbacks("User.Header.Preferences.getPreferences", [
MochiKit.Base.method(this, 'values'),
MochiKit.Base.method(this, 'mergeDefaultPreferences')
], {trace:false});
},
'getPreference': function(aKey) {
return Clipperz.Async.callbacks("User.Header.Preferences.getPreference", [
MochiKit.Base.method(this, 'getPreferences'),
MochiKit.Base.methodcaller('getValue', aKey)
], {trace:false});
},
'setPreferences': function(anObject) {
return Clipperz.Async.callbacks("User.Header.Preferences.setPreferences", [
MochiKit.Base.method(this, 'mergeUserPreferences', anObject),
MochiKit.Base.methodcaller('values'),
MochiKit.Base.method(this, 'setValues')
], {trace:false});
},
*/
//=========================================================================
__syntaxFix__: "syntax fix"
});

View File

@@ -52,10 +52,6 @@ Clipperz.PM.DataModel.User = function (args) {
this._deferredLocks = {
'passphrase': new MochiKit.Async.DeferredLock(),
'serverData': new MochiKit.Async.DeferredLock(),
// 'recordsIndex': new MochiKit.Async.DeferredLock(),
// 'directLoginsIndex': new MochiKit.Async.DeferredLock()
// 'preferences': new MochiKit.Async.DeferredLock()
// 'oneTimePasswords': new MochiKit.Async.DeferredLock()
'__syntaxFix__': 'syntax fix'
};
@@ -267,6 +263,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'name': 'oneTimePasswords',
'username': this.username(),
'passphraseCallback': MochiKit.Base.method(this, 'getPassphrase')
}),
'wallet': new Clipperz.PM.DataModel.User.Header.Wallet({
'name': 'wallet',
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
})
}
};
@@ -391,6 +391,24 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
this.setAccountInfo(new Clipperz.PM.DataModel.User.AccountInfo(aValue['accountInfo']));
},
'updateAccountInfo': function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.updateAccountInfo", {trace:false});
deferredResult.addMethod(this.connection(), 'message', 'accountInfo');
// deferredResult.addCallback(function (aValue) {
//console.log("ACCOUNT INFO", aValue);
// return new Clipperz.PM.DataModel.User.AccountInfo(aValue);
// })
deferredResult.addMethod(this, 'setupAccountInfo');
deferredResult.addErrback (MochiKit.Base.method(this, 'handleConnectionFallback'));
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
'lock': function () {
@@ -439,8 +457,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
var headerVersion;
var recordsIndex;
var preferences;
var oneTimePasswords;
var preferences;
var oneTimePasswords;
var wallet;
headerVersion = this.headerFormatVersion(someServerData['header']);
switch (headerVersion) {
@@ -462,6 +481,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
recordsIndex = legacyHeader;
preferences = legacyHeader;
oneTimePasswords = legacyHeader;
wallet = legacyHeader; // TODO: does this make any sense?
break;
case '0.1':
var headerData;
@@ -516,6 +536,22 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
});
}
if (typeof(headerData['wallet']) != 'undefined') {
wallet = new Clipperz.PM.DataModel.User.Header.Wallet({
'name': 'wallet',
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
'remoteData': {
'data': headerData['wallet']['data'],
'version': someServerData['version']
}
});
} else {
wallet = new Clipperz.PM.DataModel.User.Header.Wallet({
'name': 'wallet',
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
});
}
break;
}
@@ -527,9 +563,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'data': someServerData['header'],
'version': headerVersion,
'recordsIndex': recordsIndex,
'preferences': preferences,
'oneTimePasswords': oneTimePasswords
'recordsIndex': recordsIndex,
'preferences': preferences,
'oneTimePasswords': oneTimePasswords,
'wallet': wallet
}
};
@@ -552,7 +589,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
if (this._serverData == null) {
innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadingUserDetails');
innerDeferredResult.addMethod(this.connection(), 'message', 'getUserDetails');
// innerDeferredResult.addCallback(function (aValue) { console.log("USER DETAILS", aValue); return aValue; });
innerDeferredResult.addMethod(this, 'unpackServerData');
// innerDeferredResult.addCallback(function (aValue) { console.log("UNPACKED SERVER DATA", aValue); return aValue; });
innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadedUserDetails');
}
@@ -607,6 +646,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'getHeaderIndex': function (aKey) {
return Clipperz.Async.callbacks("User.getHeaderIndex", [
MochiKit.Base.method(this, 'getServerData'),
// function (aValue) { console.log("HEADER INDEX", aValue); return aValue; },
MochiKit.Base.itemgetter('header'),
MochiKit.Base.itemgetter(aKey)
], {trace:false})
@@ -728,12 +768,7 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//-------------------------------------------------------------------------
'getRecordDetail': function (aRecord) {
// return this.connection().message('getRecordDetail', {reference: aRecordReference});
return Clipperz.Async.callbacks("User.getRecordDetail", [
MochiKit.Base.method(this.connection(), 'message', 'getRecordDetail', {reference: aRecord.reference()}),
function(someInfo) { aRecord.setAttachmentServerStatus(someInfo['attachmentStatus']); return someInfo;}, // Couldn't find a better way...
], {trace:false});
return this.connection().message('getRecordDetail', {reference: aRecord.reference()});
},
//-------------------------------------------------------------------------
@@ -906,7 +941,11 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
'oneTimePasswords': [
MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
MochiKit.Base.methodcaller(aMethodName, aValue)
]//,
],
'wallet': [
MochiKit.Base.method(this, 'getHeaderIndex', 'wallet'),
MochiKit.Base.methodcaller(aMethodName, aValue)
]
// 'statistics': [
// MochiKit.Base.method(this, 'getStatistics'),
// MochiKit.Base.methodcaller(aMethodName, aValue)
@@ -926,14 +965,14 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//-------------------------------------------------------------------------
'getPreferences': function() {
getPreferences: function() {
return Clipperz.Async.callbacks("User.getPreferences", [
MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'),
MochiKit.Base.methodcaller('getPreferences')
], {trace:false});
},
'getPreference': function(aKey) {
getPreference: function(aKey) {
return Clipperz.Async.callbacks("User.getPreference", [
MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'),
MochiKit.Base.methodcaller('getPreference', aKey)
@@ -950,11 +989,7 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//-------------------------------------------------------------------------
/*
'addNewAttachment': function(anAttachment) {
console.log("Adding attachment", anAttachment);
},
*/
'uploadAttachment': function(aRecordReference, anAttachmentReference, someData) {
// TODO: pass a callback to handle onProgress events (and modify Connection accordingly)
this.connection().message('uploadAttachment', {
@@ -966,6 +1001,34 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//=========================================================================
getWallet: function () {
return this.getHeaderIndex('wallet');
},
getUserMasterKey: function () {
//console.log("USER - GET USER MASTER KEY");
return Clipperz.Async.callbacks("User.getPreferences", [
MochiKit.Base.method(this, 'getHeaderIndex', 'wallet'),
MochiKit.Base.methodcaller('userMasterKey')
], {trace:false});
},
createCertificateForRecord: function (aRecord) {
var cardCertificatePath = 'm/0';
return Clipperz.Async.callbacks("User.createCertificateForRecord", [
MochiKit.Base.method(this, 'getWallet'),
MochiKit.Base.methodcaller('getNextID', cardCertificatePath),
MochiKit.Base.method(aRecord, 'setID'),
MochiKit.Base.method(aRecord, 'markAsCertified'),
MochiKit.Base.method(this, 'getWallet'),
MochiKit.Base.method(aRecord, 'computeCertificateInfo'),
function (certificateInfo) { return {'certificateInfo': certificateInfo}; },
], {trace:false});
},
//=========================================================================
'hasPendingChanges': function () {
var deferredResult;
@@ -1059,12 +1122,14 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
deferredResult.addCallback(MochiKit.Base.bind(function (aResult, someHeaderPackedData) {
var header;
//console.log("USER - prepareRemoteDataWithKey", someHeaderPackedData);
header = {};
header['records'] = someHeaderPackedData['recordIndex']['records'];
header['directLogins'] = someHeaderPackedData['recordIndex']['directLogins'];
header['attachments'] = someHeaderPackedData['recordIndex']['attachments'];
header['preferences'] = {'data': someHeaderPackedData['preferences']['data']};
header['oneTimePasswords'] = {'data': someHeaderPackedData['oneTimePasswords']['data']};
header['wallet'] = {'data': someHeaderPackedData['wallet']['data']};
header['version'] = '0.1';
aResult['header'] = Clipperz.Base.serializeJSON(header);
@@ -1089,10 +1154,17 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//=========================================================================
'saveChanges': function () {
return this.saveChangesWithExtraParameters();
},
'saveChangesWithExtraParameters': function (extraParameters) {
var deferredResult;
var messageParameters;
messageParameters = {};
if (typeof(extraParameters) != 'undefined') {
messageParameters['extraParameters'] = extraParameters;
}
deferredResult = new Clipperz.Async.Deferred("User.saveChangaes", {trace:false});
@@ -1110,7 +1182,6 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
deferredResult.addMethod(this, 'commitTransientState');
deferredResult.addErrbackPass(MochiKit.Base.method(this, 'revertChanges'));
deferredResult.callback();
return deferredResult;