summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js
Unidiff
Diffstat (limited to 'frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js542
1 files changed, 542 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js b/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js
new file mode 100644
index 0000000..1aa7a52
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js
@@ -0,0 +1,542 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.KeyValueObjectStore) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.EncryptedRemoteObject depends on Clipperz.KeyValueObjectStore!";
26}
27
28if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
29if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
30
31Clipperz.PM.DataModel.EncryptedRemoteObject = function(args) {
32 args = args || {};
33
34 this._name = args.name || null;
35 this._reference = args.reference || Clipperz.PM.Crypto.randomKey();
36 this._isBrandNew = ((args.reference == null) && (args.remoteData == null));
37
38 if ((this._isBrandNew == false) && (args['retrieveKeyFunction'] == null)) {
39 Clipperz.Base.exception.raise('MandatoryParameter');
40 } else {
41 this._retrieveKeyFunction = args['retrieveKeyFunction'];
42 }
43
44 this._retrieveRemoteDataFunction = args.retrieveRemoteDataFunction|| null;
45 this._remoteData = args.remoteData || null;
46 // this._remoteData = args.remoteData ? Clipperz.Base.deepClone(args.remoteData) : null;
47 if ((!this._isBrandNew) && ((this._retrieveRemoteDataFunction == null) && (this._remoteData == null))) {
48 Clipperz.Base.exception.raise('MandatoryParameter');
49 }
50
51
52 this._encryptedDataKeypath = args.encryptedDataKeypath || 'data'; //Clipperz.Base.exception.raise('MandatoryParameter');
53 this._encryptedVersionKeypath = args.encryptedVersionKeypath || 'version';//Clipperz.Base.exception.raise('MandatoryParameter');
54
55
56 this._transientState = null;
57 this._deferredLocks = {};
58
59 if (this._isBrandNew == true) {
60 this._objectDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.objectDataStore [1]'}*/);
61 } else {
62 this._objectDataStore = null;
63 }
64
65 return this;
66}
67
68//
69 // Basic data workflow
70 //=======================
71//
72 //getRemoteData
73 // unpackRemoteData
74 // getDecryptData [encryptedDataKeypath, encryptedVersionKeypath]
75 // unpackData
76 //
77 //
78 // ?? packData
79 // ?? encryptDataWithKey
80 // ??packRemoteData [encryptedDataKeypath (?), encryptedVersionKeypath (?)]
81//
82
83Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(null, {
84
85 'toString': function () {
86 return "Clipperz.PM.DataModel.EncryptedRemoteObject" + (this.name() != null ? " - " + this.name() : "");
87 },
88
89 //-------------------------------------------------------------------------
90
91 'name': function () {
92 return this._name;
93 },
94
95 //-------------------------------------------------------------------------
96
97 'reference': function () {
98 return this._reference;
99 },
100
101 'setReference': function (aValue) {
102 this._reference = aValue;
103
104 return this._reference;
105 },
106
107 //-------------------------------------------------------------------------
108
109 'transientState': function () {
110 if (this._transientState == null) {
111 this._transientState = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.transientState [2]'}*/);
112 }
113
114 return this._transientState;
115 },
116
117 'resetTransientState': function (isCommitting) {
118 if (this._transientState != null) {
119 this._transientState.removeAllData();
120 }
121
122 this._transientState = null;
123 },
124
125 //-------------------------------------------------------------------------
126
127 'isBrandNew': function () {
128 return this._isBrandNew;
129 },
130
131 //-------------------------------------------------------------------------
132
133 'getKey': function () {
134 var deferredResult;
135 var deferredLock;
136
137 deferredLock = this.getDeferredLockForKey('key');
138
139 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.getKey", {trace:false});
140 deferredResult.acquireLock(deferredLock);
141 deferredResult.addMethod(
142 this.decryptedDataStore(),
143 'deferredGetOrSet',
144 'decryptionKey',
145 MochiKit.Base.partial(this.retrieveKeyFunction(), this.reference())
146 );
147 deferredResult.releaseLock(deferredLock);
148 deferredResult.callback();
149
150 return deferredResult;
151 },
152
153 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
154
155 'retrieveKeyFunction': function () {
156 return this._retrieveKeyFunction;
157 },
158
159 'setRetrieveKeyFunction': function (aFunction) {
160 this._retrieveKeyFunction = aFunction;
161 },
162
163 //-------------------------------------------------------------------------
164
165 'hasLoadedRemoteData': function () {
166 return (this._remoteData != null);
167 },
168
169 'getRemoteData': function () {
170 var deferredResult;
171 vardeferredLock;
172
173 deferredLock = this.getDeferredLockForKey('remoteData');
174
175 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObjects.getRemoteData", {trace:false});
176 deferredResult.acquireLock(deferredLock);
177 deferredResult.addCallback(MochiKit.Base.bind(function () {
178 var innerDeferredResult;
179
180 if (this._remoteData != null) {
181 innerDeferredResult = MochiKit.Async.succeed(this._remoteData);
182 } else {
183 innerDeferredResult = Clipperz.Async.callbacks("EncryptedRemoteObjects.getRemoteData <inner deferred>", [
184 MochiKit.Base.partial(this.retrieveRemoteDataFunction(), this.reference()),
185 MochiKit.Base.method(this, 'unpackRemoteData'),
186 MochiKit.Base.bind(function (someData) {
187 this._remoteData = someData;
188 return this._remoteData;
189 }, this)
190 ], {trace:false});
191 }
192
193 return innerDeferredResult;
194 }, this))
195 deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
196 deferredResult.releaseLock(deferredLock);
197
198 deferredResult.callback();
199
200 return deferredResult;
201 },
202
203 //-------------------------------------------------------------------------
204
205 'unpackRemoteData': function (someData) {
206 return MochiKit.Async.succeed(someData);
207 },
208
209 //.........................................................................
210
211 'packRemoteData': function (someData) {
212 var result;
213
214 result = {
215 'reference':this.reference(),
216 'data': someData,
217 'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion
218 };
219
220 return MochiKit.Async.succeed(result);
221 },
222
223 //-------------------------------------------------------------------------
224
225 'retrieveRemoteDataFunction': function () {
226 return this._retrieveRemoteDataFunction;
227 },
228
229 'setRetrieveRemoteDataFunction': function (aFunction) {
230 this._retrieveRemoteDataFunction = aFunction;
231 },
232
233 //-------------------------------------------------------------------------
234
235 'decryptedDataStore': function () {
236 if (this._decryptedDataStore == null) {
237 this._decryptedDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.decryptedDataStore [3]'}*/);
238 };
239
240 return this._decryptedDataStore;
241 },
242
243 //.........................................................................
244
245 'getDecryptedData': function () {
246 var deferredResult;
247 var deferredLock;
248
249 deferredLock = this.getDeferredLockForKey('decryptedData');
250
251 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.getDecryptedData", {trace:false});
252 deferredResult.acquireLock(deferredLock);
253 deferredResult.addMethod(this, 'decryptedDataStore');
254 deferredResult.addCallback(MochiKit.Base.methodcaller('deferredGetOrSet', 'decryptedData', MochiKit.Base.bind(function () {
255 varinnerDeferredResult;
256
257 innerDeferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.getDecryptedData <inner deferred>", {trace:false});
258
259 innerDeferredResult.addMethod(this, 'getRemoteData');
260 innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
261 innerDeferredResult.collectResults({
262 'key': MochiKit.Base.method(this, 'getKey'),
263 'value':MochiKit.Base.itemgetter(this._encryptedDataKeypath),
264 'version':MochiKit.Base.itemgetter(this._encryptedVersionKeypath)
265 });
266
267 innerDeferredResult.addCallback(Clipperz.PM.Crypto.deferredDecrypt);
268 innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
269 innerDeferredResult.addMethod(this, 'unpackData');
270 innerDeferredResult.callback();
271
272 return innerDeferredResult;
273 }, this)));
274 deferredResult.releaseLock(deferredLock);
275 deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
276 deferredResult.callback();
277
278 return deferredResult;
279 },
280
281 //-------------------------------------------------------------------------
282
283 'setValue': function(aKey, aValue) {
284 var deferredResult;
285
286 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.setValue", {trace:false});
287 deferredResult.addMethod(this, '_getObjectDataStore');
288 deferredResult.addCallback(MochiKit.Base.methodcaller('setValue', aKey, aValue));
289 deferredResult.callback();
290
291 return deferredResult;
292 },
293
294 //.........................................................................
295
296 'getValue': function (aKey) {
297 return Clipperz.Async.callbacks("EncryptedRemoteObject.getValue", [
298 MochiKit.Base.method(this, '_getObjectDataStore'),
299 MochiKit.Base.methodcaller('getValue', aKey)
300 ], {trace:false});
301 },
302
303 //.........................................................................
304
305 'removeValue': function (aKey) {
306 return Clipperz.Async.callbacks("EncryptedRemoteObject.removeValue", [
307 MochiKit.Base.method(this, '_getObjectDataStore'),
308 MochiKit.Base.methodcaller('removeValue', aKey)
309 ], {trace:false});
310 },
311
312 //.........................................................................
313
314 'values': function () {
315 return Clipperz.Async.callbacks("EncryptedRemoteObject.values", [
316 MochiKit.Base.method(this, '_getObjectDataStore'),
317 MochiKit.Base.methodcaller('values')
318 ], {trace:false});
319 },
320
321 'setValues': function (someValues) {
322 return Clipperz.Async.callbacks("EncryptedRemoteObject.values", [
323 MochiKit.Base.method(this, '_getObjectDataStore'),
324 MochiKit.Base.methodcaller('setValues', someValues)
325 ], {trace:false});
326 },
327
328 //.........................................................................
329
330 '_getObjectDataStore': function () {
331 var deferredResult;
332 var deferredLock;
333
334 deferredLock = this.getDeferredLockForKey('objectDataStore');
335
336 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject._getObjectDataStore", {trace:false});
337 deferredResult.acquireLock(deferredLock);
338 deferredResult.addCallback(MochiKit.Base.bind(function () {
339 var innerDeferredResult;
340
341 if (this._objectDataStore == null) {
342 this._objectDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.objectDataStore [4]'}*/);
343
344 innerDeferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject._getObjectDataStore <inner deferred>", {trace:false});
345 innerDeferredResult.addMethod(this, 'getDecryptedData');
346 innerDeferredResult.addMethod(this._objectDataStore, 'initWithValues');
347 innerDeferredResult.callback();
348 } else {
349 innerDeferredResult = MochiKit.Async.succeed(this._objectDataStore);
350 }
351
352 return innerDeferredResult;
353 }, this));
354 deferredResult.releaseLock(deferredLock);
355 deferredResult.callback();
356
357 return deferredResult;
358 },
359
360 'hasInitiatedObjectDataStore': function () {
361 return (this._objectDataStore != null);
362 },
363
364 //-------------------------------------------------------------------------
365
366 'getDeferredLockForKey': function (aKey) {
367 var result;
368
369 result = this._deferredLocks[aKey];
370
371 if (typeof(result) == 'undefined') {
372 result = new MochiKit.Async.DeferredLock();
373 this._deferredLocks[aKey] = result;
374 }
375
376 return result;
377 },
378
379 //-------------------------------------------------------------------------
380
381 'unpackData': function (someData) { //++
382 return someData;
383 },
384
385 'packData': function (someData) { //++
386 return someData;
387 },
388
389 //-------------------------------------------------------------------------
390
391 'hasPendingChanges': function () {
392 var deferredResult;
393 var tempObj = this;
394
395 if (this.isBrandNew()) {
396 // deferredResult = MochiKit.Async.succeed(true);
397 deferredResult = this.hasPendingChangesWhenBrandNew();
398 } else if (this.hasInitiatedObjectDataStore()) {
399 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.hasPendingChanges", {trace:false});
400 deferredResult.collectResults({
401 'decryptedData': [
402 MochiKit.Base.method(this, 'getDecryptedData'),
403 Clipperz.Base.serializeJSON
404 ],
405 'objectData': [
406 MochiKit.Base.method(this, '_getObjectDataStore'),
407 MochiKit.Base.methodcaller('values'),
408 Clipperz.Base.serializeJSON
409 ]
410 });
411 deferredResult.addCallback(function (someValues) {
412 return (someValues['decryptedData'] != someValues['objectData']);
413 });
414 deferredResult.callback();
415 } else {
416 deferredResult = MochiKit.Async.succeed(false);
417 }
418
419 return deferredResult;
420 },
421
422 'hasPendingChangesWhenBrandNew': function () {
423 return MochiKit.Async.succeed(true);
424 },
425
426 //-------------------------------------------------------------------------
427
428 'commitTransientState': function () {
429 var deferredResult;
430
431 // if (this.transientState().getValue('__prepareRemoteData') == true) {
432 if (this.transientState().getValue('packedRemoteData') != null) {
433 deferredResult = Clipperz.Async.callbacks("EncryptedRemoteObject.commitTransientState - prepareRemoteData", [
434 MochiKit.Base.bind(function (someData) {
435 this._remoteData = this.transientState().getValue('packedRemoteData');
436 }, this),
437
438 MochiKit.Base.method(this, '_getObjectDataStore'),
439 MochiKit.Base.methodcaller('values'),
440 Clipperz.Base.deepClone,
441 MochiKit.Base.method(this.decryptedDataStore(), 'setValue', 'decryptedData'),
442
443 MochiKit.Base.method(this, 'resetTransientState', true)
444 ], {trace:false});
445
446 } else {
447 deferredResult = Clipperz.Async.callbacks("EncryptedRemoteObject.commitTransientState - NO prepareRemoteData", [
448 MochiKit.Base.method(this, 'resetTransientState', true)
449 ], {trace:false});
450 }
451
452 this._isBrandNew = false;
453
454 return deferredResult;
455 },
456
457 //-------------------------------------------------------------------------
458
459 'revertChanges': function () {
460 if (this.hasInitiatedObjectDataStore()) {
461 this._objectDataStore.removeAllData();
462 this._objectDataStore = null;
463 }
464 this.resetTransientState(false);
465
466 return MochiKit.Async.succeed();
467 },
468
469 //-------------------------------------------------------------------------
470
471 'deleteAllCleanTextData': function () {
472 var deferredResult;
473
474 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.deleteAllCleanTextData", {trace:false});
475
476 deferredResult.addMethod(this, 'resetTransientState', false);
477
478 deferredResult.acquireLock(this.getDeferredLockForKey('decryptedData'));
479 deferredResult.addCallback(MochiKit.Base.bind(function () {
480 if (this._decryptedDataStore != null) {
481 this._decryptedDataStore.removeAllData();
482 }
483 }, this));
484 deferredResult.releaseLock(this.getDeferredLockForKey('decryptedData'));
485
486 deferredResult.acquireLock(this.getDeferredLockForKey('objectDataStore'));
487 deferredResult.addCallback(MochiKit.Base.bind(function () {
488 if (this._objectDataStore != null) {
489 this._objectDataStore.removeAllData();
490 this._objectDataStore = null;
491 }
492 }, this));
493 deferredResult.releaseLock(this.getDeferredLockForKey('objectDataStore'));
494
495 deferredResult.callback();
496
497 return deferredResult;
498 },
499
500 //.........................................................................
501
502 'hasAnyCleanTextData': function () {
503 var result;
504
505 result = false;
506
507 result = result || (! this.decryptedDataStore().isEmpty());
508 result = result || (! this.transientState().isEmpty());
509 if (this.hasInitiatedObjectDataStore()) {
510 result = result || (! this._objectDataStore.isEmpty());
511 }
512
513 return MochiKit.Async.succeed(result);
514 },
515
516 //-------------------------------------------------------------------------
517
518 'prepareRemoteDataWithKey': function (aKey) {
519 return Clipperz.Async.callbacks("EncryptedRemoteObject.prepareRemoteDataWithKey", [
520 // MochiKit.Base.method(this.transientState(), 'setValue', '__prepareRemoteData', true),
521 MochiKit.Base.method(this, '_getObjectDataStore'),
522 MochiKit.Base.methodcaller('values'),
523 MochiKit.Base.method(this, 'packData'),
524 function (someData) {
525 return Clipperz.PM.Crypto.deferredEncrypt({
526 'key': aKey,
527 'value':someData,
528 'version':Clipperz.PM.Crypto.encryptingFunctions.currentVersion
529 })
530 },
531 MochiKit.Base.method(this, 'packRemoteData'),
532 MochiKit.Base.method(this.transientState(), 'setValue', 'packedRemoteData'),
533 function (someData) {
534 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'advanceProgress');
535 return someData;
536 }
537 ], {trace:false});
538 },
539
540 //-------------------------------------------------------------------------
541 __syntaxFix__: "syntax fix"
542});