summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/PM/DataModel
Unidiff
Diffstat (limited to 'frontend/delta/js/Clipperz/PM/DataModel') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DirectLogin.js1086
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DirectLoginBinding.js120
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DirectLoginFormValue.js101
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DirectLoginInput.js192
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js542
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/OneTimePassword.js350
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/Record.Version.Field.js186
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js328
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/Record.js891
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Header.Legacy.js182
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js117
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Header.Preferences.js48
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js685
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Subscription.js53
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.js827
15 files changed, 5708 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DirectLogin.js b/frontend/delta/js/Clipperz/PM/DataModel/DirectLogin.js
new file mode 100644
index 0000000..8db90de
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DirectLogin.js
@@ -0,0 +1,1086 @@
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
24Clipperz.Base.module('Clipperz.PM.DataModel');
25
26Clipperz.PM.DataModel.DirectLogin = function(args) {
27 args = args || {};
28
29 Clipperz.PM.DataModel.DirectLogin.superclass.constructor.apply(this, arguments);
30
31 this._reference =args.reference
32 ||Clipperz.PM.Crypto.randomKey();
33 this._record =args.record
34 ||Clipperz.Base.exception.raise('MandatoryParameter');
35
36 this._retrieveIndexDataFunction = args.retrieveIndexDataFunction
37 ||this.record().retrieveDirectLoginIndexDataFunction()
38 ||Clipperz.Base.exception.raise('MandatoryParameter');
39 this._setIndexDataFunction = args.setIndexDataFunction
40 ||this.record().setDirectLoginIndexDataFunction()
41 ||Clipperz.Base.exception.raise('MandatoryParameter');
42 this._removeIndexDataFunction =args.removeIndexDataFunction
43 ||this.record().removeDirectLoginIndexDataFunction()
44 ||Clipperz.Base.exception.raise('MandatoryParameter');
45
46 this._inputs = null;
47 this._bindings = null;
48 this._formValues = null;
49
50 // this._inputsDeferredLock = new MochiKit.Async.DeferredLock();
51 // this._bindingsDeferredLock = new MochiKit.Async.DeferredLock();
52 // this._formValuesDeferredLock = new MochiKit.Async.DeferredLock();
53
54 this._transientState = null;
55
56 this._isBrandNew = MochiKit.Base.isUndefinedOrNull(args.reference);
57
58 this.record().addDirectLogin(this);
59
60 return this;
61}
62
63Clipperz.Base.extend(Clipperz.PM.DataModel.DirectLogin, Object, {
64
65 'toString': function() {
66 return "DirectLogin (" + this.reference() + ")";
67 },
68
69 //=========================================================================
70
71 'reference': function () {
72 return this._reference;
73 },
74
75 //-------------------------------------------------------------------------
76
77 'record': function () {
78 return this._record;
79 },
80
81 //=========================================================================
82
83 'isBrandNew': function () {
84 return this._isBrandNew;
85 },
86
87 //=========================================================================
88
89 'removeIndexDataFunction': function () {
90 return this._removeIndexDataFunction;
91 },
92
93 'remove': function () {
94 return Clipperz.Async.callbacks("DirectLogin.remove", [
95 MochiKit.Base.partial(this.removeIndexDataFunction(), this.reference()),
96 MochiKit.Base.method(this.record(), 'removeDirectLogin', this)
97 ], {trace:false});
98 },
99
100 //=========================================================================
101 /*
102 'inputsDeferredLock': function () {
103 return this._inputsDeferredLock;
104 },
105
106 'bindingsDeferredLock': function () {
107 return this._bindingsDeferredLock;
108 },
109
110 'formValuesDeferredLock': function () {
111 return this._formValuesDeferredLock;
112 },
113*/
114 //=========================================================================
115
116 'label': function () {
117 return this.getIndexDataForKey('label');
118 },
119
120 'setLabelKeepingBackwardCompatibilityWithBeta': function (aValue) {
121 return Clipperz.Async.callbacks("DirectLogin.setLabelKeepingBackwardCompatibilityWithBeta", [
122 MochiKit.Base.method(this, 'setIndexDataForKey', 'label', aValue),
123 MochiKit.Base.method(this, 'setValue', 'label', aValue)
124 ], {trace:false});
125 },
126
127 'setLabel': function (aValue) {
128 return this.setLabelKeepingBackwardCompatibilityWithBeta(aValue);
129 // return this.setIndexDataForKey('label', aValue);
130 },
131
132 //=========================================================================
133
134 'favicon': function () {
135 return this.getIndexDataForKey('favicon');
136 },
137
138 'setFavicon': function (aValue) {
139 return this.setIndexDataForKey('favicon', aValue);
140 },
141
142 'faviconUrlWithBookmarkletConfiguration': function (aBookmarkletConfiguration) {
143 varresult;
144
145 if (! MochiKit.Base.isUndefinedOrNull(aBookmarkletConfiguration['page']['favicon'])) {
146 result = aBookmarkletConfiguration['page']['favicon'];
147 } else if (! MochiKit.Base.isUndefinedOrNull(aBookmarkletConfiguration['form']['attributes']['action'])) {
148 var actionUrl;
149 var hostname;
150
151 actionUrl = aBookmarkletConfiguration['form']['attributes']['action'];
152 hostname = actionUrl.replace(/^https?:\/\/([^\/]*)\/.*/, '$1');
153 result = "http://" + hostname + "/favicon.ico";
154 } else {
155 result = null;
156 }
157
158
159 return result;
160 },
161
162 //-------------------------------------------------------------------------
163/*
164 'faviconData': function () {
165 var regexp = new RegExp('^data\:\/\/.*', 'i');
166
167 return Clipperz.Async.callbacks("DirectLogin.favicon", [
168 MochiKit.Base.method(this, 'getIndexDataForKey', 'favicon'),
169 MochiKit.Base.method(regexp, 'test'),
170 Clipperz.Async.deferredIf("is data URL", [
171 MochiKit.Base.method(this, 'getIndexDataForKey', 'favicon')
172 ], [
173 MochiKit.Base.method(this, 'transientState'),
174 MochiKit.Base.itemgetter('faviconData'),
175 Clipperz.Async.deferredIf('has a chaced value for the favicon data', [
176 MochiKit.Base.operator.identity
177 ], [
178 MochiKit.Base.method(this, 'getIndexDataForKey', 'favicon'),
179 MochiKit.Base.method(this, 'loadFaviconDataFromURL')
180 ])
181
182 ])
183 ], {trace:false});
184 },
185
186 //-------------------------------------------------------------------------
187
188 'loadFaviconDataFromURL': function (anURL) {
189 var deferredResult;
190 var image;
191
192 deferredResult = new Clipperz.Async.Deferred("DirectLogin.loadFaviconDataFromURL", {trace:false});
193 deferredResult.addCallback(function (anEvent) {
194 var image = anEvent.src();
195 var canvas = document.createElement("canvas");
196 var result;
197
198 canvas.width = image.width;
199 canvas.height = image.height;
200
201 var ctx = canvas.getContext("2d");
202 ctx.drawImage(image, 0, 0);
203
204 result = canvas.toDataURL(/*"image/png"* /);
205
206 return result;
207 });
208 deferredResult.addErrback(MochiKit.Async.succeed, Clipperz.PM.Strings.getValue('defaultFaviconUrl'));
209 deferredResult.addBoth(MochiKit.Base.bind(function (aDataUrl) {
210 this.transientState()['faviconData'] = aDataUrl;
211
212 return aDataUrl;
213 }, this));
214
215 image = new Image();
216 MochiKit.Signal.connect(image, 'onload', MochiKit.Base.method(deferredResult, 'callback'));
217 MochiKit.Signal.connect(image, 'onerror', MochiKit.Base.method(deferredResult, 'errback'));
218 MochiKit.Signal.connect(image, 'onabort', MochiKit.Base.method(deferredResult, 'errback'));
219
220 image.src = anURL;
221
222 return deferredResult;
223 },
224*/
225
226 //=========================================================================
227
228 'type': function () {
229 return this.getValue('formData.attributes.type')
230 },
231
232 //=========================================================================
233
234 'serializedData': function () {
235 return Clipperz.Async.collectResults("DirectLogin.serializedData", {
236 'bookmarkletVersion': MochiKit.Base.method(this, 'getValue', 'bookmarkletVersion'),
237 'formData': MochiKit.Base.method(this, 'getValue', 'formData'),
238 'formValues': MochiKit.Base.method(this, 'getValue', 'formValues'),
239 'bindingData': [
240 MochiKit.Base.method(this, 'bindings'),
241 function (someBindings) {
242 var result;
243 var bindingKey;
244
245 result = {}
246 for (bindingKey in someBindings) {
247 result[bindingKey] = someBindings[bindingKey].serializedData();
248 }
249
250 return result;
251 }
252 ]
253 }, {trace:false})()
254 },
255
256 //=========================================================================
257/*
258 'fixFormDataFromBookmarkletVersion_0_1': function(aValue) {
259//{"type":"radio", "name":"action", "value":"new-user", "checked":false }, { "type":"radio", "name":"action", "value":"sign-in", "checked":true }
260 // ||
261 // \ /
262 // \/
263//{"name":"dominio", "type":"radio", "options":[{"value":"@alice.it", "checked":true}, {"value":"@tin.it", "checked":false}, {"value":"@virgilio.it", "checked":false}, {"value":"@tim.it", "checked":false}]}
264 var result;
265 var inputs;
266 var updatedInputs;
267 var radios;
268
269 result = aValue;
270 inputs = aValue['inputs'];
271
272 updatedInputs = MochiKit.Base.filter(function(anInput) {
273 varresult;
274 var type;
275
276 type = anInput['type'] || 'text';
277 result = type.toLowerCase() != 'radio';
278
279 return result;
280 }, inputs);
281 radios = MochiKit.Base.filter(function(anInput) {
282 varresult;
283 var type;
284
285 type = anInput['type'] || 'text';
286 result = type.toLowerCase() == 'radio';
287
288 return result;
289 }, inputs);
290
291 if (radios.length > 0) {
292 var updatedRadios;
293
294 updatedRadios = {};
295 MochiKit.Iter.forEach(radios, MochiKit.Base.bind(function(aRadio) {
296 varradioConfiguration;
297
298 radioConfiguration = updatedRadios[aRadio['name']];
299 if (radioConfiguration == null) {
300 radioConfiguration = {type:'radio', name:aRadio['name'], options:[]};
301 updatedRadios[aRadio['name']] = radioConfiguration;
302 }
303
304 //TODO: remove the value: field and replace it with element.dom.value = <some value>
305 radioConfiguration.options.push({value:aRadio['value'], checked:aRadio['checked']});
306
307 //TODO: shoud remove the 'formValues' call, as it is now deferred
308 // if ((aRadio['checked'] == true) && (this.formValues()[aRadio['name']] == null)) {
309 // this.formValues()[aRadio['name']] = aRadio['value'];
310 // }
311 }, this))
312
313 updatedInputs = MochiKit.Base.concat(updatedInputs, MochiKit.Base.values(updatedRadios));
314 }
315
316 delete result.inputs;
317 result.inputs = updatedInputs;
318
319 return result;
320 },
321
322 '_fixConfiguration': function (aConfiguration) {
323 var fixedConfiguration;
324 // var inputs;
325 // var bindings;
326 // var i,c;
327
328 fixedConfiguration = Clipperz.Base.deepClone(aConfiguration);
329
330//Clipperz.log("PROCESS CONFIGURATION", aConfiguration);
331 switch (aConfiguration['bookmarkletVersion']) {
332 case '0.1':
333 fixedConfiguration['formData'] = this.fixFormDataFromBookmarkletVersion_0_1(aConfiguration['formData']);
334 break;
335 case '0.2':
336 fixedConfiguration['formData'] = aConfiguration['formData'];
337 break;
338 }
339
340 / *
341 aConfiguration['_inputs'] = [];
342 c = formData['inputs'].length;
343 for (i=0; i<c; i++) {
344 aConfiguration['_inputs'].push(new Clipperz.PM.DataModel.DirectLoginInput(formData['inputs'][i]));
345 }
346* /
347/ *
348 aConfiguration['_bindings'] = {};
349 if (aConfiguration['legacyBindingData'] == null) {
350 if (aConfiguration['bindingData'] != null) {
351 var bindingKey;
352
353 for (bindingKey in aConfiguration['bindingData']) {
354 var newBinding;
355
356 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(bindingKey, {fieldKey:aConfiguration['bindingData'][bindingKey]});
357 aConfiguration['_bindings'][newBinding.key()] = newBinding;
358 }
359 } else {
360 var editableFields;
361
362 editableFields = MochiKit.Base.filter(function(aField) {
363 var result;
364 var type;
365
366 type = aField['type'].toLowerCase();
367 result = ((type != 'hidden') && (type != 'submit') && (type != 'checkbox') && (type != 'radio') && (type != 'select'));
368
369 return result;
370 }, aConfiguration['_inputs']);
371
372 MochiKit.Iter.forEach(editableFields, MochiKit.Base.bind(function(anEditableField) {
373 var newBinding;
374
375 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(anEditableField['name']);
376 aConfiguration['_bindings'][newBinding.key()] = newBinding;
377 }, this));
378 }
379
380 } else {
381 var bindingKey;
382
383 for (bindingKey in aConfiguration['legacyBindingData']) {
384 var newBinding;
385
386 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(bindingKey, {fieldName:aConfiguration['legacyBindingData'][bindingKey]});
387 aConfiguration['_bindings'][newBinding.key()] = newBinding;
388 }
389 }
390* /
391
392 return fixedConfiguration;
393 },
394
395 //-------------------------------------------------------------------------
396
397 'getObjectDataStore': function () {
398 var deferredResult;
399
400 deferredResult = new Clipperz.Async.Deferred("DirectLogin.getObjectDataStore", {trace:false});
401 deferredResult.acquireLock(this.objectDataStoreDeferredLock());
402 deferredResult.addCallback(MochiKit.Base.bind(function () {
403 var innerDeferredResult;
404
405 if (this._objectDataStore == null) {
406 this._objectDataStore = new Clipperz.KeyValueObjectStore();
407
408 innerDeferredResult = new Clipperz.Async.Deferred("DirectLogin.getObjectDataStore <inner deferred>", {trace:false});
409 // innerDeferredResult.addMethod(this.record(), 'getValue', 'directLogins' + '.' + this.reference());
410 innerDeferredResult.addMethod(this, 'getValue', ''),
411 innerDeferredResult.addMethod(this, 'setOriginalState');
412 innerDeferredResult.addMethod(this, '_fixConfiguration');
413 innerDeferredResult.addMethod(this._objectDataStore, 'initWithValues');
414 // innerDeferredResult.addMethod(this._objectDataStore, 'setValues');
415 innerDeferredResult.callback();
416 } else {
417 innerDeferredResult = MochiKit.Async.succeed(this._objectDataStore);
418 }
419
420 return innerDeferredResult;
421 }, this));
422 deferredResult.releaseLock(this.objectDataStoreDeferredLock());
423 deferredResult.callback();
424
425 return deferredResult;
426 },
427
428 //-------------------------------------------------------------------------
429
430 'hasInitiatedObjectDataStore': function () {
431 return (this._objectDataStore != null);
432 },
433
434 //-------------------------------------------------------------------------
435
436 'resetObjectDataStore': function () {
437 this._objectDataStore.removeAllData();
438 this._objectDataStore = null;
439 },
440*/
441 //=========================================================================
442
443 'bookmarkletConfiguration': function () {
444 return Clipperz.Async.callbacks("DirectLogin.bookmarkletConfiguration", [
445 Clipperz.Async.collectResults("DirectLogin.bookmarkletConfiguration <inner results>", {
446 'label': MochiKit.Base.method(this, 'label'),
447 'configuration': MochiKit.Base.method(this, 'getValue', '')
448 }, {trace:false}),
449 function (someValues) {
450 var result;
451
452 if (someValues['configuration'] != null) {
453 varconfiguration;
454
455 configuration = {
456 'page': {
457 'title': someValues['label']
458 //'favicon'
459 // 'url'
460 },
461 'form': someValues['configuration']['formData'],
462 'version':someValues['configuration']['bookmarkletVersion']
463 }
464
465 result = Clipperz.Base.formatJSON(configuration);
466 } else {
467 result = '';
468 }
469
470 return result;
471 }
472 ], {trace:false});
473
474 },
475
476 //-------------------------------------------------------------------------
477
478 'setBookmarkletConfiguration': function (aValue) {
479 var bookmarkletConfiguration;
480
481 bookmarkletConfiguration = Clipperz.PM.DataModel.DirectLogin.checkBookmarkletConfiguration(aValue);
482
483 return Clipperz.Async.callbacks("DirectLogin.setBookmarkletConfiguration", [
484 MochiKit.Base.method(this, 'setValue', 'formData', bookmarkletConfiguration['form']),
485 MochiKit.Base.method(this, 'setValue', 'bookmarkletVersion', bookmarkletConfiguration['version']),
486
487 MochiKit.Base.method(this, 'favicon'),
488 Clipperz.Async.deferredIf("the favicon is not set", [
489 ], [
490 MochiKit.Base.method(this, 'faviconUrlWithBookmarkletConfiguration', bookmarkletConfiguration),
491 MochiKit.Base.method(this, 'setFavicon')
492 ]),
493
494 MochiKit.Base.method(this, 'updateInputsAfterChangingBookmarkletConfiguration'),
495 MochiKit.Base.method(this, 'updateFormValuesAfterChangingBookmarkletConfiguration'),
496 MochiKit.Base.method(this, 'updateBindingsAfterChangingBookmarkletConfiguration'),
497
498 MochiKit.Base.noop
499 ], {trace:false});
500 },
501
502 //=========================================================================
503
504 'formAttributes': function () {
505 return this.getValue('formData.attributes');
506 },
507
508 //=========================================================================
509
510 'inputs': function () {
511 return Clipperz.Async.callbacks("DirectLogin.inputs", [
512 Clipperz.Async.deferredIf("this._inputs is defined", [
513 ], [
514 MochiKit.Base.method(this, 'updateInputsAfterChangingBookmarkletConfiguration')
515 ])
516 ], {trace:false}, this._inputs);
517 },
518
519 'setInputWithFormDataConfiguration': function (aFormDataConfiguration) {
520 this._inputs = {};
521
522 if (aFormDataConfiguration != null) {
523 MochiKit.Iter.forEach(aFormDataConfiguration['inputs'], MochiKit.Base.bind(function (anInputData) {
524 var newInput;
525
526 newInput = new Clipperz.PM.DataModel.DirectLoginInput(anInputData);
527 this._inputs[newInput.name()] = newInput;
528 }, this));
529 }
530
531 return this._inputs;
532 },
533
534 'updateInputsAfterChangingBookmarkletConfiguration': function () {
535 return Clipperz.Async.callbacks("DirectLogin.updateInputsAfterChangingBookmarkletConfiguration", [
536 MochiKit.Base.method(this, 'getValue', 'formData'),
537 MochiKit.Base.method(this, 'setInputWithFormDataConfiguration')
538 ], {trace:false});
539 },
540
541 //=========================================================================
542
543 'inputValues': function () {
544 return Clipperz.Async.callbacks("DirectLogin.inputValues", [
545 MochiKit.Base.method(this, 'inputs'),
546 MochiKit.Base.values,
547 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.partial(MochiKit.Base.method(this, 'inputValue'))),
548 Clipperz.Async.collectAll,
549 Clipperz.Base.mergeItems
550 ], {trace:false});
551 },
552
553 'inputValue': function (anInput) {
554 vardeferredResult;
555
556 deferredResult = new Clipperz.Async.Deferred("DirectLogin.inputValue", {trace:false});
557
558 if (anInput.needsFormValue()) {
559 deferredResult.addMethod(this, 'formValues');
560 deferredResult.addCallback(MochiKit.Base.itemgetter(anInput.name()));
561 deferredResult.addMethodcaller('value');
562 } else if (anInput.needsBinding()) {
563 deferredResult.addMethod(this, 'bindings');
564 deferredResult.addCallback(MochiKit.Base.itemgetter(anInput.name()));
565 deferredResult.addMethodcaller('field');
566 deferredResult.addMethodcaller('value');
567 } else {
568 deferredResult.addCallback(MochiKit.Async.succeed, anInput.value());
569 }
570 deferredResult.addCallback(function (anActualValue) {
571 return [anInput.name(), anActualValue];
572 });
573
574 deferredResult.callback();
575
576 return deferredResult;
577 },
578
579 //=========================================================================
580
581 'bindings': function () {
582 return Clipperz.Async.callbacks("DirectLogin.bindings", [
583 Clipperz.Async.deferredIf("this._bindings is defined", [
584 ], [
585 MochiKit.Base.method(this, 'updateBindingsAfterChangingBookmarkletConfiguration'),
586 MochiKit.Base.bind(function () { return this._bindings;}, this)
587 ])
588 ], {trace:false}, this._bindings);
589 },
590
591 'bindFormFieldWithLabelToRecordFieldWithLabel': function (aFormFieldLabel, aRecordFieldLabel) {
592 return Clipperz.Async.callbacks("DirectLogin.bindFormFieldWithLabelToCardFieldWithLabel", [
593 Clipperz.Async.collectResults("DirectLogin.bindFormFieldWithLabelToCardFieldWithLabel - collect results", {
594 'binding': [
595 MochiKit.Base.method(this, 'bindings'),
596 MochiKit.Base.itemgetter(aFormFieldLabel)
597 ],
598 'field': [
599 MochiKit.Base.method(this.record(), 'fieldWithLabel', aRecordFieldLabel)
600 ]
601 }),
602 function (someValues) {
603 someValues['binding'].setField(someValues['field'])
604 }
605 ], {trace:false});
606 },
607
608 //-------------------------------------------------------------------------
609/*
610 'bindingValues': function () {
611 return Clipperz.Async.callbacks("DirectLogin.bindingValues", [
612 Clipperz.Async.collectResults("DirectLogin.bindingValues [collectResults]", {
613 'fieldValues': [
614 MochiKit.Base.method(this, 'record'),
615 MochiKit.Base.methodcaller('getFieldsValues')
616 ],
617 'bindings': MochiKit.Base.method(this, 'bindings')
618 }, {trace:false}),
619 function (someData) {
620 var result;
621 varbindingKey;
622
623 result = {};
624 for (bindingKey in someData['bindings']) {
625 result[bindingKey] = someData['fieldValues'][someData['bindings'][bindingKey].fieldKey()]['value'];
626 }
627
628 return result;
629 }
630 ], {trace:false});
631 },
632*/
633 //-------------------------------------------------------------------------
634
635 'updateBindingsAfterChangingBookmarkletConfiguration': function () {
636 return Clipperz.Async.callbacks("DirectLogin.updateBindingsAfterChangingBookmarkletConfiguration", [
637 Clipperz.Async.collectResults("DirectLogin.updateBindingsAfterChangingBookmarkletConfiguration<collect results>", {
638 'currentValues':MochiKit.Base.method(this, 'getValue', ''),
639 'originalValues':MochiKit.Base.method(this, 'originalConfiguration'),
640 'inputs': MochiKit.Base.method(this, 'inputs')
641 }, {trace:false}),
642 MochiKit.Base.bind(function (someValues) {
643 var availableBindingValues;
644 var inputRequiringBindingValues;
645 var newBindingValues;
646
647 if (MochiKit.Base.isUndefinedOrNull(someValues['originalValues']) || MochiKit.Base.isUndefinedOrNull(someValues['originalValues']['bindingData'])) {
648 availableBindingValues = {};
649 } else {
650 availableBindingValues = Clipperz.Base.deepClone(someValues['originalValues']['bindingData'])
651 }
652
653 if (someValues['currentValues'] != null) {
654 MochiKit.Base.update(availableBindingValues, someValues['currentValues']['bindingData']);
655 }
656
657 this._bindings = {};
658 newBindingValues = {}
659 MochiKit.Iter.forEach(MochiKit.Base.filter(MochiKit.Base.methodcaller('needsBinding'), MochiKit.Base.values(someValues['inputs'])), MochiKit.Base.bind(function (anInput) {
660 varnewBinding;
661
662 newBindingValues[anInput.name()] = availableBindingValues[anInput.name()];
663 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(this, {
664 'key': anInput.name(),
665 'field':availableBindingValues[anInput.name()]
666 });
667
668 this._bindings[anInput.name()] = newBinding;
669 }, this))
670
671 return newBindingValues;
672
673/*
674 this._bindings = {};
675
676 if (someValues['currentValues'] != null) {
677 if (someValues['currentValues']['bindingData'] != null) {
678 var bindingKey;
679
680 for (bindingKey in someValues['currentValues']['bindingData']) {
681 var newBinding;
682
683 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(this, {
684 'key': bindingKey,
685 'field':someValues['currentValues']['bindingData'][bindingKey]
686 });
687 this._bindings[newBinding.key()] = newBinding;
688 }
689 } else if (someValues['currentValues']['legacyBindingData'] == null) {
690 var bindingKey;
691
692 for (bindingKey in someValues['currentValues']['legacyBindingData']) {
693 var newBinding;
694
695 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(this, {
696 'key': bindingKey,
697 'field':someValues['currentValues']['legacyBindingData'][bindingKey]
698 });
699 this._bindings[newBinding.key()] = newBinding;
700 }
701 } else {
702 WTF = TODO;
703 }
704 }
705
706 return this._bindings;
707*/
708 }, this),
709 MochiKit.Base.method(this, 'setValue', 'bindingData')
710 ], {trace:false});
711 },
712
713 //=========================================================================
714
715 'formValues': function () {
716 return Clipperz.Async.callbacks("DirectLogin.formValues", [
717 Clipperz.Async.deferredIf("this._formValues is defined", [
718 ], [
719 MochiKit.Base.method(this, 'updateFormValuesAfterChangingBookmarkletConfiguration'),
720 MochiKit.Base.bind(function () { return this._formValues;}, this)
721 ])
722 ], {trace:false}, this._formValues);
723 },
724
725 //-------------------------------------------------------------------------
726
727 'updateFormValuesAfterChangingBookmarkletConfiguration': function () {
728 return Clipperz.Async.callbacks("DirectLogin.updateFormValuesAfterChangingBookmarkletConfiguration", [
729 Clipperz.Async.collectResults("DirectLogin.updateFormValuesAfterChangingBookmarkletConfiguration <collect results>", {
730 'currentValues':MochiKit.Base.method(this, 'getValue', ''),
731 'originalValues':MochiKit.Base.method(this, 'originalConfiguration'),
732 'inputs': MochiKit.Base.method(this, 'inputs')
733 }, {trace:false}),
734 MochiKit.Base.bind(function (someValues) {
735 var availableFormValues;
736 var inputRequiringFormValues;
737 var newFormValues;
738
739 if (MochiKit.Base.isUndefinedOrNull(someValues['originalValues']) || MochiKit.Base.isUndefinedOrNull(someValues['originalValues']['formValues'])) {
740 availableFormValues = {};
741 } else {
742 availableFormValues = Clipperz.Base.deepClone(someValues['originalValues']['formValues'])
743 }
744
745 MochiKit.Base.update(availableFormValues, someValues['currentValues']['formValues']);
746
747 this._formValues = {};
748 newFormValues = {};
749 MochiKit.Iter.forEach(MochiKit.Base.filter(MochiKit.Base.methodcaller('needsFormValue'), MochiKit.Base.values(someValues['inputs'])), MochiKit.Base.bind(function (anInput) {
750 varnewFormValue;
751 var fieldOptions;
752
753 fieldOptions = {
754 'type': anInput.type(),
755 'options':anInput.options()
756 };
757
758 newFormValues[anInput.name()] = availableFormValues[anInput.name()]
759 newFormValue = new Clipperz.PM.DataModel.DirectLoginFormValue(this, {
760 'key': anInput.name(),
761 'fieldOptions':fieldOptions,
762 'value': availableFormValues[anInput.name()]
763 });
764
765 this._formValues[anInput.name()] = newFormValue;
766 }, this))
767
768 return newFormValues;
769 }, this),
770 MochiKit.Base.method(this, 'setValue', 'formValues')
771 ], {trace:false});
772 },
773
774 //=========================================================================
775
776 'retrieveIndexDataFunction': function () {
777 return this._retrieveIndexDataFunction;
778 },
779
780 'getIndexDataForKey': function (aKey) {
781 return Clipperz.Async.callbacks("DirectLogin.getIndexDataForKey", [
782 MochiKit.Base.partial(this.retrieveIndexDataFunction(), this.reference()),
783 Clipperz.Async.deferredIf("DirectLogin.getIndexDataForKey - index data not null", [
784 MochiKit.Base.itemgetter(aKey)
785 ],[
786 MochiKit.Async.succeed
787 ])
788 ], {trace:false});
789 },
790
791 //-------------------------------------------------------------------------
792
793 'setIndexDataForKey': function (aKey, aValue) {
794 return Clipperz.Async.callbacks("DirectLogin.setValueForKey", [
795 MochiKit.Base.method(this, 'getIndexDataForKey', aKey),
796 MochiKit.Base.bind(function (anActualValue) {
797 var transientStateKey;
798
799 transientStateKey = 'original_' + aKey;
800 if (MochiKit.Base.isUndefinedOrNull(this.transientState()[transientStateKey])) {
801 if (anActualValue != aValue) {
802 this.transientState()[transientStateKey] = anActualValue;
803 }
804 } else if (this.transientState()[transientStateKey] == aValue) {
805 this.transientState()[transientStateKey] = null;
806 }
807 }, this),
808 MochiKit.Base.partial(this._setIndexDataFunction, this.reference(), aKey, aValue)
809 ], {trace:false})
810 },
811
812 //-------------------------------------------------------------------------
813/*
814 'setValueForKey': function (aKey, aValue) {
815 return Clipperz.Async.callbacks("DirectLogin.setValueForKey", [
816 MochiKit.Base.method(this, 'getIndexDataForKey', aKey),
817 MochiKit.Base.bind(function (anActualValue) {
818 var transientStateKey;
819
820 transientStateKey = 'original_' + aKey;
821 if (MochiKit.Base.isUndefinedOrNull(this.transientState()[transientStateKey])) {
822 if (anActualValue != aValue) {
823 this.transientState()[transientStateKey] = anActualValue;
824 }
825 } else if (this.transientState()[transientStateKey] == aValue) {
826 this.transientState()[transientStateKey] = null;
827 }
828 }, this),
829 MochiKit.Base.method(this, 'setIndexDataForKey', aKey, aValue)
830 ], {trace:false})
831 },
832*/
833 //=========================================================================
834/*
835 'storedConfiguration': function () {
836 return this.record().getValue('directLogins' + '.' + this.reference());
837 },
838
839 //'setStoredConfiguration': function (aValue) {
840 // return this.record().setValue('directLogins' + '.' + this.reference(), aValue);
841 //},
842*/
843 //=========================================================================
844
845 'hasPendingChanges': function () {
846 varresult;
847 var deferredResult;
848
849 result = false;
850 result = result || this.isBrandNew();
851 result = result || (! MochiKit.Base.isUndefinedOrNull(this.transientState()['original_label']));
852 result = result || (! MochiKit.Base.isUndefinedOrNull(this.transientState()['original_favicon']));
853
854 if ((result == false) && (this.originalConfiguration() != null)) {
855 deferredResult = Clipperz.Async.callbacks("DirectLogin.hasPendingChanges", [
856 MochiKit.Base.method(this, 'serializedData'),
857 MochiKit.Base.bind(function (aCurrentConfiguration) {
858 varoriginalConfiguration;
859 var currentConfiguration;
860 var result;
861
862 originalConfiguration = this.originalConfiguration();
863 currentConfiguration = aCurrentConfiguration;
864
865 result = false;
866 result = result || (MochiKit.Base.compare(originalConfiguration['bookmarkletVersion'], currentConfiguration['bookmarkletVersion'])!= 0);
867 result = result || (MochiKit.Base.compare(originalConfiguration['formData'], currentConfiguration['formData']) != 0);
868 result = result || (MochiKit.Base.compare(originalConfiguration['formValues'], currentConfiguration['formValues']) != 0);
869 result = result || (MochiKit.Base.compare(originalConfiguration['bindingData'], currentConfiguration['bindingData']) != 0);
870
871 return result;
872 }, this)
873 ], {trace:false});
874 } else {
875 deferredResult = MochiKit.Async.succeed(result);
876 }
877
878 return deferredResult;
879 },
880
881 //-------------------------------------------------------------------------
882
883 'revertChanges': function () {
884 var deferredResult;
885
886 if (this.transientState()['original_label'] != null) {
887 this.setLabel(this.transientState()['original_label']);
888 }
889
890 if (this.transientState()['original_favicon'] != null) {
891 this.setFavicon(this.transientState()['original_favicon']);
892 }
893
894 if (this.originalConfiguration() != null) {
895 deferredResult = this.setValue('', this.originalConfiguration());
896 } else {
897 deferredResult = MochiKit.Async.succeed();
898 }
899
900 this._inputs = null;
901 this._bindings = null;
902 this._formValues= null;
903
904 this.resetTransientState(false);
905
906/*
907 if (this.hasInitiatedObjectDataStore()) {
908 deferredResult = Clipperz.Async.callbacks("DirectLogin.revertChanges", [
909 // MochiKit.Base.method(this.record(), 'setValue', 'directLogins' + '.' + this.reference(), this.originalState()),
910 MochiKit.Base.method(this, 'setValue', '', this.originalState()),
911 MochiKit.Base.method(this, 'resetObjectDataStore')
912 ], {trace:false})
913 } else {
914 deferredResult = MochiKit.Async.succeed();
915 }
916*/
917 return deferredResult;
918 },
919
920
921 //=========================================================================
922
923 'transientState': function () {
924 if (this._transientState == null) {
925 this._transientState = {}
926 }
927
928 return this._transientState;
929 },
930
931 'resetTransientState': function (isCommitting) {
932 this._transientState = null;
933 },
934
935 'commitTransientState': function (isCommitting) {
936 this._transientState = null;
937 this._isBrandNew = false;
938 },
939
940 //-------------------------------------------------------------------------
941
942 'originalConfiguration': function () {
943 return this.transientState()['original_configuration'];
944 },
945
946 'setOriginalConfiguration': function (aConfiguration) {
947 this.transientState()['original_configuration'] = Clipperz.Base.deepClone(aConfiguration);
948 },
949
950 //=========================================================================
951
952 'actualKey': function (aValueKey) {
953 var actualKey;
954
955 actualKey = 'directLogins' + '.' + this.reference();
956 if (aValueKey != '') {
957 actualKey = actualKey + '.' + aValueKey;
958 }
959
960 return actualKey;
961 },
962
963 //-------------------------------------------------------------------------
964
965 'getValue': function (aValueKey) {
966 return this.record().getValue(this.actualKey(aValueKey));
967 },
968
969 'setValue': function (aValueKey, aValue) {
970 // return this.record().setValue(this.actualKey(aValueKey), aValue);
971
972 return Clipperz.Async.callbacks("DirectLogin.setValue", [
973 MochiKit.Base.method(this, 'getValue', ''),
974 MochiKit.Base.bind(function (aValue) {
975 if (this.originalConfiguration() == null) {
976 this.setOriginalConfiguration(aValue);
977 }
978 }, this),
979 // MochiKit.Base.method(this, 'originalConfiguration'),
980 // Clipperz.Async.deferredIf("originalConfiguration has been set", [
981 // ], [
982 // MochiKit.Base.method(this, 'getValue', ''),
983 // MochiKit.Base.method(this, 'setOriginalConfiguration')
984 // ]),
985 MochiKit.Base.method(this.record(), 'setValue', this.actualKey(aValueKey), aValue)
986 ], {trace:false});
987 },
988
989 'removeValue': function (aValueKey) {
990 // return this.record().removeValue(this.actualKey(aValueKey));
991
992 return Clipperz.Async.callbacks("DirectLogin.setValue", [
993 MochiKit.Base.method(this, 'originalConfiguration'),
994 Clipperz.Async.deferredIf("originalConfiguration has been set", [
995 ], [
996 MochiKit.Base.method(this, 'getValue', ''),
997 MochiKit.Base.method(this, 'setOriginalConfiguration')
998 ]),
999 MochiKit.Base.method(this.record(), 'removeValue', this.actualKey(aValueKey))
1000 ], {trace:false});
1001 },
1002
1003 //=========================================================================
1004
1005 'content': function () {
1006 // return this.serializedData();
1007 // return MochiKit.Async.succeed(this);
1008
1009 var deferredResult;
1010 varfieldValues;
1011
1012 fieldValues = {};
1013 deferredResult = new Clipperz.Async.Deferred("DirectLogin.content", {trace:false});
1014 deferredResult.addMethod(this, 'reference');
1015 deferredResult.addCallback(function (aValue) { fieldValues['reference'] = aValue; });
1016 deferredResult.addMethod(this, 'label');
1017 deferredResult.addCallback(function (aValue) { fieldValues['label'] = aValue; });
1018 deferredResult.addMethod(this, 'favicon');
1019 deferredResult.addCallback(function (aValue) { fieldValues['favicon'] = aValue; });
1020 deferredResult.addCallback(function () { return fieldValues; });
1021 deferredResult.callback();
1022
1023 return deferredResult;
1024 },
1025
1026 //=========================================================================
1027
1028 'deleteAllCleanTextData': function () {
1029 this._inputs = null;
1030 this._bindings = null;
1031 this._formValues = null;
1032
1033 this.resetTransientState();
1034 },
1035
1036 //-------------------------------------------------------------------------
1037
1038 'hasAnyCleanTextData': function () {
1039 var result;
1040
1041 result = false;
1042
1043 result = result || (this._inputs != null);
1044 result = result || (this._bindings != null);
1045 result = result || (this._formValues != null);
1046 result = result || (MochiKit.Base.keys(this.transientState()).length != 0);
1047
1048 return MochiKit.Async.succeed(result);
1049 },
1050
1051 //=========================================================================
1052 __syntaxFix__: "syntax fix"
1053});
1054
1055//#############################################################################
1056
1057Clipperz.PM.DataModel.DirectLogin.exception = {
1058 'WrongBookmarkletConfiguration': new MochiKit.Base.NamedError("Clipperz.PM.DataModel.DirectLogin.exception.WrongBookmarkletConfiguration")
1059};
1060
1061Clipperz.PM.DataModel.DirectLogin.checkBookmarkletConfiguration = function(aConfiguration) {
1062 var configuration;
1063
1064 try {
1065 configuration = Clipperz.Base.evalJSON(aConfiguration);
1066 // configuration = Clipperz.PM.BookmarkletProcessor.sanitizeBookmarkletConfiguration(configuration);
1067
1068 if (MochiKit.Base.isUndefinedOrNull(configuration['page']['title'])
1069 ||MochiKit.Base.isUndefinedOrNull(configuration['form']['attributes']['action'])
1070 // ||MochiKit.Base.isUndefinedOrNull(configuration['form']['attributes']['method'])
1071 ||MochiKit.Base.isUndefinedOrNull(configuration['form']['inputs'])
1072 ||MochiKit.Base.isUndefinedOrNull(configuration['version'])
1073 ) {
1074 throw Clipperz.PM.DataModel.DirectLogin.exception.WrongBookmarkletConfiguration;
1075 }
1076
1077 // if (MochiKit.Base.isUndefinedOrNull(configuration['favicon'])) {
1078 // throw Clipperz.PM.DataModel.DirectLogin.exception.WrongBookmarkletConfiguration;
1079 // }
1080
1081 } catch (exception) {
1082 throw exception;
1083 }
1084
1085 return configuration;
1086};
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginBinding.js b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginBinding.js
new file mode 100644
index 0000000..a8ebb97
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginBinding.js
@@ -0,0 +1,120 @@
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
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29//#############################################################################
30
31Clipperz.PM.DataModel.DirectLoginBinding = function(aDirectLogin, args) {
32 args = args || {};
33
34 this._directLogin = aDirectLogin|| Clipperz.Base.exception.raise('MandatoryParameter');
35
36 this._key = args.key|| Clipperz.Base.exception.raise('MandatoryParameter');
37 this._fieldKey = args.field || /* this.directLogin().fieldWithName(args.fieldName).reference() || */null;
38
39 return this;
40}
41
42Clipperz.PM.DataModel.DirectLoginBinding.prototype = MochiKit.Base.update(null, {
43
44 'toString': function() {
45 return "DirectLoginBinding (" + this.key() + ", " + this.fieldKey() + ")";
46 },
47
48 //-------------------------------------------------------------------------
49
50 'directLogin': function () {
51 return this._directLogin;
52 },
53
54 //-------------------------------------------------------------------------
55
56 'key': function() {
57 return this._key;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'fieldKey': function() {
63 return this._fieldKey;
64 },
65
66 'setFieldKey': function(aValue) {
67 this._fieldKey = aValue;
68
69 return this.directLogin().setValue('bindingData' + '.' + this.key(), aValue);
70 },
71
72 //'fieldName': function() {
73 // return this._fieldName;
74 //},
75
76 //-------------------------------------------------------------------------
77
78 'field': function() {
79 var deferredResult;
80
81 if (this.fieldKey() != null) {
82 deferredResult = Clipperz.Async.callbacks("DirectLoginBinding.field [1]", [
83 MochiKit.Base.method(this.directLogin().record(), 'fields'),
84 MochiKit.Base.itemgetter(this.fieldKey())
85 ], {trace:false});
86 // } else if (this.fieldName() != null) {
87 // WTF = TODO;
88 // result = this.directLogin().record().fieldWithName(this.fieldName());
89 //
90 // this.setFieldKey(result.key());
91 } else {
92 deferredResult = MochiKit.Async.succeed(null);
93 }
94
95 return deferredResult;
96 },
97
98 'setField': function (aField) {
99 this.setFieldKey(aField.reference());
100 },
101
102 //-------------------------------------------------------------------------
103/*
104 'fieldValue': function () {
105 return Clipperz.Async.callbacks("DirectLoginBinding.fieldValue", [
106 MochiKit.Base.method('field'),
107 MochiKit.Base.methodcaller('value')
108 ], {trace:false});
109 },
110*/
111 //-------------------------------------------------------------------------
112
113 'serializedData': function() {
114 return this.fieldKey();
115 },
116
117 //-------------------------------------------------------------------------
118 __syntaxFix__: "syntax fix"
119});
120
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginFormValue.js b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginFormValue.js
new file mode 100644
index 0000000..2429f88
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginFormValue.js
@@ -0,0 +1,101 @@
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
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29//#############################################################################
30
31Clipperz.PM.DataModel.DirectLoginFormValue = function(aDirectLogin, args) {
32 args = args || {};
33
34 this._directLogin = aDirectLogin|| Clipperz.Base.exception.raise('MandatoryParameter');
35
36 this._key = args.key || Clipperz.Base.exception.raise('MandatoryParameter');
37 this._fieldOptions = args.fieldOptions|| Clipperz.Base.exception.raise('MandatoryParameter');
38 this._value = args.value || null;
39
40 return this;
41}
42
43Clipperz.PM.DataModel.DirectLoginFormValue.prototype = MochiKit.Base.update(null, {
44
45 'toString': function() {
46 return "DirectLoginFormValue (" + this.key() + ", " + this.value() + ")";
47 },
48
49 //-------------------------------------------------------------------------
50
51 'directLogin': function () {
52 return this._directLogin;
53 },
54
55 //-------------------------------------------------------------------------
56
57 'key': function() {
58 return this._key;
59 },
60
61 //-------------------------------------------------------------------------
62
63 'fieldOptions': function() {
64 return this._fieldOptions;
65 },
66
67 //-------------------------------------------------------------------------
68
69 'type': function () {
70 return this.fieldOptions()['type'];
71 },
72
73 //-------------------------------------------------------------------------
74
75 'value': function() {
76 varresult;
77
78 result = this._value;
79
80 // if ((result == null) && (this.type() == 'checkbox')) {
81 // result = false;
82 // };
83
84 return result;
85 },
86
87 'setValue': function (aValue) {
88 this._value = aValue;
89 return this.directLogin().setValue('formValues' + '.' + this.key(), aValue);
90 },
91
92 //-------------------------------------------------------------------------
93/*
94 'serializedData': function() {
95 return this.value();
96 },
97*/
98 //-------------------------------------------------------------------------
99 __syntaxFix__: "syntax fix"
100});
101
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginInput.js b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginInput.js
new file mode 100644
index 0000000..d9995fc
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginInput.js
@@ -0,0 +1,192 @@
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
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28//#############################################################################
29
30Clipperz.PM.DataModel.DirectLoginInput = function(args) {
31 this._args = args;
32
33 return this;
34}
35
36Clipperz.PM.DataModel.DirectLoginInput.prototype = MochiKit.Base.update(null, {
37
38 'args': function() {
39 return this._args;
40 },
41
42 //-------------------------------------------------------------------------
43
44 'name': function() {
45 return this.args()['name'];
46 },
47
48 //-------------------------------------------------------------------------
49
50 'type': function() {
51 var result;
52
53 result = this.args()['type'];
54
55 if (result != null) {
56 result = result.toLowerCase();
57 }
58 return result;
59 },
60
61 //-------------------------------------------------------------------------
62
63 'options': function() {
64 return this.args()['options'];
65 },
66
67 //-------------------------------------------------------------------------
68
69 'value': function() {
70 return this.args()['value'];
71 },
72
73 //-------------------------------------------------------------------------
74 /*
75 'formConfiguration': function(someFormValues, someBindings, someFields) {
76 var result;
77
78 if (this.shouldSetValue()) {
79 switch (this.type()) {
80 case 'select':
81 var currentValue;
82 var options;
83
84 // currentValue = this.directLogin()._configuration['formValues'][this.name()];
85 currentValue = someFormValues[this.name()];
86 options = this.args()['options'];
87
88 result = MochiKit.DOM.SELECT({name:this.name()},
89 MochiKit.Base.map(function(anOption) {
90 var options;
91
92 options = {value:anOption['value']};
93 if (currentValue == anOption['value']) {
94 options.selected = true;
95 }
96
97 return MochiKit.DOM.OPTION(options, anOption['label'])
98 }, options)
99 )
100 break;
101 case 'checkbox':
102 var options;
103
104 options = {type:'checkbox', name: this.name()};
105 // if (this.directLogin()._configuration['formValues'][this.name()] == true) {
106 if (someFormValues[this.name()] == true) {
107 options['checked'] = true;
108 };
109
110 result = MochiKit.DOM.INPUT(options, null);
111 break;
112 case 'radio':
113 var currentName;
114 var currentValue;
115 var options;
116
117 currentName = this.name();
118 // currentValue = this.directLogin()._configuration['formValues'][this.name()];
119 currentValue = someFormValues[this.name()];
120 options = this.args()['options'];
121
122 result = MochiKit.DOM.DIV(null,
123 MochiKit.Base.map(function(anOption) {
124 var options;
125 var isChecked;
126 var inputNode;
127 var divNode;
128
129 options = {type:'radio', name:currentName, value:anOption['value']}
130 isChecked = (currentValue == anOption['value']);
131 if (isChecked) {
132 options.checked = true;
133 }
134
135 if (Clipperz_IEisBroken == true) {
136 var checkedValue;
137
138 checkedValue = (isChecked ? " CHECKED" : "");
139 inputNode = MochiKit.DOM.currentDocument().createElement("<INPUT TYPE='RADIO' NAME='" + currentName + "' VALUE='" + anOption['value'] + "'" + checkedValue + ">");
140 } else {
141 inputNode = MochiKit.DOM.INPUT(options, anOption['value']);
142 }
143 divNode = MochiKit.DOM.DIV(null, inputNode);
144
145 return divNode;
146 }, options)
147 );
148 break;
149 }
150 } else {
151 var binding;
152 // binding = this.directLogin().bindings()[this.name()];
153 binding = someBindings[this.name()];
154
155 result = MochiKit.DOM.INPUT({
156 type:((this.type() != 'password') ? this.type() : 'text'),
157 name:this.name(),
158 // value:((binding != null)? binding.field().value() : this.value())
159 value:((binding != null)? someFields[binding.fieldKey()]['value'] : this.value())
160 // value:((binding != null)? someFields[binding.fieldKey()].value() : this.value())
161 }, null);
162 }
163
164 return result;
165 },
166 */
167 //-------------------------------------------------------------------------
168
169 'needsFormValue': function() {
170 var type;
171 var result;
172
173 type = this.type();
174 result = ((type == 'checkbox') || (type == 'radio') || (type == 'select'));
175
176 return result;
177 },
178
179 'needsBinding': function() {
180 var type;
181 var result;
182
183 type = this.type();
184 result = ((type == 'text') || (type == 'password'));
185
186 return result;
187 },
188
189 //-------------------------------------------------------------------------
190 __syntaxFix__: "syntax fix"
191});
192
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});
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/OneTimePassword.js b/frontend/delta/js/Clipperz/PM/DataModel/OneTimePassword.js
new file mode 100644
index 0000000..fbca1ff
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/OneTimePassword.js
@@ -0,0 +1,350 @@
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
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29//#############################################################################
30
31Clipperz.PM.DataModel.OneTimePassword = function(args) {
32 args = args || {};
33
34 //this._user = args['user'];
35 this._reference = args['reference']|| Clipperz.PM.Crypto.randomKey();
36 this._password = args['password'];
37 this._passwordValue = Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(args['password']);
38 this._creationDate = args['created'] ? Clipperz.PM.Date.parseDateWithUTCFormat(args['created']) : new Date();
39 this._usageDate = args['used'] ? Clipperz.PM.Date.parseDateWithUTCFormat(args['used']) : null;
40
41 this._status = args['status'] || 'ACTIVE'; //'REQUESTED', 'USED', 'DISABLED'
42 this._connectionInfo= null;
43
44 this._key = null;
45 this._keyChecksum= null;
46
47 return this;
48}
49
50Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
51
52 'toString': function() {
53 return "Clipperz.PM.DataModel.OneTimePassword";
54 },
55/*
56 //-------------------------------------------------------------------------
57
58 'user': function() {
59 return this._user;
60 },
61
62 //-------------------------------------------------------------------------
63
64 'password': function() {
65 return this._password;
66 },
67
68 //-------------------------------------------------------------------------
69
70 'passwordValue': function() {
71 return this._passwordValue;
72 },
73
74 //-------------------------------------------------------------------------
75
76 'creationDate': function() {
77 return this._creationDate;
78 },
79
80 //-------------------------------------------------------------------------
81
82 'reference': function() {
83 return this._reference;
84 },
85
86 //-------------------------------------------------------------------------
87
88 'key': function() {
89 if (this._key == null) {
90 this._key = Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(this.user().username(), this.passwordValue());
91 }
92
93 return this._key;
94 },
95
96 //-------------------------------------------------------------------------
97
98 'keyChecksum': function() {
99 if (this._keyChecksum == null) {
100 this._keyChecksum = Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(this.user().username(), this.passwordValue());
101 }
102
103 return this._keyChecksum;
104 },
105*/
106 //-------------------------------------------------------------------------
107
108 'status': function() {
109 return this._status;
110 },
111
112 'setStatus': function(aValue) {
113 this._status = aValue;
114 },
115
116 //-------------------------------------------------------------------------
117/*
118 'serializedData': function() {
119 var result;
120
121 result = {
122 'password': this.password(),
123 'created': this.creationDate() ? Clipperz.PM.Date.formatDateWithUTCFormat(this.creationDate()) : null,
124 'used': this.usageDate() ? Clipperz.PM.Date.formatDateWithUTCFormat(this.usageDate()) : null,
125 'status': this.status()
126 };
127
128 return result;
129 },
130
131 //-------------------------------------------------------------------------
132
133 'packedPassphrase': function() {
134 var result;
135 var packedPassphrase;
136 var encodedPassphrase;
137 varprefixPadding;
138 var suffixPadding;
139 var getRandomBytes;
140
141 getRandomBytes = MochiKit.Base.method(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'getRandomBytes');
142
143 encodedPassphrase = new Clipperz.ByteArray(this.user().passphrase()).toBase64String();
144//Clipperz.logDebug("--- encodedPassphrase.length: " + encodedPassphrase.length);
145 prefixPadding = getRandomBytes(getRandomBytes(1).byteAtIndex(0)).toBase64String();
146//Clipperz.logDebug("--- prefixPadding.length: " + prefixPadding.length);
147 suffixPadding = getRandomBytes((500 - prefixPadding.length - encodedPassphrase.length) * 6 / 8).toBase64String();
148//Clipperz.logDebug("--- suffixPadding.length: " + suffixPadding.length);
149//Clipperz.logDebug("--- total.length: " + (prefixPadding.length + encodedPassphrase.length + suffixPadding.length));
150
151 packedPassphrase = {
152 'prefix': prefixPadding,
153 'passphrase': encodedPassphrase,
154 'suffix': suffixPadding
155 };
156
157 // result = Clipperz.Base.serializeJSON(packedPassphrase);
158 result = packedPassphrase;
159//Clipperz.logDebug("===== OTP packedPassprase: [" + result.length + "]" + result);
160//Clipperz.logDebug("<<< OneTimePassword.packedPassphrase");
161
162 return result;
163 },
164
165 //-------------------------------------------------------------------------
166
167 'encryptedPackedPassphrase': function() {
168 return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(this.passwordValue(), this.packedPassphrase())
169 },
170
171 //-------------------------------------------------------------------------
172
173 'encryptedData': function() {
174 var deferredResult;
175 varresult;
176
177//Clipperz.logDebug(">>> OneTimePassword.encryptedData");
178//Clipperz.logDebug("--- OneTimePassword.encryptedData - id: " + this.reference());
179 result = {
180 'reference': this.reference(),
181 'key': this.key(),
182 'keyChecksum': this.keyChecksum(),
183 'data': "",
184 'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion
185 }
186//Clipperz.logDebug("--- OneTimePassword.encryptedData - 2: " + Clipperz.Base.serializeJSON(result));
187 deferredResult = new MochiKit.Async.Deferred();
188//Clipperz.logDebug("--- OneTimePassword.encryptedData - 3");
189//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 1: " + res); return res;});
190 //# deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion, this.passwordValue(), this.packedPassphrase());
191 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedPackedPassphrase'));
192//Clipperz.logDebug("--- OneTimePassword.encryptedData - 4");
193//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 2: [" + res.length + "]" + res); return res;});
194 deferredResult.addCallback(function(aResult, res) {
195 aResult['data'] = res;
196 return aResult;
197 }, result);
198//Clipperz.logDebug("--- OneTimePassword.encryptedData - 5");
199//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 3: " + Clipperz.Base.serializeJSON(res)); return res;});
200 deferredResult.callback();
201//Clipperz.logDebug("--- OneTimePassword.encryptedData - 6");
202
203 return deferredResult;
204 },
205
206 //-------------------------------------------------------------------------
207
208 'saveChanges': function() {
209 var deferredResult;
210 varresult;
211
212//Clipperz.logDebug(">>> OneTimePassword.saveChanges");
213 result = {};
214 deferredResult = new MochiKit.Async.Deferred();
215
216 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptUserData');
217 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'encryptedData'));
218 deferredResult.addCallback(function(aResult, res) {
219 aResult['user'] = res;
220 return aResult;
221 }, result);
222
223 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptOTPData');
224 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedData'));
225 deferredResult.addCallback(function(aResult, res) {
226 aResult['oneTimePassword'] = res;
227 return aResult;
228 }, result);
229
230 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_sendingData');
231//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 1: " + Clipperz.Base.serializeJSON(res)); return res;});
232 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'addNewOneTimePassword');
233
234 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_updatingInterface');
235//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 2: " + res); return res;});
236 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'OTPUpdated');
237 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'oneTimePassword_saveChanges_done', null);
238//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 2: " + res); return res;});
239 deferredResult.callback();
240//Clipperz.logDebug("<<< OneTimePassword.saveChanges");
241
242 return deferredResult;
243 },
244
245 //-------------------------------------------------------------------------
246
247 'usageDate': function() {
248 return this._usageDate;
249 },
250
251 'setUsageDate': function(aValue) {
252 this._usageDate = aValue;
253 },
254
255 //-------------------------------------------------------------------------
256
257 'connectionInfo': function() {
258 return this._connectionInfo;
259 },
260
261 'setConnectionInfo': function(aValue) {
262 this._connectionInfo = aValue;
263 },
264
265 //-------------------------------------------------------------------------
266
267 'isExpired': function() {
268 return (this.usageDate() != null);
269 },
270
271 //-------------------------------------------------------------------------
272
273 'updateStatusWithValues': function(someValues) {
274 var result;
275
276 result = false;
277
278 if (someValues['status'] != this.status()) {
279 result = true;
280 }
281
282 this.setStatus(someValues['status']);
283 this.setUsageDate(Clipperz.PM.Date.parseDateWithUTCFormat(someValues['requestDate']));
284 this.setConnectionInfo(someValues['connection']);
285
286 return result;
287 },
288 */
289 //-------------------------------------------------------------------------
290 __syntaxFix__: "syntax fix"
291});
292
293//#############################################################################
294
295Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword = function(anUsername, aPassword) {
296 return Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aPassword)).toHexString().substring(2);
297}
298
299Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword = function(anUsername, aPassword) {
300 return Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(anUsername + aPassword)).toHexString().substring(2);
301}
302
303//=============================================================================
304
305Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue = function(aPassword) {
306 var result;
307
308 //"yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg"
309 if (aPassword.replace(/[\s\-]/g, '').length == 32) {
310 try {
311 var passwordByteArray;
312
313 passwordByteArray = new Clipperz.ByteArray();
314 passwordByteArray.appendBase32String(aPassword);
315
316 result = true;
317 } catch(exception) {
318 result = false;
319 }
320 } else {
321 result = false;
322 }
323
324 return result;
325}
326
327//=============================================================================
328
329Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword = function(aPassword) {
330 varresult;
331
332 if (aPassword.replace(/[\s\-]/g, '').length == 32) {
333 try {
334 var passwordByteArray;
335
336 passwordByteArray = new Clipperz.ByteArray();
337 passwordByteArray.appendBase32String(aPassword);
338
339 result = passwordByteArray.toBase64String();
340 } catch(exception) {
341 result = aPassword;
342 }
343 } else {
344 result = aPassword;
345 }
346
347 return result;
348}
349
350//#############################################################################
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.Field.js b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.Field.js
new file mode 100644
index 0000000..01e7196
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.Field.js
@@ -0,0 +1,186 @@
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.PM.DataModel.Record.Version) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.Record.Version.Field depends on Clipperz.PM.DataModel.Record.Version!";
26}
27
28Clipperz.PM.DataModel.Record.Version.Field = function(args) {
29 Clipperz.PM.DataModel.Record.Version.Field.superclass.constructor.apply(this, arguments);
30
31 this._recordVersion = args.recordVersion|| Clipperz.Base.exception.raise('MandatoryParameter');
32 this._reference = args.reference || Clipperz.PM.Crypto.randomKey();
33
34 return this;
35}
36
37
38Clipperz.Base.extend(Clipperz.PM.DataModel.Record.Version.Field, Object, {
39
40 'toString': function() {
41 return "Record.Version.Field (" + this.reference() + ")";
42 },
43
44 //-------------------------------------------------------------------------
45
46 'recordVersion': function () {
47 return this._recordVersion;
48 },
49
50 //-------------------------------------------------------------------------
51
52 'reference': function () {
53 return this._reference;
54 },
55
56 //-------------------------------------------------------------------------
57
58 'getItem': function (aKey) {
59 return Clipperz.Async.callbacks("Clipperz.PM.DataModel.Record.Version.Field.getItem", [
60 MochiKit.Base.method(this, 'recordVersion'),
61 MochiKit.Base.methodcaller('getValue', 'fields' + '.' + this.reference() + '.' + aKey)
62 ], {trace:false});
63 },
64
65 'setItem': function (aKey, aValue) {
66 return Clipperz.Async.callbacks("Clipperz.PM.DataModel.Record.Version.Field.getItem", [
67 MochiKit.Base.method(this, 'recordVersion'),
68 MochiKit.Base.methodcaller('setValue', 'fields' + '.' + this.reference() + '.' + aKey, aValue)
69 ], {trace:false});
70 },
71
72 //-------------------------------------------------------------------------
73
74 'label': function () {
75 return this.getItem('label');
76 },
77
78 'setLabel': function (aValue) {
79 return this.setItem('label', aValue);
80 },
81
82 //-------------------------------------------------------------------------
83
84 'value': function () {
85 return this.getItem('value');
86 },
87
88 'setValue': function (aValue) {
89 return this.setItem('value', aValue);
90 },
91
92 //-------------------------------------------------------------------------
93
94 'actionType': function () {
95 return Clipperz.Async.callbacks("Clipperz.PM.DataModel.Record.Version.Field.actionType", [
96 Clipperz.Async.collectResults("Clipperz.PM.DataModel.Record.Version.Field.actionType [collect results]", {
97 'isHidden':MochiKit.Base.method(this, 'isHidden'),
98 'value':MochiKit.Base.method(this, 'value')
99 }, {trace:false}),
100 function (someValues) {
101 var result; //'NONE', 'URL', 'EMAIL', 'PASSWORD'
102
103 result = 'NONE';
104
105 if (someValues['isHidden']) {
106 result = 'PASSWORD';
107 } else if (Clipperz.Base.isUrl(someValues['value'])) {
108 result = 'URL'
109 } else if (Clipperz.Base.isEmail(someValues['value'])) {
110 result = 'EMAIL'
111 };
112
113 return result;
114 }
115 ], {trace:false});
116 },
117
118 //-------------------------------------------------------------------------
119
120 'isHidden': function () {
121 return this.getItem('hidden');
122 },
123
124 'setIsHidden': function (aValue) {
125 return this.setItem('hidden', aValue);
126 },
127
128 //-------------------------------------------------------------------------
129
130 'isEmpty': function () {
131 var deferredResult;
132
133 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.Field.isEmpty", {trace:false});
134
135 deferredResult.collectResults({
136 'label': [
137 MochiKit.Base.method(this, 'label'),
138 MochiKit.Base.partial(MochiKit.Base.operator.eq, '')
139 ],
140 'value': [
141 MochiKit.Base.method(this, 'value'),
142 MochiKit.Base.partial(MochiKit.Base.operator.eq, '')
143 ],
144 'isHidden': [
145 MochiKit.Base.method(this, 'isHidden'),
146 MochiKit.Base.partial(MochiKit.Base.operator.eq, false)
147 ]
148 });
149 deferredResult.addCallback(MochiKit.Base.values);
150 deferredResult.addCallback(function(someValues) {
151 return MochiKit.Iter.every(someValues, MochiKit.Base.operator.identity);
152 });
153 deferredResult.callback();
154
155 return deferredResult;
156 },
157
158 //-------------------------------------------------------------------------
159
160 'content': function () {
161 var deferredResult;
162 varfieldValues;
163
164 fieldValues = {};
165 deferredResult = new Clipperz.Async.Deferred("Record.Version.Field.content", {trace:false});
166 deferredResult.addMethod(this, 'reference');
167 deferredResult.addCallback(function (aValue) { fieldValues['reference'] = aValue; });
168 deferredResult.addMethod(this, 'label');
169 deferredResult.addCallback(function (aValue) { fieldValues['label'] = aValue; });
170 deferredResult.addMethod(this, 'value');
171 deferredResult.addCallback(function (aValue) { fieldValues['value'] = aValue; });
172 deferredResult.addMethod(this, 'actionType');
173 deferredResult.addCallback(function (aValue) { fieldValues['actionType'] = aValue; });
174 deferredResult.addMethod(this, 'isHidden');
175 deferredResult.addCallback(function (aValue) { fieldValues['isHidden'] = aValue; });
176 deferredResult.addCallback(function () { return fieldValues; });
177 deferredResult.callback();
178
179 return deferredResult;
180 },
181
182 //-------------------------------------------------------------------------
183 __syntaxFix__: "syntax fix"
184});
185
186
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js
new file mode 100644
index 0000000..87b319c
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js
@@ -0,0 +1,328 @@
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.PM.DataModel.Record) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.Record.Version depends on Clipperz.PM.DataModel.Record!";
26}
27
28Clipperz.PM.DataModel.Record.Version = function(args) {
29 Clipperz.PM.DataModel.Record.Version.superclass.constructor.apply(this, arguments);
30
31 this._getVersionFunction = args.getVersion|| Clipperz.Base.exception.raise('MandatoryParameter');
32 this._fields = null;
33
34 return this;
35}
36
37
38Clipperz.Base.extend(Clipperz.PM.DataModel.Record.Version, Clipperz.PM.DataModel.EncryptedRemoteObject, {
39
40 'toString': function() {
41 return "Record.Version (" + this.reference() + ")";
42 },
43
44 //-------------------------------------------------------------------------
45
46 'reference': function () {
47 return this._reference;
48 },
49
50 //-------------------------------------------------------------------------
51/*
52 'hasPendingChanges': function () {
53 var deferredResult;
54
55 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.hasPendingChanges", {trace:false});
56 deferredResult.addCallback(MochiKit.Base.bind(Clipperz.PM.DataModel.Record.Version.superclass.hasPendingChanges, this));
57 deferredResult.callback();
58
59 return deferredResult;
60 },
61*/
62 //-------------------------------------------------------------------------
63
64
65 'hasPendingChangesWhenBrandNew': function () {
66 var deferredResult;
67
68 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.hasPendingChangesWhenBrandNew", {trace:false});
69 deferredResult.addMethod(this, 'fields');
70 deferredResult.addCallback(MochiKit.Base.values);
71 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.methodcaller('isEmpty'))
72 deferredResult.addCallback(Clipperz.Async.collectAll);
73 deferredResult.addCallback(function(someValues) {
74 return MochiKit.Iter.every(someValues, MochiKit.Base.operator.identity);
75 });
76 deferredResult.addCallback(MochiKit.Base.operator.lognot)
77 deferredResult.callback();
78
79 return deferredResult;
80 },
81
82 //=========================================================================
83
84 'commitTransientState': function () {
85 var deferredResult;
86
87 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.commitTransientState", {trace:false});
88 deferredResult.addCallback(MochiKit.Base.bind(Clipperz.PM.DataModel.Record.Version.superclass.commitTransientState, this));
89 deferredResult.callback();
90
91 return deferredResult;
92 },
93
94 //=========================================================================
95
96 'unpackData': function (someData) { //++
97 varresult;
98
99 result = someData;
100 if ((someData['fields'] != null) && (someData['fields'] instanceof Array)) {
101 varfields;
102 var i,c;
103
104 fields = someData['fields'];
105 delete someData['fields'];
106
107 someData['fields'] = {};
108 c = fields.length;
109 for (i=0; i<c; i++) {
110 someData['fields'][i] = fields[i];
111 }
112 }
113
114
115
116 return result;
117 },
118
119 //=========================================================================
120
121 'fields': function () {
122 vardeferredResult;
123 var deferredLock;
124
125 deferredLock = this.getDeferredLockForKey('fields');
126
127 deferredResult = new Clipperz.Async.Deferred("Record.Version.fields", {trace:false});
128 deferredResult.acquireLock(deferredLock);
129 deferredResult.addCallback(MochiKit.Base.bind(function () {
130 var innerDeferredResult;
131
132 if (this._fields == null) {
133 innerDeferredResult = new Clipperz.Async.Deferred("Record.Version.fields <inner deferred>", {trace:false});
134 innerDeferredResult.addMethod(this, 'getValue', 'fields');
135 innerDeferredResult.addCallback(MochiKit.Base.bind(function (someObjectData) {
136 var reference;
137
138 this._fields = {};
139
140 for (reference in someObjectData) {
141 varrecordVersionField;
142
143 recordVersionField = new Clipperz.PM.DataModel.Record.Version.Field({
144 'recordVersion':this,
145 'reference': reference
146 });
147
148 this._fields[reference] = recordVersionField;
149 }
150
151 return this._fields;
152 }, this));
153 innerDeferredResult.callback();
154 } else {
155 innerDeferredResult = MochiKit.Async.succeed(this._fields);
156 }
157
158 return innerDeferredResult;
159 }, this));
160 deferredResult.releaseLock(deferredLock);
161 deferredResult.callback();
162
163 return deferredResult;
164 },
165
166 //-------------------------------------------------------------------------
167
168 'getFieldsValues': function () {
169 return this.getValue('fields');
170 },
171
172 //-------------------------------------------------------------------------
173
174 'addField': function (someParameters) {
175 varnewField;
176
177 newField = new Clipperz.PM.DataModel.Record.Version.Field({recordVersion:this});
178
179 return Clipperz.Async.callbacks("Record.Version.addField", [
180 MochiKit.Base.method(this, 'fields'),
181
182 MochiKit.Base.method(this, '_getObjectDataStore'),
183 MochiKit.Base.methodcaller('values'),
184 Clipperz.Base.serializeJSON,
185
186 MochiKit.Base.bind(function () { this._fields[newField.reference()] = newField; }, this),
187 MochiKit.Base.method(newField, 'setLabel', someParameters['label']),
188 MochiKit.Base.method(newField, 'setValue', someParameters['value']),
189 MochiKit.Base.method(newField, 'setIsHidden',someParameters['isHidden']),
190
191 MochiKit.Base.method(this, '_getObjectDataStore'),
192 MochiKit.Base.methodcaller('values'),
193 Clipperz.Base.serializeJSON,
194
195 MochiKit.Base.partial(MochiKit.Async.succeed, newField)
196 ], {trace:false});
197 },
198
199 //-------------------------------------------------------------------------
200
201 'removeField': function (aField) {
202 return Clipperz.Async.callbacks("Record.Version.removeField", [
203 MochiKit.Base.method(this, 'fields'),
204 MochiKit.Base.bind(function () { delete this._fields[aField.reference()]; }, this),
205 MochiKit.Base.method(this, 'removeValue', 'fields' + '.' + aField.reference())
206 ], {trace:false});
207 },
208
209 //-------------------------------------------------------------------------
210/*
211 'sortFieldReference': function (someSortedFieldReferences) {
212
213
214
215 },
216*/
217 //=========================================================================
218/*
219 'directLogins': function () {
220 return MochiKit.Base.values(this._directLogins);
221 },
222
223 'addDirectLogin': function (aDirectLogin) {
224 this._directLogins[aDirectLogin.reference()] = aDirectLogin;
225 },
226*/
227
228 //=========================================================================
229/*
230 'updateValues': function (anotherVersion) {
231 return Clipperz.Async.callbacks("Record.Version.updateValue", [
232 MochiKit.Base.partial(MochiKit.Async.succeed, this)
233 ], {trace:false});
234 },
235*/
236 //=========================================================================
237
238 'setRemoteData': function (aValue) {
239 this._remoteData = aValue;
240
241 return aValue;
242 },
243
244 //=========================================================================
245
246 'getVersionFunction': function () {
247 return this._getVersionFunction;
248 },
249
250 'previousVersion': function () {
251 return Clipperz.Async.callbacks("Record.Versions.previousVersion", [
252 MochiKit.Base.method(this, 'previousVersionReference'),
253 this.getVersionFunction()
254 ], {trace:false});
255 },
256
257 'previousVersionReference': function () {
258 return this.getValue('previousVersionReference');
259 },
260
261 'previousVersionKey': function () {
262 //TODO: this value i encrypted on its own. So it can not be saved in the main objectStore!!!
263 return this.getValue('previousVersionKey');
264 },
265
266 //-------------------------------------------------------------------------
267
268 'setPreviousVersionReferenceAndKey': function (aVersionObjectAndKey) {
269 // this._previousVersion = anotherVersion;
270 return Clipperz.Async.callbacks("Record.Version.setPreviousVersion", [
271 MochiKit.Base.method(this, 'setValue', 'previousVersionReference',aVersionObjectAndKey['reference']),
272 MochiKit.Base.method(this, 'setValue', 'previousVersionKey', aVersionObjectAndKey['key'])
273 ], {trace:false});
274 },
275
276 //=========================================================================
277
278 'revertChanges': function () {
279 this.setReference(this.transientState()['originalReference']);
280 Clipperz.PM.DataModel.Record.Version.superclass.revertChanges.apply(this, arguments);
281 },
282
283 //-------------------------------------------------------------------------
284
285 'prepareRemoteDataWithKey': function (aKey) {
286 var deferredResult;
287 var result;
288
289 result = {};
290
291 deferredResult = new Clipperz.Async.Deferred("Record.Version.prepareRemoteDataWithKey", {trace:false});
292 if (this.isBrandNew() == false) {
293 this.transientState()['originalReference'] = this.reference();
294
295 deferredResult.collectResults({
296 'key':MochiKit.Base.partial(MochiKit.Async.succeed, aKey),
297 'value': MochiKit.Base.method(this, 'getKey'),
298 'version': MochiKit.Base.partial(MochiKit.Async.succeed, Clipperz.PM.Crypto.encryptingFunctions.currentVersion)
299 });
300 deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncrypt);
301 deferredResult.addCallback(Clipperz.Async.setItem, result, 'previousVersionKey');
302 } else {
303 deferredResult.addCallback(Clipperz.Async.setItem, result, 'previousVersionKey', Clipperz.PM.Crypto.nullValue);
304 }
305 deferredResult.addCallback(MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.prepareRemoteDataWithKey, this, aKey));
306 deferredResult.addCallback(MochiKit.Base.update, result);
307 deferredResult.addMethod(this, 'setRemoteData');
308
309 deferredResult.callback();
310
311 return deferredResult;
312 },
313
314 //=========================================================================
315/*
316 'deleteAllCleanTextData': function () {
317 return Clipperz.PM.DataModel.Record.Version.superclass.deleteAllCleanTextData.apply(this, arguments);
318 },
319
320 'hasAnyCleanTextData': function () {
321 return Clipperz.PM.DataModel.Record.Version.superclass.hasAnyCleanTextData.apply(this, arguments);
322 },
323*/
324 //=========================================================================
325 __syntaxFix__: "syntax fix"
326});
327
328
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/Record.js b/frontend/delta/js/Clipperz/PM/DataModel/Record.js
new file mode 100644
index 0000000..379872a
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/Record.js
@@ -0,0 +1,891 @@
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
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29Clipperz.PM.DataModel.Record = function(args) {
30 Clipperz.PM.DataModel.Record.superclass.constructor.apply(this, arguments);
31
32 this._updateDate = (args.updateDate ? Clipperz.PM.Date.parse(args.updateDate) : Clipperz.Base.exception.raise('MandatoryParameter'));
33
34 this._retrieveIndexDataFunction = args.retrieveIndexDataFunction|| Clipperz.Base.exception.raise('MandatoryParameter');
35 this._updateIndexDataFunction = args.updateIndexDataFunction || Clipperz.Base.exception.raise('MandatoryParameter');
36
37 this._retrieveDirectLoginIndexDataFunction = args.retrieveDirectLoginIndexDataFunction|| null;
38 this._setDirectLoginIndexDataFunction = args.setDirectLoginIndexDataFunction || null;
39 this._removeDirectLoginIndexDataFunction = args.removeDirectLoginIndexDataFunction|| null;
40
41 this._createNewDirectLoginFunction = args.createNewDirectLoginFunction || null;
42
43 this._directLogins = {};
44
45 this._versions = {};
46
47 this._currentRecordVersion = null;
48 if (this.isBrandNew()) {
49 var newVersion;
50
51 this.setNotes('');
52 newVersion = new Clipperz.PM.DataModel.Record.Version({
53 'retrieveKeyFunction':MochiKit.Base.method(this, 'getVersionKey'),
54 'getVersion': MochiKit.Base.method(this, 'getVersion')
55
56 });
57 this._versions[newVersion.reference()] = newVersion;
58 this._currentVersionReference = newVersion.reference();
59 // this.setLabel('');
60 }
61
62 return this;
63}
64
65
66Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.EncryptedRemoteObject, {
67
68 'toString': function() {
69 return "Record (" + this.reference() + ")";
70 },
71
72 //-------------------------------------------------------------------------
73
74 'reference': function () {
75 return this._reference;
76 },
77
78 //=========================================================================
79
80 'getIndexData': function () {
81 return this._retrieveIndexDataFunction(this.reference());
82 },
83
84 //.........................................................................
85
86 'getIndexDataForKey': function (aKey) {
87 return Clipperz.Async.callbacks("Record.getIndexDataForKey", [
88 MochiKit.Base.method(this, 'getIndexData'),
89 MochiKit.Base.itemgetter(aKey)
90 ], {trace:false});
91 },
92
93 //-------------------------------------------------------------------------
94
95 'setIndexDataForKey': function (aKey, aValue) {
96 // return this._updateIndexDataFunction(this.reference(), aKey, aValue);
97
98 var deferredResult;
99
100 deferredResult = new Clipperz.Async.Deferred("Record.setIndexDataForKey", {trace:false});
101 deferredResult.addMethod(this, 'getIndexDataForKey', aKey);
102 deferredResult.addCallback(MochiKit.Base.bind(function (aCurrentValue) {
103 var result;
104 var originalValue;
105
106 originalValue = this.transientState().getValue('originalValues.indexData.' + aKey);
107 if (originalValue == null) {
108 originalValue = this.transientState().setValue('originalValues.indexData.' + aKey, aCurrentValue);
109 }
110
111 if (aCurrentValue != aValue) {
112 if (originalValue != aValue) {
113 this.transientState().setValue('hasPendingChanges.indexData.' + aKey, true);
114 } else {
115 this.transientState().setValue('hasPendingChanges.indexData.' + aKey, false);
116 }
117
118 result = this._updateIndexDataFunction(this.reference(), aKey, aValue);
119 } else {
120 result = MochiKit.Async.succeed(aValue);
121 }
122
123 return result;
124 }, this));
125
126 deferredResult.callback();
127
128 return deferredResult;
129 },
130
131 //=========================================================================
132/*
133 'key': function () {
134 return this.getIndexDataForKey('key');
135 },
136*/
137 //=========================================================================
138
139 'label': function () {
140 return this.getIndexDataForKey('label');
141 },
142
143 //.........................................................................
144
145 'setLabel': function (aValue) {
146 return this.setIndexDataForKey('label', aValue);
147 },
148
149 //=========================================================================
150
151 'headerNotes': function () {
152 return this.getIndexDataForKey('notes');
153 },
154
155 //-------------------------------------------------------------------------
156
157 'notes': function () {
158 return Clipperz.Async.callbacks("Record.notes", [
159 MochiKit.Base.method(this, 'headerNotes'),
160 MochiKit.Base.bind(function (someHeaderNotes) {
161 var result;
162
163 if ((someHeaderNotes == null) || (typeof(someHeaderNotes) == 'undefined')) {
164 result = this.getValue('notes');
165 } else {
166 result = MochiKit.Async.succeed(someHeaderNotes);
167 }
168
169 return result;
170 }, this)
171 ], {trace:false});
172 },
173
174 //.........................................................................
175
176 'setNotes': function (aValue) {
177 return this.setValue('notes', aValue);
178 },
179
180 //=========================================================================
181
182 'updateDate': function () {
183 return MochiKit.Async.succeed(this._updateDate);
184 },
185
186 //=========================================================================
187
188 'favicon': function () {
189 var result;
190 var directLogins;
191
192 directLogins = MochiKit.Base.values(this.directLogins());
193 if (directLogins.length > 0) {
194 result = directLogins[0].favicon();
195 // } else if (/* is there an URL to use for searching a favicon */){
196 } else {
197 result = null; //MochiKit.Async.succeed(Clipperz.PM.Strings['defaultFaviconUrl']);
198 }
199
200 return result;
201 },
202
203 //-------------------------------------------------------------------------
204
205 'searchableContent': function () {
206 var deferredResult;
207
208 deferredResult = new Clipperz.Async.Deferred("Record.searchableContent", {trace:false});
209
210 deferredResult.collectResults({
211 'recordLabel': MochiKit.Base.method(this, 'label'),
212 'directLoginLabels': [
213 MochiKit.Base.method(this, 'directLoginReferences'),
214 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.itemgetter('label'))
215 ]
216 })
217 deferredResult.addCallback(function (someValues) {
218 return someValues['recordLabel'] + ' ' + someValues['directLoginLabels'].join(' ');
219 });
220 deferredResult.callback();
221
222 return deferredResult;
223 },
224
225 //-------------------------------------------------------------------------
226
227 'isMatching': function (aRegExp) {
228 return Clipperz.Async.callbacks("deferredFilterFunction", [
229 MochiKit.Base.method(this, 'searchableContent'),
230 MochiKit.Base.method(aRegExp, 'test'),
231 function (doesItMatch) {
232 var result;
233
234 if (doesItMatch) {
235 result = MochiKit.Async.succeed('match');
236 } else {
237 result = MochiKit.Async.fail('miss');
238 }
239
240 return result;
241 }
242 ], {trace:false});
243 },
244
245 //=========================================================================
246
247 'content': function () {
248 var deferredResult;
249 varresult;
250
251 result = {
252 'fields': [],
253 'directLogins': []
254 };
255
256 deferredResult = new Clipperz.Async.Deferred("Record.content", {trace:false});
257 deferredResult.addMethod(this, 'reference');
258 deferredResult.addCallback(function (aValue) { result['reference'] = aValue; });
259 deferredResult.addMethod(this, 'label');
260 deferredResult.addCallback(function (aValue) { result['title'] = aValue; });
261 deferredResult.addMethod(this, 'notes');
262 deferredResult.addCallback(function (aValue) { result['notes'] = aValue; });
263
264 deferredResult.addMethod(this, 'fields');
265 deferredResult.addCallback(MochiKit.Base.values);
266 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.methodcaller('content'));
267 deferredResult.addCallback(Clipperz.Async.collectAll);
268 deferredResult.addCallback(MochiKit.Base.map, function (aValue) { result['fields'].push(aValue); });
269
270 deferredResult.addMethod(this, 'directLogins');
271 deferredResult.addCallback(MochiKit.Base.values);
272 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.methodcaller('content'));
273 deferredResult.addCallback(Clipperz.Async.collectAll);
274 deferredResult.addCallback(MochiKit.Base.map, function (aValue) { result['directLogins'].push(aValue); });
275 deferredResult.addCallback(function () { return result; });
276
277 deferredResult.callback();
278
279 return deferredResult;
280 },
281
282 //=========================================================================
283
284 'directLogins': function () {
285 return this._directLogins;
286 },
287
288 'addDirectLogin': function (aDirectLogin) {
289 this._directLogins[aDirectLogin.reference()] = aDirectLogin;
290 },
291
292 'directLoginWithReference': function (aDirectLoginReference) {
293 return this._directLogins[aDirectLoginReference];
294 },
295
296 'createNewDirectLoginFunction': function () {
297 return this._createNewDirectLoginFunction;
298 },
299
300 'saveOriginalDirectLoginStatusToTransientState': function () {
301 if (this.transientState().getValue('directLogins') == null) {
302 // this.transientState().setValue('directLogins', this._directLogins)
303 MochiKit.Iter.forEach(MochiKit.Base.keys(this._directLogins), MochiKit.Base.bind(function(aKey) {
304 this.transientState().setValue('directLogins' + '.' + aKey, this._directLogins[aKey])
305 }, this))
306 }
307 },
308
309 'createNewDirectLogin': function () {
310 this.saveOriginalDirectLoginStatusToTransientState();
311
312 return this.createNewDirectLoginFunction()(this);
313 },
314
315 'removeDirectLogin': function(aDirectLogin) {
316 this.saveOriginalDirectLoginStatusToTransientState();
317
318 return Clipperz.Async.callbacks("Record.removeDirectLogin", [
319 MochiKit.Base.method(this, 'removeValue', 'directLogins' + '.' + aDirectLogin.reference()),
320 MochiKit.Base.bind(function () {
321 delete this._directLogins[aDirectLogin.reference()]
322 }, this)
323 ], {trace:false});
324
325 },
326
327 'directLoginReferences': function () {
328 var result;
329
330 result = Clipperz.Async.callbacks("Record.directLoginReferences", [
331 MochiKit.Base.method(this, 'directLogins'),
332 MochiKit.Base.values,
333 function (someDirectLogins) {
334 var result;
335 var i,c;
336
337 result = [];
338 c = someDirectLogins.length;
339 for (i=0; i<c; i++) {
340 result.push(Clipperz.Async.collectResults("Record.directLoginReferences - collectResults", {
341 '_rowObject': MochiKit.Async.succeed,
342 '_reference': MochiKit.Base.methodcaller('reference'),
343 'label': MochiKit.Base.methodcaller('label'),
344 'favicon': MochiKit.Base.methodcaller('favicon')
345 }, {trace:false})(someDirectLogins[i]));
346 };
347
348 return result;
349 },
350 Clipperz.Async.collectAll
351 ], {trace:false});
352
353 return result;
354 },
355
356 //=========================================================================
357
358 'unpackRemoteData': function (someData) {
359 var result;
360
361/*
362 this._currentRecordVersion = new Clipperz.PM.DataModel.Record.Version({
363 'reference': someData['currentVersion']['reference'],
364 'retrieveKeyFunction': MochiKit.Base.method(this, 'getCurrentRecordVersionKey'),
365 'remoteData': someData['currentVersion'],
366 });
367*/
368 var versionKey;
369
370 for (versionKey in someData['versions']) {
371 this._versions[versionKey] = new Clipperz.PM.DataModel.Record.Version({
372 'reference': versionKey,
373 'retrieveKeyFunction':MochiKit.Base.method(this, 'getVersionKey'),
374 'remoteData': someData['versions'][versionKey],
375 'getVersion': MochiKit.Base.method(this, 'getVersion')
376 })
377 }
378
379 // this._currentVersionReference = someData['currentVersion']['reference'];
380 this._currentVersionReference = someData['currentVersion'];
381
382 result = Clipperz.PM.DataModel.Record.superclass.unpackRemoteData.apply(this, arguments);
383
384 return result;
385 },
386
387 //-------------------------------------------------------------------------
388
389 'unpackData': function (someData) {
390 var result;
391
392 result = Clipperz.PM.DataModel.Record.superclass.unpackData.apply(this, arguments);
393
394 if (MochiKit.Base.isUndefinedOrNull(result['notes'])) {
395 result['notes'] = ''
396 }
397
398 return result;
399 },
400
401 //-------------------------------------------------------------------------
402
403 'prepareRemoteDataWithKey': function (aKey) {
404 var deferredResult;
405 varnewVersionKey;
406 var result;
407
408 newVersionKey = Clipperz.PM.Crypto.randomKey();
409 result = {};
410
411 deferredResult = new Clipperz.Async.Deferred("Record.prepareRemoteDataWithKey", {trace:false});
412 deferredResult.addCallbackList([
413 Clipperz.Async.collectResults("Record.prepareRemoteDataWithKey - collect results", {
414 'isBrandNew': MochiKit.Base.method(this, 'isBrandNew'),
415 'versionHasPendingChanges':[
416 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
417 // MochiKit.Base.methodcaller('hasPendingChanges')
418 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges')
419 ]
420 }),
421 Clipperz.Async.or,
422
423 Clipperz.Async.deferredIf("Current Version has pending changes", [
424 MochiKit.Base.method(this, 'createNewRecordVersion'),
425 MochiKit.Base.methodcaller('prepareRemoteDataWithKey', newVersionKey),
426 MochiKit.Base.partial(Clipperz.Async.setItem, result, 'currentRecordVersion'),
427 MochiKit.Base.method(this, 'setCurrentRecordVersionKey', newVersionKey)
428 ], []),
429
430 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.prepareRemoteDataWithKey, this, aKey),
431 MochiKit.Base.partial(Clipperz.Async.setItem, result, 'record'),
432
433 MochiKit.Base.partial(MochiKit.Async.succeed, result)
434 ]);
435
436 deferredResult.callback();
437
438 return deferredResult;
439 },
440
441 //=========================================================================
442
443 'fields': function () {
444 return this.invokeCurrentRecordVersionMethod('fields');
445 },
446
447 'addField': function (someParameters) {
448 return this.invokeCurrentRecordVersionMethod('addField', someParameters);
449 },
450
451 'removeField': function (someParameters) {
452 return this.invokeCurrentRecordVersionMethod('removeField', someParameters);
453 },
454
455 //'sortFieldReference': function (someSortedFieldReferences) {
456 // return this.invokeCurrentRecordVersionMethod('sortFieldReference', someSortedFieldReferences);
457 //},
458
459 'getFieldsValues': function () {
460 return this.invokeCurrentRecordVersionMethod('getFieldsValues');
461 },
462
463 'fieldWithLabel': function (aLabel) {
464 return Clipperz.Async.callbacks("Record.fieldWithLabel", [
465 MochiKit.Base.method(this, 'fields'),
466 MochiKit.Base.values,
467 MochiKit.Base.partial(Clipperz.Async.deferredFilter, function (aField) {
468 return Clipperz.Async.callbacks("Record.fieldWithLabel - check field label", [
469 MochiKit.Base.methodcaller('label'),
470 MochiKit.Base.partial(MochiKit.Base.operator.eq, aLabel)
471 ], {trace:false}, aField);
472 }),
473 function (someFilteredResults) {
474 var result;
475
476 switch (someFilteredResults.length) {
477 case 0:
478 result = null;
479 break;
480 case 1:
481 result = someFilteredResults[0];
482 break;
483 default:
484 WTF = TODO;
485 break;
486 }
487
488 return result;
489 }
490 ], {trace:false});
491 },
492
493 //=========================================================================
494
495 'getVersion': function (aVersionReference) {
496 return Clipperz.Async.callbacks("Record.getVersion", [
497 MochiKit.Base.method(this, 'getVersions'),
498 MochiKit.Base.itemgetter(aVersionReference)
499 ], {trace:false});
500 },
501
502 //-------------------------------------------------------------------------
503
504 'getVersionKey': function (aVersionReference) {
505 vardeferredResult;
506 var transientStateKey;
507
508 transientStateKey = 'versionKeys' + '.' + aVersionReference;
509 if (this.transientState().getValue(transientStateKey) != null) {
510 deferredResult = MochiKit.Async.succeed(this.transientState().getValue(transientStateKey));
511 } else {
512 deferredResult = Clipperz.Async.callbacks("Record.getVersionKey", [
513 MochiKit.Base.method(this, 'getVersions'),
514 MochiKit.Base.partial(MochiKit.Base.operator.eq, aVersionReference, this.currentVersionReference()),
515 Clipperz.Async.deferredIf("getVersionKey for current version", [
516 MochiKit.Base.method(this, 'getCurrentRecordVersionKey'),
517 MochiKit.Base.method(this.transientState(), 'setValue', transientStateKey)
518 ],[
519 MochiKit.Async.fail
520 ])
521 ], {trace:false});
522 }
523
524 return deferredResult;
525 },
526
527 //-------------------------------------------------------------------------
528
529 'versions': function () {
530 return this._versions;
531 },
532
533 'getVersions': function () {
534 return Clipperz.Async.callbacks("Record.versions", [
535 MochiKit.Base.method(this, 'getValue', 'fakeKey, just to trigger unpackRemoteData'),
536 MochiKit.Base.bind(function () { return this._versions; }, this)
537 ], {trace:false});
538 },
539
540 //-------------------------------------------------------------------------
541
542 'getCurrentRecordVersion': function () {
543 return Clipperz.Async.callbacks("Record.getCurrentRecordVersion", [
544 // MochiKit.Base.method(this, 'getValue', 'fakeKey, just to trigger unpackRemoteData'),
545 // MochiKit.Base.bind(function () { return this._currentRecordVersion; }, this)
546
547 MochiKit.Base.method(this, 'versions'),
548 MochiKit.Base.itemgetter(this.currentVersionReference()),
549 Clipperz.Async.deferredIf("The current version is available", [
550 MochiKit.Async.succeed
551 ], [
552 MochiKit.Base.method(this, 'getVersions'),
553 MochiKit.Base.bind(function (someVersions) { return someVersions[this.currentVersionReference()]}, this)
554 ])
555 ], {trace:false});
556 },
557
558 'setCurrentRecordVersion': function (aRecordVersion) {
559 this._currentVersionReference = aRecordVersion.reference();
560 },
561
562 //.........................................................................
563
564 'currentVersionReference': function () {
565 return this._currentVersionReference;
566 },
567
568 //-------------------------------------------------------------------------
569
570 'createNewRecordVersion': function () {
571 var deferredResult;
572
573 if (this.isBrandNew()) {
574 deferredResult = this.getCurrentRecordVersion();
575 } else {
576 var newVersion;
577
578 newVersion = new Clipperz.PM.DataModel.Record.Version({
579 // 'reference': versionKey,
580 'retrieveKeyFunction':MochiKit.Base.method(this, 'getVersionKey'),
581 // 'remoteData': {},
582 'getVersion': MochiKit.Base.method(this, 'getVersion')
583 })
584 this._versions[newVersion.reference()] = newVersion;
585
586 deferredResult = Clipperz.Async.callbacks("Record.createNewRecordVersion", [
587 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
588 // MochiKit.Base.methodcaller('values'),
589 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'values'),
590 MochiKit.Base.method(newVersion, 'setValues'),
591
592 Clipperz.Async.collectResults("Record.createNewRecordVersion [collect results]", {
593 'reference':MochiKit.Base.method(this, 'currentVersionReference'),
594 'key': MochiKit.Base.method(this, 'getCurrentRecordVersionKey')
595 }, {trace:false}),
596 MochiKit.Base.method(newVersion, 'setPreviousVersionReferenceAndKey'),
597
598 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
599 // MochiKit.Base.method(this, 'revertChanges'),
600 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'revertChanges'),
601
602 MochiKit.Base.method(this, 'setCurrentRecordVersion', newVersion),
603 MochiKit.Base.partial(MochiKit.Async.succeed, newVersion)
604 ], {trace:false});
605 }
606
607 return deferredResult;
608 },
609
610 //-------------------------------------------------------------------------
611
612 'getCurrentRecordVersionKey': function () {
613 return Clipperz.Async.callbacks("Record.getCurrentRecordVersionKey", [
614 MochiKit.Base.method(this, 'getValue', 'currentVersionKey'),
615 Clipperz.Async.deferredIf("currentVersionKey is NOT null", [
616 MochiKit.Async.succeed
617 ], [
618 MochiKit.Base.method(this, 'getKey')
619 ])
620 ], {trace:false});
621 },
622
623 'setCurrentRecordVersionKey': function (aValue) {
624 //TODO: triple check this method!
625 return Clipperz.Async.callbacks("Record.setCurrentRecordVersionKey", [
626 MochiKit.Base.method(this, 'setValue', 'currentVersionKey', aValue)
627 ], {trace:false});
628 },
629
630 //-------------------------------------------------------------------------
631
632 'invokeCurrentRecordVersionMethod': function (aMethodName, someValues) {
633 return Clipperz.Async.callbacks("Record.invokeCurrentRecordVersionMethod", [
634 MochiKit.Base.method(this, 'getCurrentRecordVersion'),
635 MochiKit.Base.methodcaller(aMethodName, someValues)
636 ], {trace:false});
637 },
638
639
640 'lazilyinvokeCurrentRecordVersionMethod': function (aMethodName, someValues, defaultResult) {
641 return Clipperz.Async.callbacks("Record.lazilyinvokeCurrentRecordVersionMethod", [
642 MochiKit.Base.method(this, 'currentVersionReference'),
643 Clipperz.Async.deferredIf("versions has been loaded", [
644 MochiKit.Base.method(this, 'getCurrentRecordVersion'),
645 MochiKit.Base.methodcaller(aMethodName, someValues),
646 ], [
647 MochiKit.Base.partial(MochiKit.Async.succeed, defaultResult),
648 ])
649 ], {trace:false});
650 },
651
652 //=========================================================================
653
654 'hasPendingChanges': function () {
655 var deferredResult;
656
657 if (this.hasInitiatedObjectDataStore()) {
658 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.hasPendingChanges", {trace:false});
659 deferredResult.collectResults({
660 'super': MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasPendingChanges, this),
661 'currentVersion': [
662 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
663 // MochiKit.Base.methodcaller('hasPendingChanges')
664 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges')
665 ],
666 'directLogins': [
667 MochiKit.Base.method(this, 'directLogins'),
668 MochiKit.Base.values,
669 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasPendingChanges')),
670 Clipperz.Async.collectAll,
671 Clipperz.Async.or
672 // function(someValues) {
673 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
674 // }
675 ]
676 });
677 deferredResult.addCallback(MochiKit.Base.values);
678 deferredResult.addCallback(MochiKit.Base.bind(function(someValues) {
679 var result;
680 result = MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
681
682 if ((result == false) && (this.isBrandNew() == false)) {
683 result = MochiKit.Iter.some(MochiKit.Base.values(this.transientState().getValue('hasPendingChanges.indexData')), MochiKit.Base.operator.identity);
684 }
685
686 return result;
687 }, this));
688
689 deferredResult.callback();
690 } else {
691 deferredResult = Clipperz.Async.callbacks("Recrod.hasPendingChanges [hasInitiatedObjectDataStore == false]", [
692 MochiKit.Base.method(this, 'directLogins'),
693 MochiKit.Base.values,
694 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasPendingChanges')),
695 Clipperz.Async.collectAll,
696 Clipperz.Async.or
697 // function(someValues) {
698 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
699 // }
700 ], {trace:false})
701 }
702
703 return deferredResult;
704 },
705
706 //-------------------------------------------------------------------------
707
708 'hasPendingChangesWhenBrandNew': function () {
709 var deferredResult;
710
711 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.hasPendingChangesWhenBrandNew", {trace:false});
712 deferredResult.collectResults({
713 'label': [
714 MochiKit.Base.method(this, 'label'),
715 MochiKit.Base.partial(MochiKit.Base.operator.ne, '')
716 ],
717 'notes': [
718 MochiKit.Base.method(this, 'notes'),
719 MochiKit.Base.partial(MochiKit.Base.operator.ne, '')
720 ]
721 });
722 // deferredResult.addCallback(MochiKit.Base.values);
723 // deferredResult.addCallback(function(someValues) {
724 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
725 // });
726 deferredResult.addCallback(Clipperz.Async.or);
727
728 deferredResult.callback();
729
730 return deferredResult;
731 },
732
733 //-------------------------------------------------------------------------
734
735 'isBrandNewWithNoPendingChanges': function () {
736 vardeferredResult;
737
738 if (this.isBrandNew() == false) {
739 deferredResult = MochiKit.Async.succeed(false);
740 } else {
741 deferredResult = Clipperz.Async.callbacks("Record.isBrandNewWithNoPendingChanges", [
742 MochiKit.Base.method(this, 'hasPendingChanges'),
743 MochiKit.Base.operator.lognot
744 ], {trace:false});
745 }
746
747 return deferredResult;
748 },
749
750 //=========================================================================
751
752 'revertChanges': function () {
753 var deferredResult;
754
755 if (this.isBrandNew() == false) {
756 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.revertChanges", {trace:false});
757 deferredResult.addMethod(this, 'hasPendingChanges');
758 deferredResult.addIf([
759 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
760 // MochiKit.Base.methodcaller('revertChanges'),
761 MochiKit.Base.method(this,'invokeCurrentRecordVersionMethod', 'revertChanges'),
762
763 MochiKit.Base.method(this, 'directLogins'),
764 MochiKit.Base.values,
765 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('revertChanges')),
766
767 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.revertChanges, this)
768 ], [
769 MochiKit.Async.succeed
770 ]);
771 deferredResult.callback();
772 } else {
773 // this.deleteAllCleanTextData();
774 deferredResult = MochiKit.Async.succeed();
775 }
776
777 return deferredResult;
778 },
779
780 //-------------------------------------------------------------------------
781
782 'resetTransientState': function (isCommitting) {
783 // if ((isCommitting == false) && (this.transientState().getValue('directLogins') != null)) {
784 // this._directLogins = this.transientState().getValue('directLogins');
785 // }
786
787 return Clipperz.Async.callbacks("Record.resetTransientState", [
788 //- MochiKit.Base.method(this, 'getCurrentRecordVersion'),
789 //- MochiKit.Base.methodcaller('resetTransientState'),
790 // MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'resetTransientState'),
791 MochiKit.Base.method(this, 'lazilyinvokeCurrentRecordVersionMethod', 'resetTransientState'),
792
793 MochiKit.Base.method(this, 'directLogins'),
794 MochiKit.Base.values,
795 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('resetTransientState')),
796
797 MochiKit.Base.bind(function () {
798 if ((isCommitting == false) && (this.transientState().getValue('directLogins') != null)) {
799 this._directLogins = this.transientState().getValue('directLogins');
800 }
801 }, this),
802
803 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.resetTransientState, this, isCommitting)
804 ], {trace:false})
805 },
806
807 //-------------------------------------------------------------------------
808
809 'commitTransientState': function () {
810 var deferredResult;
811
812 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.commitTransientState", {trace:false});
813 deferredResult.addMethod(this, 'hasPendingChanges');
814 deferredResult.addIf([
815 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.commitTransientState, this),
816 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
817 // MochiKit.Base.methodcaller('commitTransientState'),
818 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'commitTransientState'),
819 MochiKit.Base.method(this, 'directLogins'),
820 MochiKit.Base.values,
821 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('commitTransientState'))
822 ], [
823 MochiKit.Async.succeed
824 ]);
825 deferredResult.callback();
826
827 return deferredResult;
828 },
829
830 //=========================================================================
831
832 'retrieveDirectLoginIndexDataFunction': function () {
833 return this._retrieveDirectLoginIndexDataFunction;
834 },
835
836 'setDirectLoginIndexDataFunction': function () {
837 return this._setDirectLoginIndexDataFunction;
838 },
839
840 'removeDirectLoginIndexDataFunction': function () {
841 return this._removeDirectLoginIndexDataFunction;
842 },
843
844 //=========================================================================
845
846 'deleteAllCleanTextData': function () {
847 // return Clipperz.PM.DataModel.Record.superclass.deleteAllCleanTextData.apply(this, arguments);
848
849 return Clipperz.Async.callbacks("Record.deleteAllCleanTextData", [
850 MochiKit.Base.method(this, 'versions'),
851 MochiKit.Base.values,
852 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('deleteAllCleanTextData')),
853
854 MochiKit.Base.method(this, 'directLogins'),
855 MochiKit.Base.values,
856 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('deleteAllCleanTextData')),
857
858 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.deleteAllCleanTextData, this)
859 ], {trace:false});
860 },
861
862 'hasAnyCleanTextData': function () {
863 // return Clipperz.PM.DataModel.Record.superclass.hasAnyCleanTextData.apply(this, arguments);
864
865 return Clipperz.Async.callbacks("Record.hasAnyCleanTextData", [
866 Clipperz.Async.collectResults("Record.hasAnyCleanTextData [collect results]", {
867 'versions':[
868 MochiKit.Base.method(this, 'versions'),
869 MochiKit.Base.values,
870 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasAnyCleanTextData')),
871 Clipperz.Async.collectAll
872 ],
873 'directLogins': [
874 MochiKit.Base.method(this, 'directLogins'),
875 MochiKit.Base.values,
876 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasAnyCleanTextData')),
877 Clipperz.Async.collectAll
878 ],
879 'super': [
880 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasAnyCleanTextData, this)
881 ]
882 }, {trace:false}),
883 Clipperz.Async.or
884 ])
885 },
886
887 //=========================================================================
888 __syntaxFix__: "syntax fix"
889});
890
891
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Legacy.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Legacy.js
new file mode 100644
index 0000000..cda5a41
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Legacy.js
@@ -0,0 +1,182 @@
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.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Header.Legacy depends on Clipperz.PM.DataModel.User!";
26}
27
28if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
29
30Clipperz.PM.DataModel.User.Header.Legacy = function(args) {
31 //args = args || {};
32 Clipperz.PM.DataModel.User.Header.Legacy.superclass.constructor.apply(this, arguments);
33
34 this._retrieveRecordDetailFunction = args.retrieveRecordDetailFunction|| Clipperz.Base.exception.raise('MandatoryParameter');
35 this._records = null;
36 //this._directLogins = null;
37
38 return this;
39}
40
41
42Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.Legacy, Clipperz.PM.DataModel.EncryptedRemoteObject, {
43
44 'toString': function() {
45 return "Clipperz.PM.DataModel.User.Header.Legacy";
46 },
47
48 //-------------------------------------------------------------------------
49
50 'retrieveRecordDetailFunction': function () {
51 return this._retrieveRecordDetailFunction;
52 },
53
54 //-------------------------------------------------------------------------
55
56 'getRecordKey': function (aRecordReference) {
57 var deferredResult;
58
59 deferredResult = new Clipperz.Async.Deferred("User.Header.Legacy.getRecordKey", {trace:false});
60 deferredResult.addMethod(this, 'getRecordIndexData');
61 deferredResult.addCallback(MochiKit.Base.itemgetter('key'))
62 deferredResult.callback();
63
64 return deferredResult;
65 },
66
67 //=========================================================================
68
69 'getRecordIndexData': function (aRecordReference) {
70 return this.getValue('records.' + aRecordReference);
71 },
72
73 'updateRecordIndexData': function (aRecordReference, aKey, aValue) {
74 return this.setValue('records.' + aRecordReference + "." + aKey, aValue);
75 },
76
77 //-------------------------------------------------------------------------
78
79 'getDirectLoginIndexData': function (aDirectLoginReference) {
80 return this.getValue('directLogins.' + aDirectLoginReference);
81 },
82
83 'setDirectLoginIndexData': function (aDirectLoginReference, aKey, aValue) {
84 return this.setValue('directLogins.' + aDirectLoginReference + '.' + aKey, aValue);
85 },
86
87 'removeDirectLoginIndexData': function (aDirectLoginReference) {
88 return this.removeValue('directLogins.' + aDirectLoginReference);
89 },
90
91 //=========================================================================
92
93 'records': function () {
94 vardeferredResult;
95 var deferredLock;
96
97 deferredLock = this.getDeferredLockForKey('records');
98
99 deferredResult = new Clipperz.Async.Deferred("User.Header.Legacy.records", {trace:false});
100 deferredResult.acquireLock(deferredLock);
101 deferredResult.addCallback(MochiKit.Base.bind(function () {
102 var innerDeferredResult;
103
104 if (this._records == null) {
105 innerDeferredResult = new Clipperz.Async.Deferred("User.Header.Legacy.records <inner deferred>", {trace:false});
106 innerDeferredResult.collectResults({
107 'header': [
108 // MochiKit.Base.method(this, 'getObjectDataStore'),
109 // MochiKit.Base.methodcaller('values')
110 MochiKit.Base.method(this, 'values')
111 ],
112 'recordsStats': [
113 MochiKit.Base.method(this, 'getRemoteData'),
114 MochiKit.Base.itemgetter('recordsStats')
115 ]
116 });
117 innerDeferredResult.addCallback(MochiKit.Base.bind(function (someObjectData) {
118 var reference;
119
120 this._records = {};
121 // this._directLogins = {};
122
123 for (reference in someObjectData['header']['records']) {
124 varrecord;
125
126 record = new Clipperz.PM.DataModel.Record({
127 'reference': reference,
128 'retrieveKeyFunction': MochiKit.Base.method(this, 'getRecordKey'),
129 'retrieveRemoteDataFunction':this.retrieveRecordDetailFunction(),
130 // 'encryptedDataKeypath': 'data',
131 // 'encryptedVersionKeypath': 'version',
132
133 'retrieveIndexDataFunction':MochiKit.Base.method(this, 'getRecordIndexData'),
134 'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
135 'updateDate': someObjectData['recordsStats'][reference]['updateDate'],
136
137 'retrieveDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'getDirectLoginIndexData'),
138 'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
139 'removeDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'removeDirectLoginIndexData')
140 });
141
142 this._records[reference] = record;
143 }
144
145 for (reference in someObjectData['header']['directLogins']) {
146 vardirectLogin;
147 var record;
148
149 record = this._records[someObjectData['header']['directLogins'][reference]['record']];
150 if (record != null) {
151 directLogin = new Clipperz.PM.DataModel.DirectLogin({
152 'reference': reference,
153 'record': record//,
154 // 'retrieveIndexDataFunction':MochiKit.Base.method(this, 'getDirectLoginIndexData'),
155 // 'setIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
156 // 'removeIndexDataFunction': MochiKit.Base.method(this, 'removeDirectLoginIndexData')
157 });
158 } else {
159Clipperz.log("WARNING: DIRECT LOGIN without a matching RECORD!!");
160 }
161 }
162
163 return this._records;
164 }, this));
165 innerDeferredResult.callback();
166 } else {
167 innerDeferredResult = MochiKit.Async.succeed(this._records);
168 }
169
170 return innerDeferredResult;
171 }, this));
172 deferredResult.releaseLock(deferredLock);
173 deferredResult.callback();
174
175 return deferredResult;
176 },
177
178 //=========================================================================
179 __syntaxFix__: "syntax fix"
180});
181
182
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js
new file mode 100644
index 0000000..e82da47
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js
@@ -0,0 +1,117 @@
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.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Header.OneTimePasswords depends on Clipperz.PM.DataModel.User!";
26}
27if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
28
29//-----------------------------------------------------------------------------
30
31Clipperz.PM.DataModel.User.Header.OneTimePasswords = function(args) {
32 Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.constructor.apply(this, arguments);
33
34 this._oneTimePasswords = null;
35
36 return this;
37}
38
39//-----------------------------------------------------------------------------
40
41Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.OneTimePasswords, Clipperz.PM.DataModel.EncryptedRemoteObject, {
42
43 'toString': function() {
44 return "Clipperz.PM.DataModel.User.Header.OneTimePasswords";
45 },
46
47 //-------------------------------------------------------------------------
48/*
49 'packData': function (someData) { //++
50 var result;
51
52 result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.packData.apply(this, arguments);
53
54 return result;
55 },
56*/
57 //-------------------------------------------------------------------------
58/*
59 'packRemoteData': function (someData) {
60 var result;
61
62 result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.packRemoteData.apply(this, arguments);
63
64 return result;
65 },
66*/
67 //-------------------------------------------------------------------------
68/*
69 'prepareRemoteDataWithKey': function (aKey) {
70 var result;
71
72 result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.prepareRemoteDataWithKey.apply(this, arguments);
73
74 return result;
75 },
76*/
77 //=========================================================================
78
79 'oneTimePasswords': function () {
80 vardeferredResult;
81
82 deferredResult = new Clipperz.Async.Deferred("User.Header.OneTimePasswords.oneTimePasswords", {trace:false});
83 if (this._oneTimePasswords == null) {
84 deferredResult.addMethod(this, 'values')
85 deferredResult.addCallback(MochiKit.Base.bind(function (someData) {
86 varotpKey;
87
88 this._oneTimePasswords = {};
89
90 for (otpKey in someData) {
91 var otp;
92 var otpParameters;
93
94 otpParameters = Clipperz.Base.deepClone(someData[otpKey]);
95 otpParameters['reference'] = otpKey;
96
97 otp = new Clipperz.PM.DataModel.OneTimePassword(otpParameters);
98 this._oneTimePasswords[otpKey] = otp;
99 }
100
101 return this._oneTimePasswords;
102
103 }, this));
104 deferredResult.callback();
105 } else {
106 deferredResult = MochiKit.Async.succeed(this._oneTimePasswords);
107 }
108
109 return deferredResult;
110 },
111
112 //=========================================================================
113 __syntaxFix__: "syntax fix"
114});
115
116//-----------------------------------------------------------------------------
117
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Preferences.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Preferences.js
new file mode 100644
index 0000000..f1f95e8
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Preferences.js
@@ -0,0 +1,48 @@
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.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Header.Preferences depends on Clipperz.PM.DataModel.User!";
26}
27
28if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
29
30Clipperz.PM.DataModel.User.Header.Preferences = function(args) {
31 Clipperz.PM.DataModel.User.Header.Preferences.superclass.constructor.apply(this, arguments);
32
33 return this;
34}
35
36
37Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.Preferences, Clipperz.PM.DataModel.EncryptedRemoteObject, {
38
39 'toString': function() {
40 return "Clipperz.PM.DataModel.User.Header.Preferences";
41 },
42
43 //-------------------------------------------------------------------------
44 //=========================================================================
45 __syntaxFix__: "syntax fix"
46});
47
48
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js
new file mode 100644
index 0000000..5681f70
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js
@@ -0,0 +1,685 @@
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.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Header.RecordIndex depends on Clipperz.PM.DataModel.User!";
26}
27
28if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
29
30Clipperz.PM.DataModel.User.Header.RecordIndex = function(args) {
31 Clipperz.PM.DataModel.User.Header.RecordIndex.superclass.constructor.apply(this, arguments);
32
33 this._recordsData = new Clipperz.PM.DataModel.EncryptedRemoteObject({
34 'name':'recordsData',
35 'retrieveKeyFunction': args.retrieveKeyFunction,
36 'remoteData': {
37 'data': args.recordsData['data'],
38 'version': args.encryptedDataVersion,
39 'recordsStats': args.recordsStats
40 }//,
41 // 'encryptedDataKeypath': 'data',
42 // 'encryptedVersionKeypath': 'version'
43 });
44
45 this._directLoginsData = new Clipperz.PM.DataModel.EncryptedRemoteObject({
46 'name':'directLoginsData',
47 'retrieveKeyFunction': args.retrieveKeyFunction,
48 'remoteData': {
49 'data': args.directLoginsData['data'],
50 'version': args.encryptedDataVersion
51 }//,
52 // 'encryptedDataKeypath': 'data',
53 // 'encryptedVersionKeypath': 'version'
54 });
55
56 this._lock = new MochiKit.Async.DeferredLock();
57 this._transientState = null;
58
59 this._retrieveRecordDetailFunction = args.retrieveRecordDetailFunction|| Clipperz.Base.exception.raise('MandatoryParameter');
60 this._recordsIndex = args.recordsData['index'] || Clipperz.Base.exception.raise('MandatoryParameter');
61 this._directLoginsIndex = args.directLoginsData['index']|| Clipperz.Base.exception.raise('MandatoryParameter');
62
63 this._records = null;
64
65 return this;
66}
67
68
69Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.RecordIndex, Object, {
70
71 'toString': function() {
72 return "Clipperz.PM.DataModel.User.Header.RecordIndex";
73 },
74
75 //-------------------------------------------------------------------------
76
77 'retrieveRecordDetailFunction': function () {
78 return this._retrieveRecordDetailFunction;
79 },
80
81 //-------------------------------------------------------------------------
82
83 'recordsIndex': function () {
84 return this._recordsIndex;
85 },
86
87 'recordsData': function () {
88 return this._recordsData;
89 },
90
91 //-------------------------------------------------------------------------
92
93 'directLoginsIndex': function () {
94 return this._directLoginsIndex;
95 },
96
97 'directLoginsData': function () {
98 return this._directLoginsData;
99 },
100
101 //-------------------------------------------------------------------------
102
103 'lock': function () {
104 return this._lock;
105 },
106
107 //-------------------------------------------------------------------------
108
109 'transientState': function () {
110 if (this._transientState == null) {
111 this._transientState = new Clipperz.KeyValueObjectStore(/*{'name':'User.Header.RecordIndex.transientState [1]'}*/);
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 'getRecordKey': function (aRecordReference) {
128 return Clipperz.Async.callbacks("User.Header.RecordIndex.getRecordKey", [
129 MochiKit.Base.method(this, 'getRecordIndexData', aRecordReference),
130 MochiKit.Base.itemgetter('key')
131 ], {trace:false});
132 },
133
134 'setRecordKey': function (aRecordReference, aValue) {
135 return this.updateRecordIndexData(aRecordReference, 'key', aValue);
136 },
137
138 //-------------------------------------------------------------------------
139
140 'getRecordIndexData': function (aRecordReference) {
141 return this.recordsData().getValue(this.recordsIndex()[aRecordReference]);
142 },
143
144 //.........................................................................
145
146 'updateRecordIndexData': function (aRecordReference, aKey, aValue) {
147 return this.recordsData().setValue(this.recordsIndex()[aRecordReference]+'.'+aKey, aValue);
148 },
149
150 //-------------------------------------------------------------------------
151
152 'getDirectLoginIndexData': function (aDirectLoginReference) {
153 return this.directLoginsData().getValue(this.directLoginsIndex()[aDirectLoginReference]);
154 },
155
156 'setDirectLoginIndexData': function (aDirectLoginReference, aKey, aValue) {
157//if (MochiKit.Base.isUndefinedOrNull(this.directLoginsIndex()[aDirectLoginReference])) {
158 //throw "PIPPO";
159//}
160 return this.directLoginsData().setValue(this.directLoginsIndex()[aDirectLoginReference] + '.' + aKey, aValue);
161 },
162
163 'addDirectLoginIndexData': function (aDirectLoginReference) {
164 return this.directLoginsData().setValue(this.directLoginsIndex()[aDirectLoginReference], {});
165 },
166
167 'removeDirectLoginIndexData': function (aDirectLoginReference) {
168 return this.directLoginsData().removeValue(this.directLoginsIndex()[aDirectLoginReference])
169 },
170
171 //-------------------------------------------------------------------------
172
173 'records': function () {
174 vardeferredResult;
175
176 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.records", {trace:false});
177 deferredResult.acquireLock(this.lock());
178 deferredResult.addCallback(MochiKit.Base.bind(function () {
179 var innerDeferredResult;
180
181 if (this._records == null) {
182 innerDeferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.records <inner deferred>", {trace:false});
183 innerDeferredResult.collectResults({
184 'records': [
185 // MochiKit.Base.method(this.recordsData(), 'getObjectDataStore'),
186 // MochiKit.Base.methodcaller('values')
187 MochiKit.Base.method(this.recordsData(), 'values')
188 ],
189 'recordsStats': [
190 MochiKit.Base.method(this.recordsData(), 'getRemoteData'),
191 MochiKit.Base.itemgetter('recordsStats')
192 ],
193 'directLogins': [
194 // MochiKit.Base.method(this.directLoginsData(), 'getObjectDataStore'),
195 // MochiKit.Base.methodcaller('values')
196 MochiKit.Base.method(this.directLoginsData(), 'values')
197 ]
198 })
199 innerDeferredResult.addCallback(MochiKit.Base.bind(function (someData) {
200 var indexReference;
201 var recordsInvertedIndex;
202 var directLoginsInvertedIndex;
203
204 recordsInvertedIndex = Clipperz.PM.DataModel.User.Header.RecordIndex.invertIndex(this.recordsIndex());
205 directLoginsInvertedIndex= Clipperz.PM.DataModel.User.Header.RecordIndex.invertIndex(this.directLoginsIndex());
206
207 this._records = {};
208
209 for (indexReference in someData['records']) {
210 varrecord;
211 var reference;
212 var updateDate;
213
214 reference = recordsInvertedIndex[indexReference];
215
216 if (typeof(someData['recordsStats'][reference]) != 'undefined') {
217 updateDate = someData['recordsStats'][reference]['updateDate'];
218
219 record = new Clipperz.PM.DataModel.Record({
220 'reference': reference,
221 'retrieveKeyFunction': MochiKit.Base.method(this, 'getRecordKey'),
222 'retrieveRemoteDataFunction':this.retrieveRecordDetailFunction(),
223
224 'retrieveIndexDataFunction':MochiKit.Base.method(this, 'getRecordIndexData'),
225 'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
226 'updateDate': updateDate,
227
228 'retrieveDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'getDirectLoginIndexData'),
229 'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
230 'removeDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'removeDirectLoginIndexData'),
231
232 'createNewDirectLoginFunction': MochiKit.Base.method(this, 'createNewDirectLogin')
233 });
234
235 this._records[reference] = record;
236 } else {
237Clipperz.log("SKIPPING record " + reference + " as there are no stas associated - " + Clipperz.Base.serializeJSON(someData['records'][reference]));
238 //# skip the record, as it seems it is not present in the DB
239 //updateDate = Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
240 }
241 }
242
243 for (indexReference in someData['directLogins']) {
244 // vardirectLogin;
245 var reference;
246 var record;
247
248 reference = directLoginsInvertedIndex[indexReference];
249 record = this._records[recordsInvertedIndex[someData['directLogins'][indexReference]['record']]];
250
251 if (record != null) {
252 // directLogin = new Clipperz.PM.DataModel.DirectLogin({
253 new Clipperz.PM.DataModel.DirectLogin({
254 'reference': reference,
255 'record': record
256 });
257 } else {
258 Clipperz.logWarning("WARNING: DIRECT LOGIN without a matching RECORD!!");
259 }
260 }
261
262 return this._records;
263 }, this));
264 innerDeferredResult.callback();
265 } else {
266 innerDeferredResult = MochiKit.Async.succeed(this._records);
267 }
268
269 return innerDeferredResult;
270 }, this));
271 deferredResult.releaseLock(this.lock());
272 deferredResult.callback();
273
274 return deferredResult;
275 },
276
277 //-------------------------------------------------------------------------
278
279 'updateRecordIndexForNewRecord': function (aNewRecord) {
280 var newRecordIndex;
281 var recordReference;
282
283 recordReference = aNewRecord.reference();
284 newRecordIndex = (MochiKit.Base.listMax(MochiKit.Base.map(MochiKit.Base.partial(MochiKit.Base.operator.mul, 1), MochiKit.Base.values(this.recordsIndex()))) + 1) + '';
285 this.recordsIndex()[recordReference] = newRecordIndex;
286
287 this.transientState().setValue('newlyCreatedRecordsIndex' + '.' + recordReference, newRecordIndex);
288 this.transientState().setValue('newlyCreatedRecordsReferences'+ '.' + recordReference, aNewRecord);
289 },
290
291 //.........................................................................
292
293 'createNewRecord': function () {
294 var deferredResult;
295 var newRecord;
296
297 newRecord = new Clipperz.PM.DataModel.Record({
298 'retrieveKeyFunction': MochiKit.Base.method(this, 'getRecordKey'),
299 'retrieveRemoteDataFunction':this.retrieveRecordDetailFunction(),
300
301 'retrieveIndexDataFunction':MochiKit.Base.method(this, 'getRecordIndexData'),
302 'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
303 'updateDate': Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
304
305 'retrieveDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'getDirectLoginIndexData'),
306 'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
307 'removeDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'removeDirectLoginIndexData'),
308
309 'createNewDirectLoginFunction': MochiKit.Base.method(this, 'createNewDirectLogin')
310 });
311
312 this.transientState().setValue('newRecordsReferences' + '.' + newRecord.reference(), newRecord);
313 this.updateRecordIndexForNewRecord(newRecord);
314
315 deferredResult = Clipperz.Async.callbacks("User.Header.RecordIndex.createNewRecord", [
316 MochiKit.Base.method(this, 'records'),
317 MochiKit.Base.partial(Clipperz.Async.setItemOnObject, newRecord.reference(), newRecord),
318 MochiKit.Base.method(this, 'setRecordKey', newRecord.reference(), Clipperz.PM.Crypto.randomKey()),
319 MochiKit.Base.method(newRecord, 'setLabel', ''),
320 MochiKit.Base.partial(MochiKit.Async.succeed, newRecord)
321 ], {trace:false});
322
323
324 return deferredResult;
325 },
326
327 //-------------------------------------------------------------------------
328
329 'deleteRecord': function (aRecord) {
330 var deferredResult;
331 var recordReference;
332
333 recordReference = aRecord.reference();
334
335 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.deleteRecord", {trace:false});
336
337 deferredResult.addMethod(aRecord, 'directLogins');
338 deferredResult.addCallback(MochiKit.Base.values);
339 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'removeDirectLogin'));
340
341 deferredResult.addMethod(this.recordsData(), 'removeValue', this.recordsIndex()[recordReference]);
342 deferredResult.addCallback(MochiKit.Base.bind(function () {
343 this.transientState().setValue('deleteRecordsIndex' + '.' + recordReference, this.recordsIndex()[recordReference]);
344 delete this.recordsIndex()[recordReference];
345 }, this));
346
347 deferredResult.addMethod(this, 'records');
348 deferredResult.addCallback(MochiKit.Base.itemgetter(recordReference));
349 deferredResult.addMethod(this.transientState(), 'setValue', 'deleteRecordsReferences' + '.' + recordReference);
350
351 deferredResult.addMethod(this, 'records');
352 deferredResult.addCallback(MochiKit.Base.bind(function (someRecords) {
353 delete someRecords[recordReference];
354 }, this));
355 deferredResult.callback();
356
357 return deferredResult;
358 },
359
360 //=========================================================================
361
362 'removeDirectLogin': function (aDirectLogin) {
363 this.directLoginsData().removeValue(this.directLoginsIndex()[aDirectLogin.reference()]);
364 },
365
366 //-------------------------------------------------------------------------
367
368 'createNewDirectLogin': function (aRecord) {
369 var newDirectLogin;
370 varnewDirectLoginIndexValue;
371
372 newDirectLogin = new Clipperz.PM.DataModel.DirectLogin({record:aRecord});
373 newDirectLoginIndexValue = MochiKit.Base.listMax(MochiKit.Base.map(function (aValue) { return aValue * 1; }, MochiKit.Base.values(this.directLoginsIndex()))) + 1;
374
375 this.transientState().setValue('newDirectLoginReferences' + '.' + newDirectLogin.reference(), newDirectLogin);
376
377 this.directLoginsIndex()[newDirectLogin.reference()] = newDirectLoginIndexValue;
378 this.directLoginsData().setValue(this.directLoginsIndex()[newDirectLogin.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
379
380 return newDirectLogin;
381 },
382
383 //=========================================================================
384
385 'deleteAllCleanTextData': function () {
386 return Clipperz.Async.callbacks("User.Header.RecordIndex.deleteAllCleanTextData", [
387 // MochiKit.Base.method(this, 'records'),
388 // MochiKit.Base.values,
389 // MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('deleteAllCleanTextData')),
390
391 MochiKit.Base.method(this, 'recordsData'),
392 MochiKit.Base.methodcaller('deleteAllCleanTextData'),
393 MochiKit.Base.method(this, 'directLoginsData'),
394 MochiKit.Base.methodcaller('deleteAllCleanTextData')
395 ], {trace:false});
396 },
397
398 //-------------------------------------------------------------------------
399
400 'hasAnyCleanTextData': function () {
401 var deferredResult;
402
403 deferredResult = new Clipperz.Async.Deferred({trace:false});
404 deferredResult.collectResults({
405 'recordsData': [
406 MochiKit.Base.method(this, 'recordsData'),
407 MochiKit.Base.methodcaller('hasAnyCleanTextData')
408 ],
409 'directLoginsData':[
410 MochiKit.Base.method(this, 'directLoginsData'),
411 MochiKit.Base.methodcaller('hasAnyCleanTextData')
412 ],
413 // 'records': [
414 // MochiKit.Base.method(this, 'records'),
415 // MochiKit.Base.values,
416 // MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasAnyCleanTextData')),
417 // Clipperz.Async.collectAll
418 // ]
419 });
420
421 // deferredResult.addCallback(MochiKit.Base.values);
422 // deferredResult.addCallback(MochiKit.Base.flattenArguments);
423 // deferredResult.addCallback(function(someValues) {
424 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
425 // });
426 deferredResult.addCallback(Clipperz.Async.or);
427
428 deferredResult.callback();
429
430 return deferredResult;
431 },
432
433 //-------------------------------------------------------------------------
434
435 'hasPendingChanges': function () {
436 vardeferredResult;
437
438 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.hasPendingChanges", {trace:false});
439 deferredResult.collectResults({
440 'recordsData': [
441 MochiKit.Base.method(this, 'recordsData'),
442 MochiKit.Base.methodcaller('hasPendingChanges')
443 ],
444 'directLoginsData': [
445 MochiKit.Base.method(this, 'directLoginsData'),
446 MochiKit.Base.methodcaller('hasPendingChanges')
447 ]
448 });
449 deferredResult.addCallback(Clipperz.Async.or);
450 // deferredResult.addCallback(MochiKit.Base.values);
451 // deferredResult.addCallback(MochiKit.Base.flattenArguments);
452 // deferredResult.addCallback(function(someValues) {
453 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
454 // });
455 deferredResult.callback();
456
457 return deferredResult;
458 },
459
460 //-------------------------------------------------------------------------
461
462 'commitTransientState': function () {
463 var deferredResult;
464
465 deferredResut = Clipperz.Async.callbacks("User.Header.RecordIndex.commitTransientState", [
466 MochiKit.Base.method(this, 'recordsData'),
467 MochiKit.Base.methodcaller('commitTransientState'),
468
469 MochiKit.Base.method(this, 'directLoginsData'),
470 MochiKit.Base.methodcaller('commitTransientState'),
471
472 MochiKit.Base.method(this, 'resetTransientState', true)
473 ], {trace:false});
474
475 return deferredResult;
476 },
477
478 //-------------------------------------------------------------------------
479
480 'revertChanges': function () {
481 return Clipperz.Async.callbacks("User.Header.RecordIndex.revertChanges", [
482 MochiKit.Base.method(this, 'recordsData'),
483 MochiKit.Base.methodcaller('revertChanges'),
484
485 // MochiKit.Base.method(this, 'directLoginsData'),
486 // MochiKit.Base.methodcaller('revertChanges'),
487
488 MochiKit.Base.method(this, 'records'),
489 MochiKit.Base.bind(function (someRecords) {
490 varrecordReference;
491
492 for (recordReference in this.transientState().getValue('deleteRecordsReferences')) {
493 this.recordsIndex()[recordReference] = this.transientState().getValue('deleteRecordsIndex' + '.' + recordReference);
494 someRecords[recordReference] = this.transientState().getValue('deleteRecordsReferences' + '.' + recordReference);
495 }
496
497 for (recordReference in this.transientState().getValue('newRecordsReferences')) {
498 delete this.recordsIndex()[recordReference];
499 delete someRecords[recordReference];
500 }
501 }, this),
502
503 // MochiKit.Base.method(this, 'directLogins'),
504 MochiKit.Base.bind(function () {
505 vardirectLoginReference;
506
507 //this.transientState().setValue('newDirectLoginReferences' + '.' + newDirectLogin.reference(), newDirectLogin);
508//
509 //this.directLoginsIndex()[newDirectLogin.reference()] = newDirectLoginIndexValue;
510 //this.directLoginsData().setValue(this.directLoginsIndex()[newDirectLogin.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
511
512
513 // for (directLoginReference in this.transientState().getValue('deleteDirectLoginReferences')) {
514 // someDirectLogins[directLoginReference] = this.transientState().getValue('deleteDirectLoginReferences' + '.' + recordReference);
515 // }
516
517 for (directLoginReference in this.transientState().getValue('newDirectLoginReferences')) {
518 // this.directLoginsData().removeValue(this.directLoginsIndex()[directLoginReference]);
519 delete this.directLoginsIndex()[directLoginReference];
520 }
521 }, this),
522
523 MochiKit.Base.method(this, 'directLoginsData'),
524 MochiKit.Base.methodcaller('revertChanges'),
525
526 MochiKit.Base.method(this, 'resetTransientState', false)
527 ], {trace:false});
528 },
529
530 //-------------------------------------------------------------------------
531
532 'prepareRemoteDataWithKey': function (aKey) {
533 // "records": {
534 // "index": {
535 // "eeda70e0392261967bda71c3764da78989c45bbd2bb7be6b941b90f81d9b81b5": "0",
536 // "13a5e52976337ab210903cd04872588e1b21fb72bc183e91aa25c494b8138551": "1",
537 // ...
538 // "465a067a0bd2b470fa834de5397e38494de0c7707938262fae3427932e219744": "18",
539 // "4fd1dc2ca860b7fb47cef10a84edb3270da05510b0a30a6b0b083898712d4b9e": "19"
540 // },
541 // "data": "n+AzGEEQXaSRSY4d ... BDypotrXgPo94uHfoXvGFzwCn8w="
542 // },
543 // "directLogins": {
544 // "index": {
545 // "61e87fdc4f1d9112e3b30c1f6812d095dcdb24f014c83319091eb6c9899ec348":"0",
546 // "989593d4c48929f0c8f1581aa96969c622807e99619ed4732026e967530a68ad":"1",
547 // ...
548 // "cb9ae0bba1957075ccdbfd3b3481704d62087687a2ac7c411a4f07d444bde0f7":"17",
549 // "7e1d069b7fa57c03bd7bf48807520feb953157834503aaff8c9d493f37dea69d":"18"
550 // },
551 // "data":"5YG9KKU/OZ5guUgFlms6k1 ... ZG/5Fn0uN+LoAsNfHm+EE62x"
552 // },
553
554 var deferredResult;
555 var result;
556
557 result = {};
558
559 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.prepareRemoteDataWithKey", {trace:false});
560 deferredResult.collectResults({
561 'index':MochiKit.Base.partial(MochiKit.Async.succeed, this.recordsIndex()),
562 'data': [
563 MochiKit.Base.method(this.recordsData(), 'prepareRemoteDataWithKey', aKey),
564 MochiKit.Base.itemgetter('data')
565 ]
566 });
567 deferredResult.addCallback(Clipperz.Async.setItem, result, 'records');
568
569 deferredResult.collectResults({
570 'index':MochiKit.Base.partial(MochiKit.Async.succeed, this.directLoginsIndex()),
571 'data': [
572 MochiKit.Base.method(this.directLoginsData(), 'prepareRemoteDataWithKey', aKey),
573 MochiKit.Base.itemgetter('data')
574 ]
575 });
576 deferredResult.addCallback(Clipperz.Async.setItem, result, 'directLogins');
577
578 deferredResult.addCallback(MochiKit.Async.succeed, result);
579
580 deferredResult.callback();
581
582 return deferredResult;
583 },
584
585 //-------------------------------------------------------------------------
586
587 'updateRecordKeyAndPrepareRemoteData': function (aRecord) {
588 varnewRecordKey;
589 var deferredResult;
590
591 newRecordKey = Clipperz.PM.Crypto.randomKey();
592
593 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.updateRecordKeyAndPrepareRemoteData", {trace:false});
594 deferredResult.addCallback(MochiKit.Base.method(aRecord, 'prepareRemoteDataWithKey', newRecordKey));
595 deferredResult.addCallbackPass(MochiKit.Base.method(this, 'setRecordKey', aRecord.reference(), newRecordKey));
596 deferredResult.callback();
597
598 return deferredResult;
599 },
600
601 //.........................................................................
602
603 'removeNewRecordWithNoChanges': function (aRecord) {
604 var deferredResult;
605 var recordReference;
606
607 recordReference = aRecord.reference();
608
609 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.removeNewRecordWithNoChanges", {trace:false});
610
611 deferredResult.addMethod(this.recordsData(), 'removeValue', this.recordsIndex()[recordReference]);
612 deferredResult.addCallback(MochiKit.Base.bind(function () {
613 delete this.recordsIndex()[recordReference];
614 }, this));
615
616 deferredResult.addMethod(this, 'records');
617 deferredResult.addCallback(MochiKit.Base.bind(function (someRecords) {
618 delete someRecords[recordReference];
619 }, this));
620 deferredResult.callback();
621
622 return deferredResult;
623 },
624
625 //.........................................................................
626
627 'prepareRemoteDataForChangedRecords': function () {
628 vardeferredResult;
629 varresult;
630
631 result = {};
632
633 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.prepareRemoteDataForChangedRecords", {trace:false});
634
635 deferredResult.addMethod(this, 'records');
636 deferredResult.addCallback(MochiKit.Base.values);
637 deferredResult.addCallback(Clipperz.Async.deferredFilter, MochiKit.Base.methodcaller('isBrandNewWithNoPendingChanges'));
638 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'removeNewRecordWithNoChanges'));
639
640 deferredResult.addMethod(this, 'records');
641 deferredResult.addCallback(MochiKit.Base.values);
642 deferredResult.addCallback(Clipperz.Async.deferredFilter, MochiKit.Base.methodcaller('hasPendingChanges'));
643 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'updateRecordKeyAndPrepareRemoteData'));
644 deferredResult.addCallback(Clipperz.Async.collectAll);
645
646 deferredResult.addCallback(Clipperz.Async.deferredIf("updated records != null", [
647 MochiKit.Base.operator.identity
648 ], [
649 MochiKit.Base.partial(MochiKit.Async.succeed, [])
650 ]));
651 deferredResult.addCallback(Clipperz.Async.setItem, result, 'updated');
652
653 deferredResult.addMethod(this.transientState(), 'getValue', 'deleteRecordsReferences');
654 deferredResult.addCallback(MochiKit.Base.keys);
655 deferredResult.addCallback(Clipperz.Async.deferredIf("deleted records != null", [
656 MochiKit.Base.operator.identity
657 ], [
658 MochiKit.Base.partial(MochiKit.Async.succeed, [])
659 ]));
660 deferredResult.addCallback(Clipperz.Async.setItem, result, 'deleted');
661
662 deferredResult.addCallback(MochiKit.Async.succeed, result);
663 deferredResult.callback();
664
665 return deferredResult;
666 },
667
668 //-------------------------------------------------------------------------
669 __syntaxFix__: "syntax fix"
670});
671
672
673
674Clipperz.PM.DataModel.User.Header.RecordIndex.invertIndex = function (anIndex) {
675 var result;
676 var key;
677
678 result = {};
679
680 for (key in anIndex) {
681 result[anIndex[key]] = key;
682 }
683
684 return result;
685}; \ No newline at end of file
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Subscription.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Subscription.js
new file mode 100644
index 0000000..341e9f3
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Subscription.js
@@ -0,0 +1,53 @@
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.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Subscription depends on Clipperz.PM.DataModel.User!";
26}
27
28Clipperz.PM.DataModel.User.Subscription = function(args) {
29 this._attributes = args;
30 return this;
31}
32
33
34Clipperz.Base.extend(Clipperz.PM.DataModel.User.Subscription, Object, {
35
36 'features': function () {
37 return this._attributes['features'];
38 },
39
40 'type': function () {
41 return this._attributes['type'];
42 },
43
44 'validity': function () {
45 return {
46 'from':this._attributes['fromDate'],
47 'to':this._attributes['toDate']
48 };
49 },
50
51 //=========================================================================
52 __syntaxFix__: "syntax fix"
53});
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.js b/frontend/delta/js/Clipperz/PM/DataModel/User.js
new file mode 100644
index 0000000..1d90800
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.js
@@ -0,0 +1,827 @@
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
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29//#############################################################################
30
31Clipperz.PM.DataModel.User = function (args) {
32 args = args || {};
33
34 Clipperz.PM.DataModel.User.superclass.constructor.apply(this, arguments);
35
36 this._username = args.username || null;
37 this._getPassphraseFunction = args.getPassphraseFunction || null;
38
39 this._data = null;
40
41 this._connection = null;
42 this._connectionVersion = 'current';
43
44 this._subscription = null;
45 this._serverData = null;
46 //this._serverLockValue = null;
47 this._transientState = null;
48
49 this._deferredLocks = {
50 'passphrase': new MochiKit.Async.DeferredLock(),
51 'serverData': new MochiKit.Async.DeferredLock(),
52 // 'recordsIndex': new MochiKit.Async.DeferredLock(),
53 // 'directLoginsIndex':new MochiKit.Async.DeferredLock()
54 // 'preferences': new MochiKit.Async.DeferredLock()
55 // 'oneTimePasswords': new MochiKit.Async.DeferredLock()
56 '__syntaxFix__': 'syntax fix'
57 };
58
59 return this;
60}
61
62Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
63
64 'toString': function () {
65 return "Clipperz.PM.DataModel.User - " + this.username();
66 },
67
68 //-------------------------------------------------------------------------
69
70 'username': function () {
71 return this._username;
72 },
73
74 'setUsername': function (aValue) {
75 this._username = aValue;
76 },
77
78 //-------------------------------------------------------------------------
79
80 //this.setSubscription(new Clipperz.PM.DataModel.User.Subscription(someServerData['subscription']));
81 'subscription': function () {
82 return this._subscription;
83 },
84
85 'setSubscription': function (aValue) {
86 this._subscription = aValue;
87 },
88
89 //-------------------------------------------------------------------------
90
91 'displayName': function() {
92 return "" + this.username() + "";
93 },
94
95 //-------------------------------------------------------------------------
96
97 'data': function () {
98 if (this._data == null) {
99 this._data = new Clipperz.KeyValueObjectStore(/*{'name':'User.data [1]'}*/);
100 };
101
102 return this._data;
103 },
104
105 //-------------------------------------------------------------------------
106/*
107 'serverLockValue': function () {
108 return this._serverLockValue;
109 },
110
111 'setServerLockValue': function (aValue) {
112 this._serverLockValue = aValue;
113 },
114*/
115 //-------------------------------------------------------------------------
116
117 'transientState': function () {
118 if (this._transientState == null) {
119 this._transientState = {}
120 }
121
122 return this._transientState;
123 },
124
125 'resetTransientState': function (isCommitting) {
126 this._transientState = null;
127 },
128
129 //-------------------------------------------------------------------------
130
131 'deferredLockForSection': function(aSectionName) {
132 return this._deferredLocks[aSectionName];
133 },
134
135 //-------------------------------------------------------------------------
136
137 'getPassphrase': function() {
138 var deferredResult;
139
140 deferredResult = new Clipperz.Async.Deferred("User.getPassphrase", {trace:false});
141 deferredResult.acquireLock(this.deferredLockForSection('passphrase'));
142 deferredResult.addMethod(this.data(), 'deferredGetOrSet', 'passphrase', this.getPassphraseFunction());
143 deferredResult.releaseLock(this.deferredLockForSection('passphrase'));
144 deferredResult.callback();
145
146 return deferredResult;
147 },
148
149 'getPassphraseFunction': function () {
150 return this._getPassphraseFunction;
151 },
152
153 //-------------------------------------------------------------------------
154
155 'getCredentials': function () {
156 return Clipperz.Async.collectResults("User; get username and passphrase", {
157 'username': MochiKit.Base.method(this, 'username'),
158 'password': MochiKit.Base.method(this, 'getPassphrase')
159 }, {trace:false})();
160 },
161
162 //-------------------------------------------------------------------------
163
164 'changePassphrase': function (aNewValue) {
165 return this.updateCredentials(this.username(), aNewValue);
166 },
167
168 //.........................................................................
169
170 'updateCredentials': function (aUsername, aPassphrase) {
171 vardeferredResult;
172
173 deferredResult = new Clipperz.Async.Deferred("User.updateCredentials", {trace:false});
174 // deferredResult.addMethod(this, 'getPassphrase');
175 // deferredResult.setValue('currentPassphrase');
176 deferredResult.addMethod(this.connection(), 'ping');
177 deferredResult.addMethod(this, 'setUsername', aUsername)
178 deferredResult.acquireLock(this.deferredLockForSection('passphrase'));
179 deferredResult.addMethod(this.data(), 'deferredGetOrSet', 'passphrase', aPassphrase);
180 deferredResult.releaseLock(this.deferredLockForSection('passphrase'));
181 // deferredResult.getValue('currentPassphrase');
182 deferredResult.addMethod(this, 'prepareRemoteDataWithKey', aPassphrase);
183 deferredResult.addMethod(this.connection(), 'updateCredentials', aUsername, aPassphrase);
184 deferredResult.callback();
185
186 return deferredResult;
187 },
188
189 //-------------------------------------------------------------------------
190
191 'initialSetupWithNoData': function () {
192 this._serverData = {
193 'version': '0.1',
194 'statistics': "",
195 'header': {
196 'data': null,
197 'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion,
198
199 'recordsIndex': new Clipperz.PM.DataModel.User.Header.RecordIndex({
200 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
201 'recordsData': {'data':null, 'index':{}},
202 'recordsStats': null,
203 'directLoginsData': {'data':null, 'index':{}},
204 'encryptedDataVersion': Clipperz.PM.Crypto.encryptingFunctions.currentVersion,
205 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail')
206 }),
207 'preferences': new Clipperz.PM.DataModel.User.Header.Preferences({
208 'name':'preferences',
209 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
210 }),
211 'oneTimePasswords': new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
212 'name':'preferences',
213 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
214 })
215 }
216 };
217
218 // this._serverLockValue = Clipperz.PM.Crypto.randomKey();
219 },
220
221 //.........................................................................
222
223 'registerAsNewAccount': function () {
224 var deferredResult;
225
226 deferredResult = new Clipperz.Async.Deferred("User.registerAsNewAccount", {trace:false});
227 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':3});
228 deferredResult.addMethod(this, 'initialSetupWithNoData')
229 deferredResult.addMethod(this, 'getPassphrase');
230 deferredResult.addMethod(this, 'prepareRemoteDataWithKey');
231 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
232 deferredResult.addMethod(this.connection(), 'register');
233 // deferredResult.addCallback(MochiKit.Base.itemgetter('lock'));
234 // deferredResult.addMethod(this, 'setServerLockValue');
235 // deferredResult.addCallbackPass(MochiKit.Signal.signal,Clipperz.Signal.NotificationCenter, 'userSuccessfullyRegistered');
236
237 // deferredResult.addErrback (MochiKit.Base.method(this, 'handleRegistrationFailure'));
238
239 deferredResult.callback();
240
241 return deferredResult;
242 },
243
244 //-------------------------------------------------------------------------
245
246 'login': function () {
247 var deferredResult;
248
249 deferredResult = new Clipperz.Async.Deferred("User.login", {trace:false});
250 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':3});
251 deferredResult.addMethod(this, 'getPassphrase');
252 deferredResult.addCallback(Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue);
253 deferredResult.addCallback(Clipperz.Async.deferredIf("Is the passphrase an OTP", [
254 // MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':1}),
255 MochiKit.Base.method(this, 'getCredentials'),
256 MochiKit.Base.method(this.connection(), 'redeemOneTimePassword'),
257 MochiKit.Base.method(this.data(), 'setValue', 'passphrase')
258 ], []));
259 deferredResult.addErrback(MochiKit.Base.method(this, 'getPassphrase'));
260 deferredResult.addMethod(this.connection(), 'login', false);
261 deferredResult.addMethod(this, 'setupConnectionInfo');
262 // deferredResult.addCallbackPass(MochiKit.Signal.signal,Clipperz.Signal.NotificationCenter, 'userSuccessfullyLoggedIn');
263 deferredResult.addErrback (MochiKit.Base.method(this, 'handleConnectionFallback'));
264
265 deferredResult.callback();
266
267 return deferredResult;
268 },
269
270 //.........................................................................
271
272 'handleConnectionFallback': function(aValue) {
273 var result;
274
275//console.log("USER - handleConnectionFallback", aValue, aValue['isPermanent']);
276 if (aValue instanceof MochiKit.Async.CancelledError) {
277 result = aValue;
278 } else if ((aValue['isPermanent'] === true) || (Clipperz.PM.Connection.communicationProtocol.fallbackVersions[this.connectionVersion()] == null)) {
279 result = Clipperz.Async.callbacks("User.handleConnectionFallback - failed", [
280 MochiKit.Base.method(this.data(), 'removeValue', 'passphrase'),
281 MochiKit.Base.method(this, 'setConnectionVersion', 'current'),
282 // MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userLoginFailed'),
283 // MochiKit.Base.partial(MochiKit.Async.fail, Clipperz.PM.DataModel.User.exception.LoginFailed)
284 MochiKit.Base.partial(MochiKit.Async.fail, aValue)
285 ], {trace:false});
286 } else {
287 this.setConnectionVersion(Clipperz.PM.Connection.communicationProtocol.fallbackVersions[this.connectionVersion()]);
288 result = new Clipperz.Async.Deferred("User.handleConnectionFallback - retry");
289 result.addMethod(this, 'login');
290 result.callback();
291 }
292
293 return result;
294 },
295
296 //-------------------------------------------------------------------------
297
298 'setupConnectionInfo': function (aValue) {
299 // this.setLoginInfo(aValue['loginInfo']);
300 this.setSubscription(new Clipperz.PM.DataModel.User.Subscription(aValue['subscription']));
301 },
302
303 //-------------------------------------------------------------------------
304
305 'lock': function () {
306 return Clipperz.Async.callbacks("User.lock", [
307 MochiKit.Base.method(this, 'deleteAllCleanTextData')
308 ], {trace:false});
309 },
310
311 //-------------------------------------------------------------------------
312
313 'logout': function () {
314 return Clipperz.Async.callbacks("User.logout", [
315 MochiKit.Base.method(this, 'deleteAllCleanTextData'),
316 MochiKit.Base.method(this.connection(), 'logout')
317 ], {trace:false});
318 },
319
320 //-------------------------------------------------------------------------
321
322 'headerFormatVersion': function(anHeader) {
323 var result;
324
325 if (anHeader.charAt(0) == '{') {
326 varheaderData;
327
328 headerData = Clipperz.Base.evalJSON(anHeader);
329 result = headerData['version'];
330 } else {
331 result = 'LEGACY';
332 }
333
334 return result;
335 },
336
337 //-------------------------------------------------------------------------
338
339 'unpackServerData': function (someServerData) {
340 var unpackedData;
341 var headerVersion;
342
343 varrecordsIndex;
344 var preferences;
345 var oneTimePasswords;
346
347 // this.setServerLockValue(someServerData['lock']);
348
349 headerVersion = this.headerFormatVersion(someServerData['header']);
350 switch (headerVersion) {
351 case 'LEGACY':
352 varlegacyHeader;
353
354 legacyHeader = new Clipperz.PM.DataModel.User.Header.Legacy({
355 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
356 'remoteData': {
357 'data': someServerData['header'],
358 'version': someServerData['version'],
359 'recordsStats': someServerData['recordsStats']
360 },
361 // 'encryptedDataKeypath': 'data',
362 // 'encryptedVersionKeypath': 'version',
363 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail')
364 });
365
366 recordsIndex = legacyHeader;
367 preferences = legacyHeader;
368 oneTimePasswords= legacyHeader;
369 break;
370 case '0.1':
371 varheaderData;
372
373 headerData = Clipperz.Base.evalJSON(someServerData['header']);
374
375 recordsIndex = new Clipperz.PM.DataModel.User.Header.RecordIndex({
376 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
377 'recordsData': headerData['records'],
378 'recordsStats': someServerData['recordsStats'],
379 'directLoginsData': headerData['directLogins'],
380 'encryptedDataVersion': someServerData['version'],
381 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail')
382 });
383
384 //Still missing a test case that actually fais with the old version of the code, where the check for undefined was missing
385 if (typeof(headerData['preferences']) != 'undefined') {
386 preferences= new Clipperz.PM.DataModel.User.Header.Preferences({
387 'name':'preferences',
388 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
389 'remoteData': {
390 'data': headerData['preferences']['data'],
391 'version': someServerData['version']
392 }
393 });
394 } else {
395 preferences= new Clipperz.PM.DataModel.User.Header.Preferences({
396 'name':'preferences',
397 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
398 });
399 }
400
401 if (typeof(headerData['oneTimePasswords']) != 'undefined') {
402 oneTimePasswords = new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
403 'name':'preferences',
404 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
405 'remoteData': {
406 'data': headerData['oneTimePasswords']['data'],
407 'version': someServerData['version']
408 }
409 });
410 } else {
411 oneTimePasswords = new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
412 'name':'preferences',
413 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
414 });
415 }
416
417 break;
418 }
419
420 unpackedData = {
421 'version': someServerData['version'],
422 'statistics': someServerData['statistics'],
423 'header': {
424 'data': someServerData['header'],
425 'version': headerVersion,
426
427 'recordsIndex': recordsIndex,
428 'preferences': preferences,
429 'oneTimePasswords': oneTimePasswords
430 }
431 };
432
433 this._serverData = unpackedData;
434
435 return this._serverData;
436 },
437
438 //-------------------------------------------------------------------------
439
440 'getServerData': function() {
441 var deferredResult;
442
443 deferredResult = new Clipperz.Async.Deferred("User.getServerData", {trace:false});
444 deferredResult.acquireLock(this.deferredLockForSection('serverData'));
445 deferredResult.addCallback(MochiKit.Base.bind(function(aResult) {
446 var innerDeferredResult;
447
448 innerDeferredResult = new Clipperz.Async.Deferred("User.getUserDetails.innerDeferred", {trace:false});
449 if (this._serverData == null) {
450 innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadingUserDetails');
451 innerDeferredResult.addMethod(this.connection(), 'message', 'getUserDetails');
452 innerDeferredResult.addMethod(this, 'unpackServerData');
453 innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadedUserDetails');
454 }
455
456 innerDeferredResult.addCallback(MochiKit.Base.bind(function () {
457 return this._serverData;
458 },this));
459 innerDeferredResult.callback();
460
461 return innerDeferredResult;
462 }, this));
463 deferredResult.releaseLock(this.deferredLockForSection('serverData'));
464 deferredResult.callback();
465
466 return deferredResult;
467 },
468
469 //-------------------------------------------------------------------------
470
471 'connectionVersion': function() {
472 return this._connectionVersion;
473 },
474
475 'setConnectionVersion': function(aValue) {
476 if (this._connectionVersion != aValue) {
477 this.resetConnection();
478 }
479 this._connectionVersion = aValue;
480 },
481
482 //-------------------------------------------------------------------------
483
484 'connection': function() {
485 if ((this._connection == null) && (this.connectionVersion() != null) ){
486 this._connection = new Clipperz.PM.Connection.communicationProtocol.versions[this.connectionVersion()]({
487 getCredentialsFunction: MochiKit.Base.method(this, 'getCredentials')
488 });
489 }
490
491 return this._connection;
492 },
493
494 'resetConnection': function(aValue) {
495 if (this._connection != null) {
496 this._connection.reset();
497 }
498
499 this._connection = null;
500 },
501
502 //=========================================================================
503
504 'getHeaderIndex': function (aKey) {
505 return Clipperz.Async.callbacks("User.getHeaderIndex", [
506 MochiKit.Base.method(this, 'getServerData'),
507 MochiKit.Base.itemgetter('header'),
508 MochiKit.Base.itemgetter(aKey)
509 ], {trace:false})
510 },
511
512 //=========================================================================
513
514 'getRecords': function () {
515 return Clipperz.Async.callbacks("User.getRecords", [
516 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
517 MochiKit.Base.methodcaller('records'),
518 MochiKit.Base.values
519 ], {trace:false});
520 },
521
522 'recordWithLabel': function (aLabel) {
523 return Clipperz.Async.callbacks("User.recordWithLabel", [
524 MochiKit.Base.method(this, 'getRecords'),
525 MochiKit.Base.partial(Clipperz.Async.deferredFilter, function (aRecord) {
526 return Clipperz.Async.callbacks("User.recordWithLabel - check record label", [
527 MochiKit.Base.methodcaller('label'),
528 MochiKit.Base.partial(MochiKit.Base.operator.eq, aLabel)
529 ], {trace:false}, aRecord);
530 }),
531 function (someFilteredResults) {
532 var result;
533
534 switch (someFilteredResults.length) {
535 case 0:
536 result = null;
537 break;
538 case 1:
539 result = someFilteredResults[0];
540 break;
541 default:
542 WTF = TODO;
543 break;
544 }
545
546 return result;
547 }
548 ], {trace:false});
549 },
550
551 //-------------------------------------------------------------------------
552
553 'getRecord': function (aRecordReference) {
554 return Clipperz.Async.callbacks("User.getRecord", [
555 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
556 MochiKit.Base.methodcaller('records'),
557 MochiKit.Base.itemgetter(aRecordReference),
558
559 Clipperz.Async.deferredIf("record != null", [
560 MochiKit.Base.operator.identity
561 ], [
562 function () { throw "Record does not exists"}
563 ])
564 ], {trace:false});
565 },
566
567 //-------------------------------------------------------------------------
568
569 'getRecordDetail': function (aRecordReference) {
570 return this.connection().message('getRecordDetail', {reference: aRecordReference});
571 },
572
573 //-------------------------------------------------------------------------
574
575 'deleteRecord': function (aRecord) {
576 return Clipperz.Async.callbacks("User.deleteRecord", [
577 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
578 MochiKit.Base.methodcaller('deleteRecord', aRecord)
579 ], {trace:false});
580 },
581
582 //-------------------------------------------------------------------------
583
584 'createNewRecord': function () {
585 return Clipperz.Async.callbacks("User.createNewRecord", [
586 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
587 MochiKit.Base.methodcaller('createNewRecord')
588 ], {trace:false});
589 },
590
591 //=========================================================================
592
593 'getDirectLogins': function() {
594 var deferredResult;
595
596 deferredResult = new Clipperz.Async.Deferred("User.getDirectLogins", {trace:false});
597 deferredResult.addMethod(this, 'getRecords');
598 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.compose(MochiKit.Base.values, MochiKit.Base.methodcaller('directLogins')));
599 deferredResult.addCallback(MochiKit.Base.flattenArray);
600 deferredResult.callback();
601
602 return deferredResult;
603 },
604
605 //=========================================================================
606
607 'getOneTimePasswords': function () {
608 return Clipperz.Async.callbacks("User.getOneTimePasswords", [
609 MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
610 MochiKit.Base.methodcaller('oneTimePasswords'),
611 MochiKit.Base.values
612 ], {trace:false});
613 },
614
615 //=========================================================================
616
617 'invokeMethodNamedOnHeader': function (aMethodName, aValue) {
618 return Clipperz.Async.collectResults("User.invokeMethodNamedOnHeader [" + aMethodName + "]", {
619 'recordIndex': [
620 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
621 MochiKit.Base.methodcaller(aMethodName, aValue)
622 ],
623 'preferences': [
624 MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'),
625 MochiKit.Base.methodcaller(aMethodName, aValue)
626 ],
627 'oneTimePasswords': [
628 MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
629 MochiKit.Base.methodcaller(aMethodName, aValue)
630 ]//,
631 // 'statistics': [
632 // MochiKit.Base.method(this, 'getStatistics'),
633 // MochiKit.Base.methodcaller(aMethodName, aValue)
634 // ]
635 }, {trace:false})();
636 },
637
638 //-------------------------------------------------------------------------
639
640 'invokeMethodNamedOnRecords': function (aMethodName, aValue) {
641 return Clipperz.Async.callbacks("User.invokeMethodNamedOnRecords[" + aMethodName + "]", [
642 MochiKit.Base.method(this, 'getRecords'),
643 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller(aMethodName, aValue)),
644 Clipperz.Async.collectAll
645 ], {trace:false});
646 },
647
648 //=========================================================================
649
650 'hasPendingChanges': function () {
651 vardeferredResult;
652
653 deferredResult = new Clipperz.Async.Deferred("User.hasPendingChanges", {trace:false});
654 deferredResult.collectResults({
655 'header': [
656 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'hasPendingChanges'),
657 MochiKit.Base.values
658 ],
659 'records': MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'hasPendingChanges')
660 });
661 deferredResult.addCallback(Clipperz.Async.or);
662 deferredResult.callback();
663 // recordsIndex = legacyHeader;
664 // preferences = legacyHeader;
665 // oneTimePasswords= legacyHeader;
666
667 return deferredResult;
668 },
669
670 //=========================================================================
671
672 'commitTransientState': function () {
673 return Clipperz.Async.callbacks("User.commitTransientState", [
674 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'commitTransientState'),
675 MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'commitTransientState'),
676
677 MochiKit.Base.method(this, 'transientState'),
678 // MochiKit.Base.itemgetter('lock'),
679 // MochiKit.Base.method(this, 'setServerLockValue'),
680 MochiKit.Base.method(this, 'resetTransientState', true)
681 ], {trace:false});
682 },
683
684 //-------------------------------------------------------------------------
685
686 'revertChanges': function () {
687 return Clipperz.Async.callbacks("User.revertChanges", [
688 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'revertChanges'),
689 MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'revertChanges'),
690 MochiKit.Base.method(this, 'resetTransientState', false)
691 ], {trace:false});
692 },
693
694 //=========================================================================
695
696 'deleteAllCleanTextData': function () {
697 return Clipperz.Async.callbacks("User.deleteAllCleanTextData", [
698 MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'deleteAllCleanTextData'),
699 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'deleteAllCleanTextData'),
700
701 MochiKit.Base.method(this.data(), 'removeAllData'),
702 MochiKit.Base.method(this, 'resetTransientState', false)
703 ], {trace:false});
704 },
705
706 //-------------------------------------------------------------------------
707
708 'hasAnyCleanTextData': function () {
709 vardeferredResult;
710
711 deferredResult = new Clipperz.Async.Deferred("User.hasAnyCleanTextData", {trace:false});
712 deferredResult.collectResults({
713 'header':[
714 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'hasAnyCleanTextData'),
715 MochiKit.Base.values
716 ],
717 'records':MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'hasAnyCleanTextData'),
718 'data': MochiKit.Base.bind(function () {
719 return MochiKit.Async.succeed(! this.data().isEmpty());
720 }, this),
721 'transientState':MochiKit.Base.bind(function () {
722 return MochiKit.Async.succeed(MochiKit.Base.keys(this.transientState()).length != 0);
723 }, this)
724 });
725 deferredResult.addCallback(Clipperz.Async.or);
726 deferredResult.callback();
727
728 return deferredResult;
729 },
730
731 //=========================================================================
732
733 'prepareRemoteDataWithKey': function (aKey /*, aCurrentKey*/) {
734 var deferredResult;
735 varresult;
736
737 result = {};
738 deferredResult = new Clipperz.Async.Deferred("User.prepareRemoteDataWithKey", {trace:false});
739 deferredResult.addMethod(this, 'invokeMethodNamedOnHeader', 'prepareRemoteDataWithKey', aKey /*, aCurrentKey*/);
740 deferredResult.addCallback(MochiKit.Base.bind(function (aResult, someHeaderPackedData) {
741 var header;
742
743 header = {};
744 header['records'] = someHeaderPackedData['recordIndex']['records'];
745 header['directLogins'] = someHeaderPackedData['recordIndex']['directLogins'];
746 header['preferences'] = {'data': someHeaderPackedData['preferences']['data']};
747 header['oneTimePasswords']= {'data': someHeaderPackedData['oneTimePasswords']['data']};
748 header['version'] = '0.1';
749
750 aResult['header'] = Clipperz.Base.serializeJSON(header);
751 aResult['statistics'] = this._serverData['statistics']; //"someHeaderPackedData['statistics']['data']";
752
753 return aResult;
754 }, this), result);
755 deferredResult.addCallback(Clipperz.Async.setItem, result, 'version', Clipperz.PM.Crypto.encryptingFunctions.currentVersion);
756 // deferredResult.addCallback(Clipperz.Async.setItem, result, 'lock', this.serverLockValue());
757 deferredResult.callback();
758
759 return deferredResult;
760 },
761
762 //=========================================================================
763
764 'saveChanges': function () {
765 vardeferredResult;
766 var messageParameters;
767
768 messageParameters = {};
769
770 deferredResult = new Clipperz.Async.Deferred("User.saveChangaes", {trace:false});
771
772 deferredResult.addMethod(this, 'getHeaderIndex', 'recordsIndex');
773 deferredResult.addCallback(MochiKit.Base.methodcaller('prepareRemoteDataForChangedRecords'));
774 deferredResult.addCallback(Clipperz.Async.setItem, messageParameters, 'records');
775 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
776
777 deferredResult.addMethod(this, 'getPassphrase');
778 deferredResult.addMethod(this, 'prepareRemoteDataWithKey');
779 deferredResult.addCallback(Clipperz.Async.setItem, messageParameters, 'user');
780 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
781
782 deferredResult.addCallback(MochiKit.Async.succeed, messageParameters);
783 deferredResult.addMethod(this.connection(), 'message', 'saveChanges');
784 deferredResult.addCallback(MochiKit.Base.update, this.transientState())
785 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
786
787 deferredResult.addMethod(this, 'commitTransientState');
788 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
789 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userDataSuccessfullySaved');
790
791 deferredResult.addErrbackPass(MochiKit.Base.method(this, 'revertChanges'));
792 // deferredResult.addErrbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'failureWhileSavingUserData');
793
794 deferredResult.callback();
795
796 return deferredResult;
797 },
798
799 //=========================================================================
800 __syntaxFix__: "syntax fix"
801});
802
803//-----------------------------------------------------------------------------
804
805Clipperz.PM.DataModel.User.registerNewAccount = function (anUsername, aPassphraseFunction) {
806 vardeferredResult;
807 var user;
808
809 user = new Clipperz.PM.DataModel.User({'username':anUsername, 'getPassphraseFunction':aPassphraseFunction});
810
811 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.User.registerNewAccount", {trace:false});
812 deferredResult.addMethod(user, 'registerAsNewAccount');
813 deferredResult.addMethod(user, 'login');
814 deferredResult.addCallback(MochiKit.Async.succeed, user);
815 deferredResult.callback();
816
817 return deferredResult;
818}
819
820//-----------------------------------------------------------------------------
821
822Clipperz.PM.DataModel.User.exception = {
823 LoginFailed: new MochiKit.Base.NamedError("Clipperz.PM.DataModel.User.exception.LoginFailed"),
824 CredentialUpgradeFailed:new MochiKit.Base.NamedError("Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed")
825};
826
827//-----------------------------------------------------------------------------