summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/PM/Connection.js
Unidiff
Diffstat (limited to 'frontend/delta/js/Clipperz/PM/Connection.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/PM/Connection.js636
1 files changed, 636 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/PM/Connection.js b/frontend/delta/js/Clipperz/PM/Connection.js
new file mode 100644
index 0000000..c02125f
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Connection.js
@@ -0,0 +1,636 @@
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 = {}; }
26
27//-----------------------------------------------------------------------------
28//
29 // Abstract C O N N E C T I O N class
30//
31//-----------------------------------------------------------------------------
32
33Clipperz.PM.Connection = function (args) {
34 args = args || {};
35
36 this._proxy = args.proxy || Clipperz.PM.Proxy.defaultProxy;
37 this._getCredentialsFunction = args.getCredentialsFunction;
38
39 this._clipperz_pm_crypto_version = null;
40 this._connectionId = null;
41 this._sharedSecret = null;
42 this._serverLockValue = null;
43
44 return this;
45}
46
47Clipperz.PM.Connection.prototype = MochiKit.Base.update(null, {
48
49 'toString': function() {
50 return "Connection [" + this.version() + "]";
51 },
52
53 //=========================================================================
54
55 'version': function() {
56 throw Clipperz.Base.exception.AbstractMethod;
57 },
58
59 'clipperz_pm_crypto_version': function() {
60 if (this._clipperz_pm_crypto_version == null) {
61 var connectionVersions;
62 varversions;
63 varversion;
64 var i, c;
65
66 version = null;
67 connectionVersions = Clipperz.PM.Connection.communicationProtocol.versions;
68 versions = MochiKit.Base.keys(connectionVersions);
69 c = versions.length;
70 for (i=0; i<c; i++) {
71 if (! (versions[i] == 'current')) {
72 if (this instanceof connectionVersions[versions[i]]) {
73 version = versions[i];
74 };
75 }
76 }
77
78 this._clipperz_pm_crypto_version = version;
79 }
80
81 return this._clipperz_pm_crypto_version;
82 },
83
84 //-------------------------------------------------------------------------
85
86 'defaultErrorHandler': function(anErrorString, anException) {
87 // Clipperz.logError("### Connection.defaultErrorHandler: " + anErrorString, anException);
88 Clipperz.logError("### Connection.defaultErrorHandler: " + anErrorString + " (" + anException + ")");
89 },
90
91 //-------------------------------------------------------------------------
92
93 'getCredentialsFunction': function () {
94 return this._getCredentialsFunction;
95 },
96
97 'normalizedCredentials': function(someValues) {
98 throw Clipperz.Base.exception.AbstractMethod;
99 },
100
101 //=========================================================================
102
103 'proxy': function () {
104 return this._proxy;
105 },
106
107 //=========================================================================
108
109 'register': function () {
110 throw Clipperz.Base.exception.AbstractMethod;
111 },
112
113 'login': function() {
114 throw Clipperz.Base.exception.AbstractMethod;
115 },
116
117 //-------------------------------------------------------------------------
118
119 'message': function(someArguments, aCallback) {
120 throw Clipperz.Base.exception.AbstractMethod;
121 },
122
123 //-------------------------------------------------------------------------
124
125 'serverSideUserCredentials': function() {
126 throw Clipperz.Base.exception.AbstractMethod;
127 },
128
129 //=========================================================================
130
131 'sharedSecret': function () {
132 return this._sharedSecret;
133 },
134
135 'setSharedSecret': function (aValue) {
136 this._sharedSecret = aValue;
137 },
138
139 //-------------------------------------------------------------------------
140
141 'connectionId': function() {
142 return this._connectionId;
143 },
144
145 'setConnectionId': function(aValue) {
146 this._connectionId = aValue;
147 },
148
149 //-------------------------------------------------------------------------
150
151 'serverLockValue': function () {
152 return this._serverLockValue;
153 },
154
155 'setServerLockValue': function (aValue) {
156 this._serverLockValue = aValue;
157 },
158
159 //=========================================================================
160/*
161 //TODO: ?????
162 'oneTimePassword': function() {
163 return this._oneTimePassword;
164 },
165
166 'setOneTimePassword': function(aValue) {
167 this._oneTimePassword = aValue;
168 },
169*/
170 //=========================================================================
171
172 'reset': function() {
173 this.setSharedSecret(null);
174 this.setConnectionId(null);
175 },
176
177 //=========================================================================
178 __syntaxFix__: "syntax fix"
179
180}
181);
182
183
184if (typeof(Clipperz.PM.Connection.SRP) == 'undefined') { Clipperz.PM.Connection.SRP = {}; }
185//-----------------------------------------------------------------------------
186//
187 // S R P [ 1 . 0 ] C O N N E C T I O N class
188//
189//-----------------------------------------------------------------------------
190
191Clipperz.PM.Connection.SRP['1.0'] = function (args) {
192 Clipperz.PM.Connection.call(this, args);
193
194 return this;
195}
196
197Clipperz.PM.Connection.SRP['1.0'].prototype = MochiKit.Base.update(new Clipperz.PM.Connection(), {
198
199 'version': function() {
200 return '1.0';
201 },
202
203 //=========================================================================
204
205 'register': function (someUserData) {
206 vardeferredResult;
207 var cryptoVersion;
208 var srpConnection;
209
210 cryptoVersion = this.clipperz_pm_crypto_version();
211
212 deferredResult = new Clipperz.Async.Deferred("Connection.registerWithVersion", {trace:false});
213 deferredResult.collectResults({
214 'credentials': [
215 this.getCredentialsFunction(),
216 MochiKit.Base.method(this, 'normalizedCredentials'),
217 MochiKit.Base.bind(function(someCredentials) {
218 var srpConnection;
219 var result;
220
221 srpConnection = new Clipperz.Crypto.SRP.Connection({ C:someCredentials['username'], P:someCredentials['password'], hash:this.hash() });
222 result = srpConnection.serverSideCredentials();
223 result['version'] = Clipperz.PM.Connection.communicationProtocol.currentVersion;
224
225 return result;
226 }, this)
227 ],
228 'user': MochiKit.Base.partial(MochiKit.Async.succeed, someUserData),
229 'version':MochiKit.Base.partial(MochiKit.Async.succeed, Clipperz.PM.Connection.communicationProtocol.currentVersion),
230 'message':MochiKit.Base.partial(MochiKit.Async.succeed, 'completeRegistration')
231 });
232 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
233 deferredResult.addMethod(this.proxy(), 'registration');
234 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
235
236 deferredResult.callback();
237
238 return deferredResult;
239 },
240
241 //-------------------------------------------------------------------------
242
243 'updateCredentials': function (aUsername, aPassphrase, someUserData) {
244 vardeferredResult;
245
246 deferredResult = new Clipperz.Async.Deferred("Connection.updateCredentials", {trace:false});
247 deferredResult.collectResults({
248 'credentials': [
249 MochiKit.Base.method(this, 'normalizedCredentials', {username:aUsername, password:aPassphrase}),
250 MochiKit.Base.bind(function(someCredentials) {
251 var srpConnection;
252 var result;
253
254 srpConnection = new Clipperz.Crypto.SRP.Connection({ C:someCredentials['username'], P:someCredentials['password'], hash:this.hash() });
255 result = srpConnection.serverSideCredentials();
256 result['version'] = Clipperz.PM.Connection.communicationProtocol.currentVersion;
257
258 return result;
259 }, this)
260 ],
261 'user': MochiKit.Base.partial(MochiKit.Async.succeed, someUserData)
262 });
263 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
264 deferredResult.addMethod(this, 'message', 'upgradeUserCredentials');
265 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
266 deferredResult.callback();
267
268 return deferredResult;
269
270 },
271
272 //=========================================================================
273
274 'redeemOneTimePassword': function (someParameters) {
275/*
276 //=========================================================================
277 //LOGIN WITH PASSPHRASE, extracted from the TRUNK version (LoginPanel.js)
278 deferredResult.addCallback(function(anUsername, aOneTimePassword) {
279 var args;
280
281 args = {
282 'message': 'oneTimePassword',
283 'version': Clipperz.PM.Crypto.communicationProtocol.currentVersion,
284 'parameters': {
285 'oneTimePasswordKey': Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(anUsername, aOneTimePassword),
286 'oneTimePasswordKeyChecksum': Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(anUsername, aOneTimePassword)
287 }
288 }
289
290 return args;
291 }, anUsername, oneTimePassword);
292 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'OTP_login_loadingOTP');
293 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Proxy.defaultProxy, 'handshake'));
294 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'OTP_login_extractingPassphrase');
295 deferredResult.addCallback(function(aResult) {
296 return Clipperz.PM.Crypto.deferredDecrypt(oneTimePassword, aResult['data'], aResult['version']);
297 });
298 deferredResult.addCallback(function(aResult) {
299 return (new Clipperz.ByteArray().appendBase64String(aResult['passphrase'])).asString();
300 });
301 deferredResult.addMethod(this, 'doLoginWithUsernameAndPassphrase', anUsername),
302*/
303 var args;
304 var normalizedOTP;
305
306 normalizedOTP = Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(someParameters['password']);
307
308 args = {
309 'message': 'oneTimePassword',
310 'version': Clipperz.PM.Connection.communicationProtocol.currentVersion,
311 'parameters': {
312 'oneTimePasswordKey': Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(someParameters['username'], normalizedOTP),
313 'oneTimePasswordKeyChecksum':Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(someParameters['username'], normalizedOTP)
314 }
315 }
316
317 return Clipperz.Async.callbacks("Connction.redeemOTP", [
318 MochiKit.Base.method(this.proxy(), 'handshake', args),
319 function(aResult) {
320 return Clipperz.PM.Crypto.deferredDecrypt({
321 value:aResult['data'],
322 key:normalizedOTP,
323 version:aResult['version']
324 });
325 },
326 function(aResult) {
327 return (new Clipperz.ByteArray().appendBase64String(aResult['passphrase'])).asString();
328 }
329 ], {trace:false})
330 },
331
332 'login': function(isReconnecting) {
333 vardeferredResult;
334 var cryptoVersion;
335 var srpConnection;
336
337 cryptoVersion = this.clipperz_pm_crypto_version();
338 deferredResult = new Clipperz.Async.Deferred("Connection.login", {trace:false});
339 deferredResult.addCallback(this.getCredentialsFunction());
340 deferredResult.addMethod(this, 'normalizedCredentials');
341 // deferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'updatedProgressState', 'connection_sendingCredentials');
342 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
343 deferredResult.addCallback(MochiKit.Base.bind(function(someCredentials) {
344 srpConnection = new Clipperz.Crypto.SRP.Connection({ C:someCredentials['username'], P:someCredentials['password'], hash:this.hash() });
345 }, this));
346 deferredResult.addCallback(function() {
347 var result;
348
349 result = {
350 message: 'connect',
351 version: cryptoVersion,
352 parameters: {
353 C: srpConnection.C(),
354 A: srpConnection.A().asString(16)
355 // reconnecting: this.connectionId()
356 }
357 };
358
359 // TODO: ?????
360 // if (isReconnecting == true) {
361 // args.parameters['reconnecting'] = aConnection.connectionId();
362 // }
363
364 return result;
365 });
366 deferredResult.addMethod(this.proxy(), 'handshake');
367 // deferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'updatedProgressState', 'connection_credentialVerification');
368 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
369 deferredResult.addCallback(function(someParameters) {
370 var result;
371
372 srpConnection.set_s(new Clipperz.Crypto.BigInt(someParameters['s'], 16));
373 srpConnection.set_B(new Clipperz.Crypto.BigInt(someParameters['B'], 16));
374
375 //TODO: ?????
376 // if (typeof(someParameters['oneTimePassword']) != 'undefined') {
377 // this.setOneTimePassword(someParameters['oneTimePassword']);
378 // }
379
380 result = {
381 message: 'credentialCheck',
382 version: cryptoVersion,
383 parameters: {
384 M1: srpConnection.M1()
385 }
386 };
387
388 return result;
389 });
390 deferredResult.addMethod(this.proxy(), 'handshake');
391 deferredResult.addCallback(function(someParameters) {
392 var result;
393
394 if (someParameters['M2'] == srpConnection.M2()) {
395 result = MochiKit.Async.succeed(someParameters);
396 } else {
397 result = MochiKit.Async.fail(Clipperz.PM.Connection.exception.WrongChecksum);
398 }
399
400 return result;
401 });
402 deferredResult.addCallback(MochiKit.Base.bind(function(someParameters) {
403 this.setConnectionId(someParameters['connectionId']);
404 this.setSharedSecret(srpConnection.K());
405 // TODO: ?????
406 // if (this.oneTimePassword() != null) {
407 /// ?? result = this.user().oneTimePasswordManager().archiveOneTimePassword(this.oneTimePassword()));
408 // }
409
410 if ((isReconnecting == true) && (this.serverLockValue() != someParameters['lock'])) {
411 throw Clipperz.PM.Connection.exception.StaleData;
412 } else {
413 this.setServerLockValue(someParameters['lock']);
414 }
415
416 return someParameters;
417 }, this));
418 // deferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'updatedProgressState', 'connection_loggedIn');
419 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
420 // deferredResult.addCallback(MochiKit.Async.succeed, {result:"done"});
421
422 deferredResult.callback();
423
424 return deferredResult;
425 },
426
427 //=========================================================================
428
429 'logout': function() {
430 return Clipperz.Async.callbacks("Connection.logout", [
431 MochiKit.Base.method(this, 'setSharedSecret'),
432 MochiKit.Base.method(this.proxy(), 'logout', {})
433 ], {trace:false});
434 },
435
436 //=========================================================================
437
438 'ping': function () {
439 //TODO: ping the server in order to have a valid session
440 },
441
442 //=========================================================================
443
444 'message': function(aMessageName, someParameters) {
445 var args;
446 var parameters;
447
448 parameters = someParameters || {};
449 if (typeof(parameters['user']) != 'undefined') {
450 parameters['user']['lock'] = this.serverLockValue();
451 }
452
453 args = {
454 message: aMessageName,
455 srpSharedSecret: this.sharedSecret(),
456 // parameters: (someParameters || {})
457 parameters: parameters
458 }
459
460 return this.sendMessage(args);
461 },
462
463 //-------------------------------------------------------------------------
464
465 'sendMessage': function(someArguments) {
466 vardeferredResult;
467
468 deferredResult = new Clipperz.Async.Deferred("Connection.sendMessage", {trace:false});
469 deferredResult.addMethod(this.proxy(), 'message', someArguments);
470 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
471 if (typeof(res['lock']) != 'undefined') {
472 this.setServerLockValue(res['lock']);
473 }
474 return res;
475 }, this));
476
477 deferredResult.addErrback(MochiKit.Base.method(this, 'messageExceptionHandler'), someArguments);
478 deferredResult.callback();
479
480 return deferredResult
481 },
482
483 //-------------------------------------------------------------------------
484
485 'messageExceptionHandler': function(anOriginalMessageArguments, anError) {
486 var result;
487
488Clipperz.log(">>> Connection.messageExceptionHandler: " + anError.message, anError);
489 if (anError instanceof MochiKit.Async.CancelledError) {
490 result = anError;
491 } else {
492 if ((anError.message == 'Trying to communicate without an active connection')||
493 (anError.message == 'No tollManager available for current session')
494 ) {
495 result = this.reestablishConnection(anOriginalMessageArguments);
496 } else if (anError.message == 'Session with stale data') {
497 MochiKit.Signal.signal(this, 'EXCEPTION');
498 } else {
499 result = anError;
500 }
501 }
502Clipperz.log("<<< Connection.messageExceptionHandler")
503
504 return result;;
505 },
506
507 //=========================================================================
508
509 'reestablishConnection': function(anOriginalMessageArguments) {
510 var deferredResult;
511
512 deferredResult = new Clipperz.Async.Deferred("Connection.reestablishConnection");
513 deferredResult.addMethod(this, 'reset');
514 deferredResult.addMethod(this, 'login', true);
515 deferredResult.addCallback(MochiKit.Base.bind(function(aMessage) {
516 aMessage['srpSharedSecret'] = this.sharedSecret();
517 return aMessage;
518 }, this), anOriginalMessageArguments);
519 deferredResult.addMethod(this, 'sendMessage');
520 deferredResult.addErrback(MochiKit.Signal.signal, this, 'EXCEPTION', null);
521 deferredResult.callback();
522
523 return deferredResult;
524 },
525
526 //=========================================================================
527
528 'serverSideUserCredentials': function(aUsername, aPassword) {
529 varresult;
530 varnewSrpConnection;
531 var normalizedAttributes;
532
533 normalizedAttributes = this.normalizedCredentials({username:aUsername, password:aPassword});
534 newSrpConnection = new Clipperz.Crypto.SRP.Connection({ C:normalizedAttributes['username'], P:normalizedAttributes['password'], hash:this.hash() });
535 result = newSrpConnection.serverSideCredentials();
536 result['version'] = this.clipperz_pm_crypto_version();
537
538 return result;
539 },
540
541 //=========================================================================
542
543 'normalizedCredentials': function(someValues) {
544 var result;
545
546 result = {}
547 result['username'] = this.hash()(new Clipperz.ByteArray(someValues['username'])).toHexString().substring(2);
548 result['password'] = this.hash()(new Clipperz.ByteArray(someValues['password'] + someValues['username'])).toHexString().substring(2);
549
550 return result;
551 },
552
553 //-----------------------------------------------------------------------------
554
555 'hash': function() {
556 return Clipperz.PM.Crypto.encryptingFunctions.versions['0.1'].hash;
557 },
558
559 //-----------------------------------------------------------------------------
560 __syntaxFix__: "syntax fix"
561
562});
563
564
565
566//-----------------------------------------------------------------------------
567//
568 // S R P [ 1 . 1 ] C O N N E C T I O N class
569//
570//-----------------------------------------------------------------------------
571
572Clipperz.PM.Connection.SRP['1.1'] = function (args) {
573 Clipperz.PM.Connection.SRP['1.0'].call(this, args);
574
575 return this;
576}
577
578Clipperz.PM.Connection.SRP['1.1'].prototype = MochiKit.Base.update(new Clipperz.PM.Connection.SRP['1.0'](), {
579
580 'version': function() {
581 return '1.1';
582 },
583
584 //-----------------------------------------------------------------------------
585
586 'normalizedCredentials': function(someValues) {
587 var result;
588
589 result = {}
590 result['username'] = this.hash()(new Clipperz.ByteArray(someValues['username'] + someValues['password'])).toHexString().substring(2);
591 result['password'] = this.hash()(new Clipperz.ByteArray(someValues['password'] + someValues['username'])).toHexString().substring(2);
592
593 return result;
594 },
595
596 //-----------------------------------------------------------------------------
597
598 'hash': function() {
599 return Clipperz.PM.Crypto.encryptingFunctions.versions['0.2'].hash;
600 },
601
602 //-----------------------------------------------------------------------------
603 __syntaxFix__: "syntax fix"
604
605});
606
607Clipperz.PM.Connection.exception = {
608 WrongChecksum: new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.InvalidValue"),
609 StaleData: new MochiKit.Base.NamedError("Stale data"),
610 UnexpectedRequest:new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.UnexpectedRequest")
611};
612
613
614Clipperz.PM.Connection.communicationProtocol = {
615 'currentVersion': '0.2',
616 'versions': {
617 '0.1': Clipperz.PM.Connection.SRP['1.0'],//Clipperz.Crypto.SRP.versions['1.0'].Connection,
618 '0.2': Clipperz.PM.Connection.SRP['1.1']//Clipperz.Crypto.SRP.versions['1.1'].Connection
619 },
620 'fallbackVersions': {
621 // 'current':'0.1',
622 '0.2': '0.1',
623 '0.1': null
624 }
625};
626
627MochiKit.Base.update(Clipperz.PM.Connection.communicationProtocol.versions, {
628 'current': Clipperz.PM.Connection.communicationProtocol.versions[Clipperz.PM.Connection.communicationProtocol.currentVersion]
629});
630
631MochiKit.Base.update(Clipperz.PM.Connection.communicationProtocol.fallbackVersions, {
632 'current': Clipperz.PM.Connection.communicationProtocol.fallbackVersions[Clipperz.PM.Connection.communicationProtocol.currentVersion]
633});
634
635
636