Diffstat (limited to 'frontend/gamma/js/Clipperz/PM/DataModel/User.js') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/gamma/js/Clipperz/PM/DataModel/User.js | 817 |
1 files changed, 817 insertions, 0 deletions
diff --git a/frontend/gamma/js/Clipperz/PM/DataModel/User.js b/frontend/gamma/js/Clipperz/PM/DataModel/User.js new file mode 100644 index 0000000..e8afa97 --- a/dev/null +++ b/frontend/gamma/js/Clipperz/PM/DataModel/User.js | |||
@@ -0,0 +1,817 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2011 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz's Javascript Crypto Library. | ||
6 | Javascript Crypto Library provides web developers with an extensive | ||
7 | and efficient set of cryptographic functions. The library aims to | ||
8 | obtain maximum execution speed while preserving modularity and | ||
9 | reusability. | ||
10 | For further information about its features and functionalities please | ||
11 | refer to http://www.clipperz.com | ||
12 | |||
13 | * Javascript Crypto Library is free software: you can redistribute | ||
14 | it and/or modify it under the terms of the GNU Affero General Public | ||
15 | License as published by the Free Software Foundation, either version | ||
16 | 3 of the License, or (at your option) any later version. | ||
17 | |||
18 | * Javascript Crypto Library is distributed in the hope that it will | ||
19 | be useful, but WITHOUT ANY WARRANTY; without even the implied | ||
20 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
21 | See the GNU Affero General Public License for more details. | ||
22 | |||
23 | * You should have received a copy of the GNU Affero General Public | ||
24 | License along with Javascript Crypto Library. If not, see | ||
25 | <http://www.gnu.org/licenses/>. | ||
26 | |||
27 | */ | ||
28 | |||
29 | if (typeof(Clipperz) == 'undefined') { Clipperz = {}; } | ||
30 | if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; } | ||
31 | if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; } | ||
32 | |||
33 | |||
34 | //############################################################################# | ||
35 | |||
36 | Clipperz.PM.DataModel.User = function (args) { | ||
37 | args = args || {}; | ||
38 | |||
39 | Clipperz.PM.DataModel.User.superclass.constructor.apply(this, arguments); | ||
40 | |||
41 | this._username = args.username || null; | ||
42 | this._getPassphraseFunction = args.getPassphraseFunction || null; | ||
43 | |||
44 | this._data = null; | ||
45 | |||
46 | this._connection = null; | ||
47 | this._connectionVersion = 'current'; | ||
48 | |||
49 | this._serverData = null; | ||
50 | this._serverLockValue = null; | ||
51 | this._transientState = null; | ||
52 | |||
53 | this._deferredLocks = { | ||
54 | 'passphrase': new MochiKit.Async.DeferredLock(), | ||
55 | 'serverData': new MochiKit.Async.DeferredLock(), | ||
56 | // 'recordsIndex': new MochiKit.Async.DeferredLock(), | ||
57 | // 'directLoginsIndex':new MochiKit.Async.DeferredLock() | ||
58 | // 'preferences': new MochiKit.Async.DeferredLock() | ||
59 | // 'oneTimePasswords': new MochiKit.Async.DeferredLock() | ||
60 | '__syntaxFix__': 'syntax fix' | ||
61 | }; | ||
62 | |||
63 | return this; | ||
64 | } | ||
65 | |||
66 | Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { | ||
67 | |||
68 | 'toString': function () { | ||
69 | return "Clipperz.PM.DataModel.User - " + this.username(); | ||
70 | }, | ||
71 | |||
72 | //------------------------------------------------------------------------- | ||
73 | |||
74 | 'username': function () { | ||
75 | return this._username; | ||
76 | }, | ||
77 | |||
78 | 'setUsername': function (aValue) { | ||
79 | this._username = aValue; | ||
80 | }, | ||
81 | |||
82 | //------------------------------------------------------------------------- | ||
83 | |||
84 | 'displayName': function() { | ||
85 | return "" + this.username() + ""; | ||
86 | }, | ||
87 | |||
88 | //------------------------------------------------------------------------- | ||
89 | |||
90 | 'data': function () { | ||
91 | if (this._data == null) { | ||
92 | this._data = new Clipperz.KeyValueObjectStore(/*{'name':'User.data [1]'}*/); | ||
93 | }; | ||
94 | |||
95 | return this._data; | ||
96 | }, | ||
97 | |||
98 | //------------------------------------------------------------------------- | ||
99 | |||
100 | 'serverLockValue': function () { | ||
101 | return this._serverLockValue; | ||
102 | }, | ||
103 | |||
104 | 'setServerLockValue': function (aValue) { | ||
105 | this._serverLockValue = aValue; | ||
106 | }, | ||
107 | |||
108 | //------------------------------------------------------------------------- | ||
109 | |||
110 | 'transientState': function () { | ||
111 | if (this._transientState == null) { | ||
112 | this._transientState = {} | ||
113 | } | ||
114 | |||
115 | return this._transientState; | ||
116 | }, | ||
117 | |||
118 | 'resetTransientState': function (isCommitting) { | ||
119 | this._transientState = null; | ||
120 | }, | ||
121 | |||
122 | //------------------------------------------------------------------------- | ||
123 | |||
124 | 'deferredLockForSection': function(aSectionName) { | ||
125 | return this._deferredLocks[aSectionName]; | ||
126 | }, | ||
127 | |||
128 | //------------------------------------------------------------------------- | ||
129 | |||
130 | 'getPassphrase': function() { | ||
131 | var deferredResult; | ||
132 | |||
133 | deferredResult = new Clipperz.Async.Deferred("User.getPassphrase", {trace:false}); | ||
134 | deferredResult.acquireLock(this.deferredLockForSection('passphrase')); | ||
135 | deferredResult.addMethod(this.data(), 'deferredGetOrSet', 'passphrase', this.getPassphraseFunction()); | ||
136 | deferredResult.releaseLock(this.deferredLockForSection('passphrase')); | ||
137 | deferredResult.callback(); | ||
138 | |||
139 | return deferredResult; | ||
140 | }, | ||
141 | |||
142 | 'getPassphraseFunction': function () { | ||
143 | return this._getPassphraseFunction; | ||
144 | }, | ||
145 | |||
146 | //------------------------------------------------------------------------- | ||
147 | |||
148 | 'getCredentials': function () { | ||
149 | return Clipperz.Async.collectResults("User; get username and passphrase", { | ||
150 | 'username': MochiKit.Base.method(this, 'username'), | ||
151 | 'password': MochiKit.Base.method(this, 'getPassphrase') | ||
152 | }, {trace:false})(); | ||
153 | }, | ||
154 | |||
155 | //------------------------------------------------------------------------- | ||
156 | |||
157 | 'changePassphrase': function (aNewValue) { | ||
158 | return this.updateCredentials(this.username(), aNewValue); | ||
159 | }, | ||
160 | |||
161 | //......................................................................... | ||
162 | |||
163 | 'updateCredentials': function (aUsername, aPassphrase) { | ||
164 | vardeferredResult; | ||
165 | |||
166 | deferredResult = new Clipperz.Async.Deferred("User.updateCredentials", {trace:false}); | ||
167 | // deferredResult.addMethod(this, 'getPassphrase'); | ||
168 | // deferredResult.setValue('currentPassphrase'); | ||
169 | deferredResult.addMethod(this.connection(), 'ping'); | ||
170 | deferredResult.addMethod(this, 'setUsername', aUsername) | ||
171 | deferredResult.acquireLock(this.deferredLockForSection('passphrase')); | ||
172 | deferredResult.addMethod(this.data(), 'deferredGetOrSet', 'passphrase', aPassphrase); | ||
173 | deferredResult.releaseLock(this.deferredLockForSection('passphrase')); | ||
174 | // deferredResult.getValue('currentPassphrase'); | ||
175 | deferredResult.addMethod(this, 'prepareRemoteDataWithKey', aPassphrase); | ||
176 | deferredResult.addMethod(this.connection(), 'updateCredentials', aUsername, aPassphrase); | ||
177 | deferredResult.callback(); | ||
178 | |||
179 | return deferredResult; | ||
180 | }, | ||
181 | |||
182 | //------------------------------------------------------------------------- | ||
183 | |||
184 | 'initialSetupWithNoData': function () { | ||
185 | this._serverData = { | ||
186 | 'version': '0.1', | ||
187 | 'statistics': "", | ||
188 | 'header': { | ||
189 | 'data': null, | ||
190 | 'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion, | ||
191 | |||
192 | 'recordsIndex': new Clipperz.PM.DataModel.User.Header.RecordIndex({ | ||
193 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'), | ||
194 | 'recordsData': {'data':null, 'index':{}}, | ||
195 | 'recordsStats': null, | ||
196 | 'directLoginsData': {'data':null, 'index':{}}, | ||
197 | 'encryptedDataVersion': Clipperz.PM.Crypto.encryptingFunctions.currentVersion, | ||
198 | 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail') | ||
199 | }), | ||
200 | 'preferences': new Clipperz.PM.DataModel.User.Header.Preferences({ | ||
201 | 'name':'preferences', | ||
202 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase') | ||
203 | }), | ||
204 | 'oneTimePasswords': new Clipperz.PM.DataModel.User.Header.OneTimePasswords({ | ||
205 | 'name':'preferences', | ||
206 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase') | ||
207 | }) | ||
208 | } | ||
209 | }; | ||
210 | |||
211 | // this._serverLockValue = Clipperz.PM.Crypto.randomKey(); | ||
212 | }, | ||
213 | |||
214 | //......................................................................... | ||
215 | |||
216 | 'registerAsNewAccount': function () { | ||
217 | var deferredResult; | ||
218 | |||
219 | deferredResult = new Clipperz.Async.Deferred("User.registerAsNewAccount", {trace:false}); | ||
220 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':3}); | ||
221 | deferredResult.addMethod(this, 'initialSetupWithNoData') | ||
222 | deferredResult.addMethod(this, 'getPassphrase'); | ||
223 | deferredResult.addMethod(this, 'prepareRemoteDataWithKey'); | ||
224 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress'); | ||
225 | deferredResult.addMethod(this.connection(), 'register'); | ||
226 | deferredResult.addCallback(MochiKit.Base.itemgetter('lock')); | ||
227 | deferredResult.addMethod(this, 'setServerLockValue'); | ||
228 | deferredResult.addCallbackPass(MochiKit.Signal.signal,Clipperz.Signal.NotificationCenter, 'userSuccessfullyRegistered'); | ||
229 | |||
230 | // deferredResult.addErrback (MochiKit.Base.method(this, 'handleRegistrationFailure')); | ||
231 | |||
232 | deferredResult.callback(); | ||
233 | |||
234 | return deferredResult; | ||
235 | }, | ||
236 | |||
237 | //------------------------------------------------------------------------- | ||
238 | |||
239 | 'login': function () { | ||
240 | var deferredResult; | ||
241 | |||
242 | deferredResult = new Clipperz.Async.Deferred("User.login", {trace:false}); | ||
243 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':3}); | ||
244 | deferredResult.addMethod(this, 'getPassphrase'); | ||
245 | deferredResult.addCallback(Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue); | ||
246 | deferredResult.addCallback(Clipperz.Async.deferredIf("Is the passphrase an OTP", [ | ||
247 | MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':1}), | ||
248 | MochiKit.Base.method(this, 'getCredentials'), | ||
249 | MochiKit.Base.method(this.connection(), 'redeemOneTimePassword'), | ||
250 | MochiKit.Base.method(this.data(), 'setValue', 'passphrase') | ||
251 | ], [])); | ||
252 | deferredResult.addErrback(MochiKit.Base.method(this, 'getPassphrase')); | ||
253 | deferredResult.addMethod(this.connection(), 'login'); | ||
254 | deferredResult.addCallbackPass(MochiKit.Signal.signal,Clipperz.Signal.NotificationCenter, 'userSuccessfullyLoggedIn'); | ||
255 | deferredResult.addErrback (MochiKit.Base.method(this, 'handleConnectionFallback')); | ||
256 | |||
257 | deferredResult.callback(); | ||
258 | |||
259 | return deferredResult; | ||
260 | }, | ||
261 | |||
262 | //......................................................................... | ||
263 | |||
264 | 'handleConnectionFallback': function(aValue) { | ||
265 | var result; | ||
266 | |||
267 | if (aValue instanceof MochiKit.Async.CancelledError) { | ||
268 | result = aValue; | ||
269 | } else { | ||
270 | this.setConnectionVersion(Clipperz.PM.Connection.communicationProtocol.fallbackVersions[this.connectionVersion()]); | ||
271 | |||
272 | if (this.connectionVersion() != null) { | ||
273 | result = new Clipperz.Async.Deferred("User.handleConnectionFallback - retry"); | ||
274 | |||
275 | result.addMethod(this, 'login'); | ||
276 | result.callback(); | ||
277 | } else { | ||
278 | result = Clipperz.Async.callbacks("User.handleConnectionFallback - failed", [ | ||
279 | MochiKit.Base.method(this.data(), 'removeValue', 'passphrase'), | ||
280 | MochiKit.Base.method(this, 'setConnectionVersion', 'current'), | ||
281 | MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userLoginFailed'), | ||
282 | MochiKit.Base.partial(MochiKit.Async.fail, Clipperz.PM.DataModel.User.exception.LoginFailed) | ||
283 | ], {trace:false}); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | return result; | ||
288 | }, | ||
289 | |||
290 | //------------------------------------------------------------------------- | ||
291 | |||
292 | 'lock': function () { | ||
293 | return Clipperz.Async.callbacks("User.lock", [ | ||
294 | MochiKit.Base.method(this, 'deleteAllCleanTextData') | ||
295 | ], {trace:false}); | ||
296 | }, | ||
297 | |||
298 | //------------------------------------------------------------------------- | ||
299 | |||
300 | 'logout': function () { | ||
301 | return Clipperz.Async.callbacks("User.logout", [ | ||
302 | MochiKit.Base.method(this, 'deleteAllCleanTextData'), | ||
303 | MochiKit.Base.method(this.connection(), 'logout') | ||
304 | ], {trace:false}); | ||
305 | }, | ||
306 | |||
307 | //------------------------------------------------------------------------- | ||
308 | |||
309 | 'headerFormatVersion': function(anHeader) { | ||
310 | var result; | ||
311 | |||
312 | if (anHeader.charAt(0) == '{') { | ||
313 | varheaderData; | ||
314 | |||
315 | headerData = Clipperz.Base.evalJSON(anHeader); | ||
316 | result = headerData['version']; | ||
317 | } else { | ||
318 | result = 'LEGACY'; | ||
319 | } | ||
320 | |||
321 | return result; | ||
322 | }, | ||
323 | |||
324 | //------------------------------------------------------------------------- | ||
325 | |||
326 | 'unpackServerData': function (someServerData) { | ||
327 | var unpackedData; | ||
328 | var headerVersion; | ||
329 | |||
330 | varrecordsIndex; | ||
331 | var preferences; | ||
332 | var oneTimePasswords; | ||
333 | |||
334 | //console.log(">>> ***************** user.unpackServerData", someServerData); | ||
335 | this.setServerLockValue(someServerData['lock']); | ||
336 | |||
337 | headerVersion = this.headerFormatVersion(someServerData['header']); | ||
338 | |||
339 | switch (headerVersion) { | ||
340 | case 'LEGACY': | ||
341 | varlegacyHeader; | ||
342 | |||
343 | legacyHeader = new Clipperz.PM.DataModel.User.Header.Legacy({ | ||
344 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'), | ||
345 | 'remoteData': { | ||
346 | 'data': someServerData['header'], | ||
347 | 'version': someServerData['version'], | ||
348 | 'recordsStats': someServerData['recordsStats'] | ||
349 | }, | ||
350 | // 'encryptedDataKeypath': 'data', | ||
351 | // 'encryptedVersionKeypath': 'version', | ||
352 | 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail') | ||
353 | }); | ||
354 | |||
355 | recordsIndex = legacyHeader; | ||
356 | preferences = legacyHeader; | ||
357 | oneTimePasswords= legacyHeader; | ||
358 | break; | ||
359 | case '0.1': | ||
360 | varheaderData; | ||
361 | |||
362 | headerData = Clipperz.Base.evalJSON(someServerData['header']); | ||
363 | |||
364 | recordsIndex = new Clipperz.PM.DataModel.User.Header.RecordIndex({ | ||
365 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'), | ||
366 | 'recordsData': headerData['records'], | ||
367 | 'recordsStats': someServerData['recordsStats'], | ||
368 | 'directLoginsData': headerData['directLogins'], | ||
369 | 'encryptedDataVersion': someServerData['version'], | ||
370 | 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail') | ||
371 | }); | ||
372 | |||
373 | //Still missing a test case that actually fais with the old version of the code, where the check for undefined was missing | ||
374 | if (typeof(headerData['preferences']) != 'undefined') { | ||
375 | preferences= new Clipperz.PM.DataModel.User.Header.Preferences({ | ||
376 | 'name':'preferences', | ||
377 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'), | ||
378 | 'remoteData': { | ||
379 | 'data': headerData['preferences']['data'], | ||
380 | 'version': someServerData['version'] | ||
381 | } | ||
382 | }); | ||
383 | } else { | ||
384 | preferences= new Clipperz.PM.DataModel.User.Header.Preferences({ | ||
385 | 'name':'preferences', | ||
386 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase') | ||
387 | }); | ||
388 | } | ||
389 | |||
390 | if (typeof(headerData['oneTimePasswords']) != 'undefined') { | ||
391 | oneTimePasswords = new Clipperz.PM.DataModel.User.Header.OneTimePasswords({ | ||
392 | 'name':'preferences', | ||
393 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'), | ||
394 | 'remoteData': { | ||
395 | 'data': headerData['oneTimePasswords']['data'], | ||
396 | 'version': someServerData['version'] | ||
397 | } | ||
398 | }); | ||
399 | } else { | ||
400 | oneTimePasswords = new Clipperz.PM.DataModel.User.Header.OneTimePasswords({ | ||
401 | 'name':'preferences', | ||
402 | 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase') | ||
403 | }); | ||
404 | } | ||
405 | |||
406 | break; | ||
407 | } | ||
408 | |||
409 | unpackedData = { | ||
410 | 'version': someServerData['version'], | ||
411 | 'statistics': someServerData['statistics'], | ||
412 | 'header': { | ||
413 | 'data': someServerData['header'], | ||
414 | 'version': headerVersion, | ||
415 | |||
416 | 'recordsIndex': recordsIndex, | ||
417 | 'preferences': preferences, | ||
418 | 'oneTimePasswords': oneTimePasswords | ||
419 | } | ||
420 | }; | ||
421 | |||
422 | this._serverData = unpackedData; | ||
423 | //console.log("<<< ***************** user.unpackServerData", this._serverData); | ||
424 | |||
425 | return this._serverData; | ||
426 | }, | ||
427 | |||
428 | //------------------------------------------------------------------------- | ||
429 | |||
430 | 'getServerData': function() { | ||
431 | var deferredResult; | ||
432 | |||
433 | deferredResult = new Clipperz.Async.Deferred("User.getServerData", {trace:false}); | ||
434 | deferredResult.acquireLock(this.deferredLockForSection('serverData')); | ||
435 | deferredResult.addCallback(MochiKit.Base.bind(function(aResult) { | ||
436 | var innerDeferredResult; | ||
437 | |||
438 | innerDeferredResult = new Clipperz.Async.Deferred("User.getUserDetails.innerDeferred", {trace:false}); | ||
439 | if (this._serverData == null) { | ||
440 | innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadingUserDetails'); | ||
441 | innerDeferredResult.addMethod(this.connection(), 'message', 'getUserDetails'); | ||
442 | innerDeferredResult.addMethod(this, 'unpackServerData'); | ||
443 | innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadedUserDetails'); | ||
444 | } | ||
445 | |||
446 | innerDeferredResult.addCallback(MochiKit.Base.bind(function () { | ||
447 | return this._serverData; | ||
448 | },this)); | ||
449 | innerDeferredResult.callback(); | ||
450 | |||
451 | return innerDeferredResult; | ||
452 | }, this)); | ||
453 | deferredResult.releaseLock(this.deferredLockForSection('serverData')); | ||
454 | deferredResult.callback(); | ||
455 | |||
456 | return deferredResult; | ||
457 | }, | ||
458 | |||
459 | //------------------------------------------------------------------------- | ||
460 | |||
461 | 'connectionVersion': function() { | ||
462 | return this._connectionVersion; | ||
463 | }, | ||
464 | |||
465 | 'setConnectionVersion': function(aValue) { | ||
466 | if (this._connectionVersion != aValue) { | ||
467 | this.resetConnection(); | ||
468 | } | ||
469 | this._connectionVersion = aValue; | ||
470 | }, | ||
471 | |||
472 | //------------------------------------------------------------------------- | ||
473 | |||
474 | 'connection': function() { | ||
475 | if ((this._connection == null) && (this.connectionVersion() != null) ){ | ||
476 | this._connection = new Clipperz.PM.Connection.communicationProtocol.versions[this.connectionVersion()]({ | ||
477 | getCredentialsFunction: MochiKit.Base.method(this, 'getCredentials') | ||
478 | }); | ||
479 | } | ||
480 | |||
481 | return this._connection; | ||
482 | }, | ||
483 | |||
484 | 'resetConnection': function(aValue) { | ||
485 | if (this._connection != null) { | ||
486 | this._connection.reset(); | ||
487 | } | ||
488 | |||
489 | this._connection = null; | ||
490 | }, | ||
491 | |||
492 | //========================================================================= | ||
493 | |||
494 | 'getHeaderIndex': function (aKey) { | ||
495 | return Clipperz.Async.callbacks("User.getHeaderIndex", [ | ||
496 | MochiKit.Base.method(this, 'getServerData'), | ||
497 | MochiKit.Base.itemgetter('header'), | ||
498 | MochiKit.Base.itemgetter(aKey) | ||
499 | ], {trace:false}) | ||
500 | }, | ||
501 | |||
502 | //========================================================================= | ||
503 | |||
504 | 'getRecords': function () { | ||
505 | return Clipperz.Async.callbacks("User.getRecords", [ | ||
506 | MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'), | ||
507 | MochiKit.Base.methodcaller('records'), | ||
508 | MochiKit.Base.values | ||
509 | ], {trace:false}); | ||
510 | }, | ||
511 | |||
512 | 'recordWithLabel': function (aLabel) { | ||
513 | return Clipperz.Async.callbacks("User.recordWithLabel", [ | ||
514 | MochiKit.Base.method(this, 'getRecords'), | ||
515 | MochiKit.Base.partial(Clipperz.Async.deferredFilter, function (aRecord) { | ||
516 | return Clipperz.Async.callbacks("User.recordWithLabel - check record label", [ | ||
517 | MochiKit.Base.methodcaller('label'), | ||
518 | MochiKit.Base.partial(MochiKit.Base.operator.eq, aLabel) | ||
519 | ], {trace:false}, aRecord); | ||
520 | }), | ||
521 | function (someFilteredResults) { | ||
522 | var result; | ||
523 | |||
524 | switch (someFilteredResults.length) { | ||
525 | case 0: | ||
526 | result = null; | ||
527 | break; | ||
528 | case 1: | ||
529 | result = someFilteredResults[0]; | ||
530 | break; | ||
531 | default: | ||
532 | WTF = TODO; | ||
533 | break; | ||
534 | } | ||
535 | |||
536 | return result; | ||
537 | } | ||
538 | ], {trace:false}); | ||
539 | }, | ||
540 | |||
541 | //------------------------------------------------------------------------- | ||
542 | |||
543 | 'getRecord': function (aRecordReference) { | ||
544 | return Clipperz.Async.callbacks("User.getRecord", [ | ||
545 | MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'), | ||
546 | MochiKit.Base.methodcaller('records'), | ||
547 | MochiKit.Base.itemgetter(aRecordReference), | ||
548 | |||
549 | Clipperz.Async.deferredIf("record != null", [ | ||
550 | MochiKit.Base.operator.identity | ||
551 | ], [ | ||
552 | function () { throw "Record does not exists"} | ||
553 | ]) | ||
554 | ], {trace:false}); | ||
555 | }, | ||
556 | |||
557 | //------------------------------------------------------------------------- | ||
558 | |||
559 | 'getRecordDetail': function (aRecordReference) { | ||
560 | return this.connection().message('getRecordDetail', {reference: aRecordReference}); | ||
561 | }, | ||
562 | |||
563 | //------------------------------------------------------------------------- | ||
564 | |||
565 | 'deleteRecord': function (aRecord) { | ||
566 | return Clipperz.Async.callbacks("User.deleteRecord", [ | ||
567 | MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'), | ||
568 | MochiKit.Base.methodcaller('deleteRecord', aRecord) | ||
569 | ], {trace:false}); | ||
570 | }, | ||
571 | |||
572 | //------------------------------------------------------------------------- | ||
573 | |||
574 | 'createNewRecord': function () { | ||
575 | return Clipperz.Async.callbacks("User.createNewRecord", [ | ||
576 | MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'), | ||
577 | MochiKit.Base.methodcaller('createNewRecord') | ||
578 | ], {trace:false}); | ||
579 | }, | ||
580 | |||
581 | //========================================================================= | ||
582 | |||
583 | 'getDirectLogins': function() { | ||
584 | var deferredResult; | ||
585 | |||
586 | deferredResult = new Clipperz.Async.Deferred("User.getDirectLogins", {trace:false}); | ||
587 | deferredResult.addMethod(this, 'getRecords'); | ||
588 | deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.compose(MochiKit.Base.values, MochiKit.Base.methodcaller('directLogins'))); | ||
589 | deferredResult.addCallback(MochiKit.Base.flattenArray); | ||
590 | deferredResult.callback(); | ||
591 | |||
592 | return deferredResult; | ||
593 | }, | ||
594 | |||
595 | //========================================================================= | ||
596 | |||
597 | 'getOneTimePasswords': function () { | ||
598 | return Clipperz.Async.callbacks("User.getOneTimePasswords", [ | ||
599 | MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'), | ||
600 | MochiKit.Base.methodcaller('oneTimePasswords'), | ||
601 | MochiKit.Base.values | ||
602 | ], {trace:false}); | ||
603 | }, | ||
604 | |||
605 | //========================================================================= | ||
606 | |||
607 | 'invokeMethodNamedOnHeader': function (aMethodName, aValue) { | ||
608 | return Clipperz.Async.collectResults("User.invokeMethodNamedOnHeader [" + aMethodName + "]", { | ||
609 | 'recordIndex': [ | ||
610 | MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'), | ||
611 | MochiKit.Base.methodcaller(aMethodName, aValue) | ||
612 | ], | ||
613 | 'preferences': [ | ||
614 | MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'), | ||
615 | MochiKit.Base.methodcaller(aMethodName, aValue) | ||
616 | ], | ||
617 | 'oneTimePasswords': [ | ||
618 | MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'), | ||
619 | MochiKit.Base.methodcaller(aMethodName, aValue) | ||
620 | ]//, | ||
621 | // 'statistics': [ | ||
622 | // MochiKit.Base.method(this, 'getStatistics'), | ||
623 | // MochiKit.Base.methodcaller(aMethodName, aValue) | ||
624 | // ] | ||
625 | }, {trace:false})(); | ||
626 | }, | ||
627 | |||
628 | //------------------------------------------------------------------------- | ||
629 | |||
630 | 'invokeMethodNamedOnRecords': function (aMethodName, aValue) { | ||
631 | return Clipperz.Async.callbacks("User.invokeMethodNamedOnRecords[" + aMethodName + "]", [ | ||
632 | MochiKit.Base.method(this, 'getRecords'), | ||
633 | MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller(aMethodName, aValue)), | ||
634 | Clipperz.Async.collectAll | ||
635 | ], {trace:false}); | ||
636 | }, | ||
637 | |||
638 | //========================================================================= | ||
639 | |||
640 | 'hasPendingChanges': function () { | ||
641 | vardeferredResult; | ||
642 | |||
643 | deferredResult = new Clipperz.Async.Deferred("User.hasPendingChanges", {trace:false}); | ||
644 | deferredResult.collectResults({ | ||
645 | 'header': [ | ||
646 | MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'hasPendingChanges'), | ||
647 | MochiKit.Base.values | ||
648 | ], | ||
649 | 'records': MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'hasPendingChanges') | ||
650 | }); | ||
651 | deferredResult.addCallback(Clipperz.Async.or); | ||
652 | deferredResult.callback(); | ||
653 | // recordsIndex = legacyHeader; | ||
654 | // preferences = legacyHeader; | ||
655 | // oneTimePasswords= legacyHeader; | ||
656 | |||
657 | return deferredResult; | ||
658 | }, | ||
659 | |||
660 | //========================================================================= | ||
661 | |||
662 | 'commitTransientState': function () { | ||
663 | return Clipperz.Async.callbacks("User.commitTransientState", [ | ||
664 | MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'commitTransientState'), | ||
665 | MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'commitTransientState'), | ||
666 | |||
667 | MochiKit.Base.method(this, 'transientState'), | ||
668 | MochiKit.Base.itemgetter('lock'), | ||
669 | MochiKit.Base.method(this, 'setServerLockValue'), | ||
670 | MochiKit.Base.method(this, 'resetTransientState', true) | ||
671 | ], {trace:false}); | ||
672 | }, | ||
673 | |||
674 | //------------------------------------------------------------------------- | ||
675 | |||
676 | 'revertChanges': function () { | ||
677 | return Clipperz.Async.callbacks("User.revertChanges", [ | ||
678 | MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'revertChanges'), | ||
679 | MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'revertChanges'), | ||
680 | MochiKit.Base.method(this, 'resetTransientState', false) | ||
681 | ], {trace:false}); | ||
682 | }, | ||
683 | |||
684 | //========================================================================= | ||
685 | |||
686 | 'deleteAllCleanTextData': function () { | ||
687 | return Clipperz.Async.callbacks("User.deleteAllCleanTextData", [ | ||
688 | MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'deleteAllCleanTextData'), | ||
689 | MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'deleteAllCleanTextData'), | ||
690 | |||
691 | MochiKit.Base.method(this.data(), 'removeAllData'), | ||
692 | MochiKit.Base.method(this, 'resetTransientState', false) | ||
693 | ], {trace:false}); | ||
694 | }, | ||
695 | |||
696 | //------------------------------------------------------------------------- | ||
697 | |||
698 | 'hasAnyCleanTextData': function () { | ||
699 | vardeferredResult; | ||
700 | |||
701 | deferredResult = new Clipperz.Async.Deferred("User.hasAnyCleanTextData", {trace:false}); | ||
702 | deferredResult.collectResults({ | ||
703 | 'header':[ | ||
704 | MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'hasAnyCleanTextData'), | ||
705 | MochiKit.Base.values | ||
706 | ], | ||
707 | 'records':MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'hasAnyCleanTextData'), | ||
708 | 'data': MochiKit.Base.bind(function () { | ||
709 | return MochiKit.Async.succeed(! this.data().isEmpty()); | ||
710 | }, this), | ||
711 | 'transientState':MochiKit.Base.bind(function () { | ||
712 | return MochiKit.Async.succeed(MochiKit.Base.keys(this.transientState()).length != 0); | ||
713 | }, this) | ||
714 | }); | ||
715 | deferredResult.addCallback(Clipperz.Async.or); | ||
716 | deferredResult.callback(); | ||
717 | |||
718 | return deferredResult; | ||
719 | }, | ||
720 | |||
721 | //========================================================================= | ||
722 | |||
723 | 'prepareRemoteDataWithKey': function (aKey /*, aCurrentKey*/) { | ||
724 | var deferredResult; | ||
725 | varresult; | ||
726 | |||
727 | result = {}; | ||
728 | deferredResult = new Clipperz.Async.Deferred("User.prepareRemoteDataWithKey", {trace:false}); | ||
729 | deferredResult.addMethod(this, 'invokeMethodNamedOnHeader', 'prepareRemoteDataWithKey', aKey /*, aCurrentKey*/); | ||
730 | deferredResult.addCallback(MochiKit.Base.bind(function (aResult, someHeaderPackedData) { | ||
731 | var header; | ||
732 | |||
733 | header = {}; | ||
734 | header['records'] = someHeaderPackedData['recordIndex']['records']; | ||
735 | header['directLogins'] = someHeaderPackedData['recordIndex']['directLogins']; | ||
736 | header['preferences'] = {'data': someHeaderPackedData['preferences']['data']}; // this._serverData['header']['preferences']; // Clipperz.Base.evalJSON(this._serverData['header']['data'])['preferences']; //??????????? | ||
737 | header['oneTimePasswords'] = {'data': someHeaderPackedData['oneTimePasswords']['data']}; // this._serverData['header']['oneTimePasswords']; // Clipperz.Base.evalJSON(this._serverData['header']['data'])['oneTimePasswords']; //??????????? | ||
738 | header['version'] = '0.1'; | ||
739 | |||
740 | aResult['header'] = Clipperz.Base.serializeJSON(header); | ||
741 | aResult['statistics'] = this._serverData['statistics']; //"someHeaderPackedData['statistics']['data']"; | ||
742 | |||
743 | return aResult; | ||
744 | }, this), result); | ||
745 | deferredResult.addCallback(Clipperz.Async.setItem, result, 'version', Clipperz.PM.Crypto.encryptingFunctions.currentVersion); | ||
746 | deferredResult.addCallback(Clipperz.Async.setItem, result, 'lock', this.serverLockValue()); | ||
747 | deferredResult.callback(); | ||
748 | |||
749 | return deferredResult; | ||
750 | }, | ||
751 | |||
752 | //========================================================================= | ||
753 | |||
754 | 'saveChanges': function () { | ||
755 | vardeferredResult; | ||
756 | var messageParameters; | ||
757 | |||
758 | messageParameters = {}; | ||
759 | |||
760 | deferredResult = new Clipperz.Async.Deferred("User.saveChangaes", {trace:false}); | ||
761 | |||
762 | deferredResult.addMethod(this, 'getHeaderIndex', 'recordsIndex'); | ||
763 | deferredResult.addCallback(MochiKit.Base.methodcaller('prepareRemoteDataForChangedRecords')); | ||
764 | deferredResult.addCallback(Clipperz.Async.setItem, messageParameters, 'records'); | ||
765 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress'); | ||
766 | |||
767 | deferredResult.addMethod(this, 'getPassphrase'); | ||
768 | deferredResult.addMethod(this, 'prepareRemoteDataWithKey'); | ||
769 | deferredResult.addCallback(Clipperz.Async.setItem, messageParameters, 'user'); | ||
770 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress'); | ||
771 | |||
772 | deferredResult.addCallback(MochiKit.Async.succeed, messageParameters); | ||
773 | deferredResult.addMethod(this.connection(), 'message', 'saveChanges'); | ||
774 | deferredResult.addCallback(MochiKit.Base.update, this.transientState()) | ||
775 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress'); | ||
776 | |||
777 | deferredResult.addMethod(this, 'commitTransientState'); | ||
778 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress'); | ||
779 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userDataSuccessfullySaved'); | ||
780 | |||
781 | deferredResult.addErrbackPass(MochiKit.Base.method(this, 'revertChanges')); | ||
782 | deferredResult.addErrbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'failureWhileSavingUserData'); | ||
783 | |||
784 | deferredResult.callback(); | ||
785 | |||
786 | return deferredResult; | ||
787 | }, | ||
788 | |||
789 | //========================================================================= | ||
790 | __syntaxFix__: "syntax fix" | ||
791 | }); | ||
792 | |||
793 | //----------------------------------------------------------------------------- | ||
794 | |||
795 | Clipperz.PM.DataModel.User.registerNewAccount = function (anUsername, aPassphraseFunction) { | ||
796 | vardeferredResult; | ||
797 | var user; | ||
798 | |||
799 | user = new Clipperz.PM.DataModel.User({'username':anUsername, 'getPassphraseFunction':aPassphraseFunction}); | ||
800 | |||
801 | deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.User.registerNewAccount", {trace:false}); | ||
802 | deferredResult.addMethod(user, 'registerAsNewAccount'); | ||
803 | deferredResult.addMethod(user, 'login'); | ||
804 | deferredResult.addCallback(MochiKit.Async.succeed, user); | ||
805 | deferredResult.callback(); | ||
806 | |||
807 | return deferredResult; | ||
808 | } | ||
809 | |||
810 | //----------------------------------------------------------------------------- | ||
811 | |||
812 | Clipperz.PM.DataModel.User.exception = { | ||
813 | LoginFailed: new MochiKit.Base.NamedError("Clipperz.PM.DataModel.User.exception.LoginFailed"), | ||
814 | CredentialUpgradeFailed:new MochiKit.Base.NamedError("Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed") | ||
815 | }; | ||
816 | |||
817 | //----------------------------------------------------------------------------- | ||