summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.MemoryDataStore.js
Unidiff
Diffstat (limited to 'frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.MemoryDataStore.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.MemoryDataStore.js643
1 files changed, 643 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.MemoryDataStore.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.MemoryDataStore.js
new file mode 100644
index 0000000..ecc4408
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.MemoryDataStore.js
@@ -0,0 +1,643 @@
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.Proxy.Offline.DataStore) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.Proxy.Offline.MemoryDataStore depends on Clipperz.PM.Proxy.Offline.DataStore!";
26}
27
28//=============================================================================
29
30Clipperz.PM.Proxy.Offline.MemoryDataStore = function(args) {
31 args = args || {};
32
33 this._data = args.data || (typeof(_clipperz_dump_data_) != 'undefined' ? _clipperz_dump_data_ : null);
34 this._isReadOnly = (typeof(args.readOnly) == 'undefined' ? true : args.readOnly);
35 this._shouldPayTolls = args.shouldPayTolls || false;
36
37 this._tolls = {};
38 this._currentStaticConnection = null;
39
40 return this;
41}
42
43Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.MemoryDataStore, Clipperz.PM.Proxy.Offline.DataStore, {
44
45 //=========================================================================
46
47 'resetData': function() {
48 this._data = {
49 'users': {
50 'catchAllUser': {
51 __masterkey_test_value__: 'masterkey',
52 s: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00',
53 v: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00'
54 }
55 }
56 };
57 },
58
59 //-------------------------------------------------------------------------
60
61 'setupWithEncryptedData': function(someData) {
62 this._data = Clipperz.Base.deepClone(someData);
63 },
64
65 //-------------------------------------------------------------------------
66
67 'setupWithData': function(someData) {
68 var deferredResult;
69 var resultData;
70 var i, c;
71
72//Clipperz.log(">>> Proxy.Test.setupWithData");
73 resultData = this._data;
74
75 deferredResult = new Clipperz.Async.Deferred("Proxy.Test.seupWithData", {trace:false});
76 c = someData['users'].length;
77
78 for (i=0; i<c; i++) {
79 varnewConnection;
80 varrecordConfiguration;
81
82 deferredResult.addMethod(this, 'userSerializedEncryptedData', someData['users'][i]);
83 deferredResult.addCallback(MochiKit.Base.bind(function(aUserSerializationContext) {
84 resultData['users'][aUserSerializationContext['credentials']['C']] = {
85 's': aUserSerializationContext['credentials']['s'],
86 'v': aUserSerializationContext['credentials']['v'],
87 'version': aUserSerializationContext['data']['connectionVersion'],
88 'userDetails': aUserSerializationContext['encryptedData']['user']['header'],
89 'userDetailsVersion':aUserSerializationContext['encryptedData']['user']['version'],
90 'statistics': aUserSerializationContext['encryptedData']['user']['statistics'],
91 'lock': aUserSerializationContext['encryptedData']['user']['lock'],
92 'records': this.rearrangeRecordsData(aUserSerializationContext['encryptedData']['records'])
93 }
94 }, this));
95 }
96
97 deferredResult.addCallback(MochiKit.Base.bind(function() {
98 this._data = resultData;
99 }, this));
100
101 deferredResult.callback();
102//Clipperz.log("<<< Proxy.Test.setupWithData");
103
104 return deferredResult;
105 },
106
107 //=========================================================================
108
109 'getTollForRequestType': function (aRequestType) {
110 varresult;
111 vartargetValue;
112 var cost;
113
114 targetValue = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
115 switch (aRequestType) {
116 case 'REGISTER':
117 cost = 5;
118 break;
119 case 'CONNECT':
120 cost = 5;
121 break;
122 case 'MESSAGE':
123 cost = 2;
124 break;
125 }
126
127 result = {
128 requestType: aRequestType,
129 targetValue: targetValue,
130 cost: cost
131 }
132
133 if (this.shouldPayTolls()) {
134 this.tolls()[targetValue] = result;
135 }
136
137 return result;
138 },
139
140 //-------------------------------------------------------------------------
141
142 'checkToll': function (aFunctionName, someParameters) {
143 if (this.shouldPayTolls()) {
144 var localToll;
145 vartollParameters;
146
147 tollParameters = someParameters['toll'];
148 localToll = this.tolls()[tollParameters['targetValue']];
149
150 if (localToll != null) {
151 if (! Clipperz.PM.Toll.validate(tollParameters['targetValue'], tollParameters['toll'], localToll['cost'])) {
152 throw "Toll value too low.";
153 };
154 } else {
155 throw "Missing toll";
156 }
157 }
158 },
159
160 //=========================================================================
161
162 'currentStaticConnection': function () {
163 if (this._currentStaticConnection == null) {
164 this._currentStaticConnection = {};
165 }
166
167 return this._currentStaticConnection;
168 },
169
170 //-------------------------------------------------------------------------
171
172 'getConnectionForRequest': function (aFunctionName, someParameters) {
173 varresult;
174
175 if (this.shouldPayTolls()) {
176 if ((typeof(someParameters['toll']) != 'undefined') && (typeof(someParameters['toll']['targetValue']) != 'undefined')) {
177 result = this.tolls()[someParameters['toll']['targetValue']]['connection'];
178 if (typeof(result) == 'undefined') {
179 result = {};
180 }
181 } else {
182 result = {};
183 }
184 } else {
185 result = this.currentStaticConnection();
186 }
187
188 return result;
189 },
190
191 //-------------------------------------------------------------------------
192
193 'storeConnectionForRequestWithConnectionAndResponse': function (aFunctionName, someParameters, aConnection, aResponse) {
194 if (this.shouldPayTolls()) {
195 if ((typeof(aResponse['toll']) != 'undefined')
196 &&(typeof(aResponse['toll']['targetValue']) != 'undefined')
197 &&(typeof(this.tolls()[aResponse['toll']['targetValue']]) != 'undefined')
198 ) {
199 this.tolls()[aResponse['toll']['targetValue']]['connection'] = aConnection;
200 }
201 }
202 },
203
204 //=========================================================================
205
206 'processMessage': function (aFunctionName, someParameters) {
207 var result;
208 varconnection;
209
210 connection = this.getConnectionForRequest(aFunctionName, someParameters);
211
212 switch(aFunctionName) {
213 case 'knock':
214 result = this._knock(connection, someParameters);
215 break;
216 case 'registration':
217 this.checkToll(aFunctionName, someParameters);
218 result = this._registration(connection, someParameters.parameters);
219 break;
220 case 'handshake':
221 this.checkToll(aFunctionName, someParameters);
222 result = this._handshake(connection, someParameters.parameters);
223 break;
224 case 'message':
225 this.checkToll(aFunctionName, someParameters);
226 result = this._message(connection, someParameters.parameters);
227 break;
228 case 'logout':
229 this._currentStaticConnection = null;
230 result = this._logout(connection, someParameters.parameters);
231 break;
232 }
233
234 this.storeConnectionForRequestWithConnectionAndResponse(aFunctionName, someParameters, connection, result);
235
236 return MochiKit.Async.succeed(result);
237 },
238
239 //=========================================================================
240
241 '_knock': function(aConnection, someParameters) {
242 var result;
243
244 result = {
245 toll: this.getTollForRequestType(someParameters['requestType'])
246 }
247
248 return result;
249 },
250
251 //-------------------------------------------------------------------------
252
253 '_registration': function(aConnection, someParameters) {
254 if (this.isReadOnly() == false) {
255 if (typeof(this.data()['users'][someParameters['credentials']['C']]) == 'undefined') {
256 this.data()['users'][someParameters['credentials']['C']] = {
257 's': someParameters['credentials']['s'],
258 'v': someParameters['credentials']['v'],
259 'version':someParameters['credentials']['version'],
260 // 'lock': Clipperz.Crypto.Base.generateRandomSeed(),
261 'userDetails': someParameters['user']['header'],
262 'statistics': someParameters['user']['statistics'],
263 'userDetailsVersion':someParameters['user']['version'],
264 'records':{}
265 }
266 } else {
267 throw "user already exists";
268 }
269 } else {
270 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
271 }
272
273 result = {
274 result: {
275 'lock': this.data()['users'][someParameters['credentials']['C']]['lock'],
276 'result':'done'
277 },
278 toll: this.getTollForRequestType('CONNECT')
279 }
280
281 return result;
282 },
283
284 //-------------------------------------------------------------------------
285
286 '_handshake': function(aConnection, someParameters) {
287 var result;
288 varnextTollRequestType;
289
290 result = {};
291 if (someParameters.message == "connect") {
292 var userData;
293 var randomBytes;
294 var v;
295
296 userData = this.data()['users'][someParameters.parameters.C];
297
298 if ((typeof(userData) != 'undefined') && (userData['version'] == someParameters.version)) {
299 aConnection['userData'] = userData;
300 aConnection['C'] = someParameters.parameters.C;
301 } else {
302 aConnection['userData'] = this.data()['users']['catchAllUser'];
303 }
304
305 randomBytes = Clipperz.Crypto.Base.generateRandomSeed();
306 aConnection['b'] = new Clipperz.Crypto.BigInt(randomBytes, 16);
307 v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
308 aConnection['B'] = v.add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()));
309
310 aConnection['A'] = someParameters.parameters.A;
311
312 result['s'] = aConnection['userData']['s'];
313 result['B'] = aConnection['B'].asString(16);
314
315 nextTollRequestType = 'CONNECT';
316 } else if (someParameters.message == "credentialCheck") {
317 var v, u, S, A, K, M1;
318
319 v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
320 u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aConnection['B'].asString(10))).toHexString(), 16);
321 A = new Clipperz.Crypto.BigInt(aConnection['A'], 16);
322 S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(aConnection['b'], Clipperz.Crypto.SRP.n());
323
324 K = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(S.asString(10))).toHexString().slice(2);
325
326 M1 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + aConnection['B'].asString(10) + K)).toHexString().slice(2);
327 if (someParameters.parameters.M1 == M1) {
328 var M2;
329
330 M2 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + someParameters.parameters.M1 + K)).toHexString().slice(2);
331 result['M2'] = M2;
332 } else {
333 throw new Error("Client checksum verification failed! Expected <" + M1 + ">, received <" + someParameters.parameters.M1 + ">.", "Error");
334 }
335
336 nextTollRequestType = 'MESSAGE';
337 } else if (someParameters.message == "oneTimePassword") {
338 var otpData;
339
340 otpData = this.data()['onetimePasswords'][someParameters.parameters.oneTimePasswordKey];
341
342 try {
343 if (typeof(otpData) != 'undefined') {
344 if (otpData['status'] == 'ACTIVE') {
345 if (otpData['key_checksum'] == someParameters.parameters.oneTimePasswordKeyChecksum) {
346 result = {
347 'data': otpData['data'],
348 'version':otpData['version']
349 }
350
351 otpData['status'] = 'REQUESTED';
352 } else {
353 otpData['status'] = 'DISABLED';
354 throw "The requested One Time Password has been disabled, due to a wrong keyChecksum";
355 }
356 } else {
357 throw "The requested One Time Password was not active";
358 }
359 } else {
360 throw "The requested One Time Password has not been found"
361 }
362 } catch (exception) {
363 result = {
364 'data': Clipperz.PM.Crypto.randomKey(),
365 'version':Clipperz.PM.Connection.communicationProtocol.currentVersion
366 }
367 }
368 nextTollRequestType = 'CONNECT';
369 } else {
370 Clipperz.logError("Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters.message);
371 }
372
373 result = {
374 result: result,
375 toll: this.getTollForRequestType(nextTollRequestType)
376 }
377
378 return result;
379 },
380
381 //-------------------------------------------------------------------------
382
383 '_message': function(aConnection, someParameters) {
384 var result;
385
386 result = {};
387
388 //=====================================================================
389 //
390 // R E A D - O N L Y M e t h o d s
391 //
392 //=====================================================================
393 if (someParameters.message == 'getUserDetails') {
394 var recordsStats;
395 var recordReference;
396
397 recordsStats = {};
398 for (recordReference in aConnection['userData']['records']) {
399 recordsStats[recordReference] = {
400 'updateDate': aConnection['userData']['records'][recordReference]['updateDate']
401 }
402 }
403
404 result['header'] = this.userDetails(aConnection);
405 result['statistics'] = this.statistics(aConnection);
406 result['maxNumberOfRecords'] = aConnection['userData']['maxNumberOfRecords'];
407 result['version'] = aConnection['userData']['userDetailsVersion'];
408 result['recordsStats'] = recordsStats;
409
410 if (this.isReadOnly() == false) {
411 varlock;
412
413 if (typeof(aConnection['userData']['lock']) == 'undefined') {
414 aConnection['userData']['lock'] = "<<LOCK>>";
415 }
416
417 result['lock'] = aConnection['userData']['lock'];
418 }
419
420 //=====================================================================
421 } else if (someParameters.message == 'getRecordDetail') {
422/*
423 varrecordData;
424 var currentVersionData;
425
426 recordData = this.userData()['records'][someParameters['parameters']['reference']];
427 result['reference'] = someParameters['parameters']['reference'];
428 result['data'] = recordData['data'];
429 result['version'] = recordData['version'];
430 result['creationData'] = recordData['creationDate'];
431 result['updateDate'] = recordData['updateDate'];
432 result['accessDate'] = recordData['accessDate'];
433
434 currentVersionData = recordData['versions'][recordData['currentVersion']];
435
436 result['currentVersion'] = {};
437 result['currentVersion']['reference'] = recordData['currentVersion'];
438 result['currentVersion']['version'] = currentVersionData['version'];
439 result['currentVersion']['header'] = currentVersionData['header'];
440 result['currentVersion']['data'] = currentVersionData['data'];
441 result['currentVersion']['creationData'] = currentVersionData['creationDate'];
442 result['currentVersion']['updateDate'] = currentVersionData['updateDate'];
443 result['currentVersion']['accessDate'] = currentVersionData['accessDate'];
444 if (typeof(currentVersionData['previousVersion']) != 'undefined') {
445 result['currentVersion']['previousVersionKey'] = currentVersionData['previousVersionKey'];
446 result['currentVersion']['previousVersion'] = currentVersionData['previousVersion'];
447 }
448*/
449 MochiKit.Base.update(result, aConnection['userData']['records'][someParameters['parameters']['reference']]);
450 result['reference'] = someParameters['parameters']['reference'];
451
452 //=====================================================================
453 //
454 // R E A D - W R I T E M e t h o d s
455 //
456 //=====================================================================
457 } else if (someParameters.message == 'upgradeUserCredentials') {
458 if (this.isReadOnly() == false) {
459 var parameters;
460 var credentials;
461
462 parameters = someParameters['parameters'];
463 credentials = parameters['credentials'];
464
465 if ((credentials['C'] == null)
466 ||(credentials['s'] == null)
467 ||(credentials['v'] == null)
468 ||(credentials['version'] != Clipperz.PM.Connection.communicationProtocol.currentVersion)
469 ) {
470 result = Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed;
471 } else {
472 varoldCValue;
473 oldCValue = aConnection['C'];
474
475 this.data()['users'][credentials['C']] = aConnection['userData'];
476 aConnection['C'] = credentials['C'];
477
478 aConnection['userData']['s'] = credentials['s'];
479 aConnection['userData']['v'] = credentials['v'];
480 aConnection['userData']['version'] = credentials['version'];
481
482 aConnection['userData']['userDetails'] = parameters['user']['header'];
483 aConnection['userData']['userDetailsVersion'] = parameters['user']['version'];
484 aConnection['userData']['statistics'] = parameters['user']['statistics'];
485
486 aConnection['userData']['lock'] = parameters['user']['lock'];
487
488 delete this.data()['users'][oldCValue];
489
490 result = {result:"done", parameters:parameters};
491 }
492 } else {
493 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
494 }
495
496 //=====================================================================
497
498 } else if (someParameters.message == 'saveChanges') {
499 if (this.isReadOnly() == false) {
500 var i, c;
501
502 if (aConnection['userData']['lock']!= someParameters['parameters']['user']['lock']) {
503 throw "the lock attribute is not processed correctly"
504 }
505
506 aConnection['userData']['userDetails'] = someParameters['parameters']['user']['header'];
507 aConnection['userData']['statistics'] = someParameters['parameters']['user']['statistics'];
508 aConnection['userData']['userDetailsVersion']= someParameters['parameters']['user']['version'];
509
510 c = someParameters['parameters']['records']['updated'].length;
511 for (i=0; i<c; i++) {
512 var currentRecord;
513 var currentRecordData;
514
515 currentRecordData = someParameters['parameters']['records']['updated'][i];
516 currentRecord = aConnection['userData']['records'][currentRecordData['record']['reference']];
517
518 if (
519 (typeof(aConnection['userData']['records'][currentRecordData['record']['reference']]) == 'undefined')
520 &&
521 (typeof(currentRecordData['currentRecordVersion']) == 'undefined')
522 ) {
523 throw "Record added without a recordVersion";
524 }
525
526 if (currentRecord == null) {
527 currentRecord = {};
528 currentRecord['versions'] = {};
529 currentRecord['creationDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
530 currentRecord['accessDate'] = Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
531
532 aConnection['userData']['records'][currentRecordData['record']['reference']] = currentRecord;
533 }
534
535 currentRecord['data'] = currentRecordData['record']['data'];
536 currentRecord['version']= currentRecordData['record']['version'];
537 currentRecord['updateDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
538
539 if (typeof(currentRecordData['currentRecordVersion']) != 'undefined') {
540 currentRecord['currentVersion'] = currentRecordData['currentRecordVersion']['reference'];
541 currentRecord['versions'][currentRecordData['currentRecordVersion']['reference']] = {
542 'data': currentRecordData['currentRecordVersion']['data'],
543 'version': currentRecordData['currentRecordVersion']['version'],
544 'previousVersion': currentRecordData['currentRecordVersion']['previousVersion'],
545 'previousVersionKey':currentRecordData['currentRecordVersion']['previousVersionKey'],
546 'creationDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
547 'updateDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
548 'accessDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date())
549 }
550 }
551 }
552
553 c = someParameters['parameters']['records']['deleted'].length;
554 for (i=0; i<c; i++) {
555 var currentRecordReference;
556
557 currentRecordReference = someParameters['parameters']['records']['deleted'][i];
558 delete aConnection['userData']['records'][currentRecordReference];
559 }
560
561 aConnection['userData']['lock'] = Clipperz.PM.Crypto.randomKey();
562 result['lock'] = aConnection['userData']['lock'];
563 result['result'] = 'done';
564 } else {
565 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
566 }
567
568 //=====================================================================
569 //
570 // U N H A N D L E D M e t h o d
571 //
572 //=====================================================================
573 } else {
574 Clipperz.logError("Clipperz.PM.Proxy.Test.message - unhandled message: " + someParameters.message);
575 }
576
577 result = {
578 result: result,
579 toll: this.getTollForRequestType('MESSAGE')
580 }
581
582 // return MochiKit.Async.succeed(result);
583 return result;
584 },
585
586 //-------------------------------------------------------------------------
587
588 '_logout': function(someParameters) {
589 // return MochiKit.Async.succeed({result: 'done'});
590 return {result: 'done'};
591 },
592
593 //=========================================================================
594 //#########################################################################
595
596 'isTestData': function(aConnection) {
597 return (typeof(aConnection['userData']['__masterkey_test_value__']) != 'undefined');
598 },
599
600 'userDetails': function(aConnection) {
601 var result;
602
603 if (this.isTestData(aConnection)) {
604 var serializedHeader;
605 var version;
606
607//Clipperz.logDebug("### test data");
608 version = aConnection['userData']['userDetailsVersion'];
609 serializedHeader = Clipperz.Base.serializeJSON(aConnection['userData']['userDetails']);
610 result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(aConnection['userData']['__masterkey_test_value__'], serializedHeader);
611 } else {
612//Clipperz.logDebug("### NOT test data");
613 result = aConnection['userData']['userDetails'];
614 }
615
616 return result;
617 },
618
619 'statistics': function(aConnection) {
620 var result;
621
622 if (aConnection['userData']['statistics'] != null) {
623 if (this.isTestData(aConnection)) {
624 var serializedStatistics;
625 var version;
626
627 version = aConnection['userData']['userDetailsVersion'];
628 serializedStatistics = Clipperz.Base.serializeJSON(aConnection['userData']['statistics']);
629 result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(aConnection['userData']['__masterkey_test_value__'], serializedStatistics);
630 } else {
631 result = aConnection['userData']['statistics'];
632 }
633 } else {
634 result = null;
635 }
636
637 return result;
638 },
639
640 //=========================================================================
641 __syntaxFix__: "syntax fix"
642});
643