author | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2013-08-30 15:56:53 (UTC) |
---|---|---|
committer | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2013-08-30 21:23:42 (UTC) |
commit | 20bea94ab6b91c85b171dcf86baba0a64169d508 (patch) (unidiff) | |
tree | 6e38e91498dcdb861620eba1e237d1026fe79cc5 /frontend/delta/js/Clipperz/PM/Proxy | |
parent | bde3c7b98523112ade9c5bbf7390c4ecb494cd2e (diff) | |
download | clipperz-20bea94ab6b91c85b171dcf86baba0a64169d508.zip clipperz-20bea94ab6b91c85b171dcf86baba0a64169d508.tar.gz clipperz-20bea94ab6b91c85b171dcf86baba0a64169d508.tar.bz2 |
First release of /delta version
Diffstat (limited to 'frontend/delta/js/Clipperz/PM/Proxy') (more/less context) (ignore whitespace changes)
6 files changed, 2175 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js new file mode 100755 index 0000000..1638d99 --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | if (typeof(Clipperz) == 'undefined') { Clipperz = {}; } | ||
25 | if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; } | ||
26 | |||
27 | //============================================================================= | ||
28 | |||
29 | Clipperz.PM.Proxy.JSON = function(args) { | ||
30 | Clipperz.PM.Proxy.JSON.superclass.constructor.call(this, args); | ||
31 | |||
32 | this._url = args.url || Clipperz.Base.exception.raise('MandatoryParameter'); | ||
33 | |||
34 | return this; | ||
35 | } | ||
36 | |||
37 | Clipperz.Base.extend(Clipperz.PM.Proxy.JSON, Clipperz.PM.Proxy, { | ||
38 | |||
39 | 'toString': function() { | ||
40 | return "Clipperz.PM.Proxy.JSON"; | ||
41 | }, | ||
42 | |||
43 | //========================================================================= | ||
44 | |||
45 | 'url': function () { | ||
46 | return this._url; | ||
47 | }, | ||
48 | |||
49 | //========================================================================= | ||
50 | |||
51 | '_sendMessage': function(aFunctionName, aVersion, someParameters) { | ||
52 | vardeferredResult; | ||
53 | var parameters; | ||
54 | |||
55 | parameters = { | ||
56 | method: aFunctionName, | ||
57 | version: aVersion, | ||
58 | parameters: Clipperz.Base.serializeJSON(someParameters) | ||
59 | }; | ||
60 | |||
61 | deferredResult = new Clipperz.Async.Deferred("Proxy.JSON.sendMessage", {trace:false}); | ||
62 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestSent'); | ||
63 | deferredResult.addCallback(MochiKit.Async.doXHR, this.url(), { | ||
64 | method:'POST', | ||
65 | sendContent:MochiKit.Base.queryString(parameters), | ||
66 | headers:{"Content-Type":"application/x-www-form-urlencoded"} | ||
67 | }); | ||
68 | deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestReceived'); | ||
69 | deferredResult.addCallback(MochiKit.Base.itemgetter('responseText')); | ||
70 | deferredResult.addCallback(Clipperz.Base.evalJSON); | ||
71 | deferredResult.addCallback(function (someValues) { | ||
72 | if (someValues['result'] == 'EXCEPTION') { | ||
73 | throw someValues['message']; | ||
74 | } | ||
75 | |||
76 | return someValues; | ||
77 | }) | ||
78 | deferredResult.callback(); | ||
79 | |||
80 | return deferredResult; | ||
81 | }, | ||
82 | |||
83 | //========================================================================= | ||
84 | __syntaxFix__: "syntax fix" | ||
85 | |||
86 | }); | ||
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js new file mode 100644 index 0000000..5711742 --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js | |||
@@ -0,0 +1,793 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | try { if (typeof(Clipperz.PM.Proxy.Offline) == 'undefined') { throw ""; }} catch (e) { | ||
25 | throw "Clipperz.PM.Proxy.Offline.DataStore depends on Clipperz.PM.Proxy.Offline!"; | ||
26 | } | ||
27 | |||
28 | //============================================================================= | ||
29 | |||
30 | Clipperz.PM.Proxy.Offline.DataStore = 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 | |||
43 | Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, { | ||
44 | |||
45 | //------------------------------------------------------------------------- | ||
46 | |||
47 | 'isReadOnly': function () { | ||
48 | return this._isReadOnly; | ||
49 | }, | ||
50 | |||
51 | 'canRegisterNewUsers': function () { | ||
52 | return false; | ||
53 | }, | ||
54 | |||
55 | |||
56 | //------------------------------------------------------------------------- | ||
57 | |||
58 | 'shouldPayTolls': function() { | ||
59 | return this._shouldPayTolls; | ||
60 | }, | ||
61 | |||
62 | //------------------------------------------------------------------------- | ||
63 | |||
64 | 'data': function () { | ||
65 | return this._data; | ||
66 | }, | ||
67 | |||
68 | //------------------------------------------------------------------------- | ||
69 | |||
70 | 'tolls': function () { | ||
71 | return this._tolls; | ||
72 | }, | ||
73 | |||
74 | //========================================================================= | ||
75 | |||
76 | 'resetData': function() { | ||
77 | this._data = { | ||
78 | 'users': { | ||
79 | 'catchAllUser': { | ||
80 | __masterkey_test_value__: 'masterkey', | ||
81 | s: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00', | ||
82 | v: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00' | ||
83 | } | ||
84 | } | ||
85 | }; | ||
86 | }, | ||
87 | |||
88 | //------------------------------------------------------------------------- | ||
89 | |||
90 | 'setupWithEncryptedData': function(someData) { | ||
91 | this._data = Clipperz.Base.deepClone(someData); | ||
92 | }, | ||
93 | |||
94 | //------------------------------------------------------------------------- | ||
95 | |||
96 | 'setupWithData': function(someData) { | ||
97 | var deferredResult; | ||
98 | var resultData; | ||
99 | var i, c; | ||
100 | |||
101 | //Clipperz.log(">>> Proxy.Test.setupWithData"); | ||
102 | resultData = this._data; | ||
103 | |||
104 | deferredResult = new Clipperz.Async.Deferred("Proxy.Test.seupWithData", {trace:false}); | ||
105 | c = someData['users'].length; | ||
106 | |||
107 | for (i=0; i<c; i++) { | ||
108 | varnewConnection; | ||
109 | varrecordConfiguration; | ||
110 | |||
111 | deferredResult.addMethod(this, 'userSerializedEncryptedData', someData['users'][i]); | ||
112 | deferredResult.addCallback(MochiKit.Base.bind(function(aUserSerializationContext) { | ||
113 | resultData['users'][aUserSerializationContext['credentials']['C']] = { | ||
114 | 's': aUserSerializationContext['credentials']['s'], | ||
115 | 'v': aUserSerializationContext['credentials']['v'], | ||
116 | 'version': aUserSerializationContext['data']['connectionVersion'], | ||
117 | 'userDetails': aUserSerializationContext['encryptedData']['user']['header'], | ||
118 | 'userDetailsVersion':aUserSerializationContext['encryptedData']['user']['version'], | ||
119 | 'statistics': aUserSerializationContext['encryptedData']['user']['statistics'], | ||
120 | 'lock': aUserSerializationContext['encryptedData']['user']['lock'], | ||
121 | 'records': this.rearrangeRecordsData(aUserSerializationContext['encryptedData']['records']) | ||
122 | } | ||
123 | }, this)); | ||
124 | } | ||
125 | |||
126 | deferredResult.addCallback(MochiKit.Base.bind(function() { | ||
127 | this._data = resultData; | ||
128 | }, this)); | ||
129 | |||
130 | deferredResult.callback(); | ||
131 | //Clipperz.log("<<< Proxy.Test.setupWithData"); | ||
132 | |||
133 | return deferredResult; | ||
134 | }, | ||
135 | |||
136 | //========================================================================= | ||
137 | |||
138 | 'getTollForRequestType': function (aRequestType) { | ||
139 | varresult; | ||
140 | vartargetValue; | ||
141 | var cost; | ||
142 | |||
143 | targetValue = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2); | ||
144 | switch (aRequestType) { | ||
145 | case 'REGISTER': | ||
146 | cost = 5; | ||
147 | break; | ||
148 | case 'CONNECT': | ||
149 | cost = 5; | ||
150 | break; | ||
151 | case 'MESSAGE': | ||
152 | cost = 2; | ||
153 | break; | ||
154 | } | ||
155 | |||
156 | result = { | ||
157 | requestType: aRequestType, | ||
158 | targetValue: targetValue, | ||
159 | cost: cost | ||
160 | } | ||
161 | |||
162 | if (this.shouldPayTolls()) { | ||
163 | this.tolls()[targetValue] = result; | ||
164 | } | ||
165 | |||
166 | return result; | ||
167 | }, | ||
168 | |||
169 | //------------------------------------------------------------------------- | ||
170 | |||
171 | 'checkToll': function (aFunctionName, someParameters) { | ||
172 | if (this.shouldPayTolls()) { | ||
173 | var localToll; | ||
174 | vartollParameters; | ||
175 | |||
176 | tollParameters = someParameters['toll']; | ||
177 | localToll = this.tolls()[tollParameters['targetValue']]; | ||
178 | |||
179 | if (localToll != null) { | ||
180 | if (! Clipperz.PM.Toll.validate(tollParameters['targetValue'], tollParameters['toll'], localToll['cost'])) { | ||
181 | throw "Toll value too low."; | ||
182 | }; | ||
183 | } else { | ||
184 | throw "Missing toll"; | ||
185 | } | ||
186 | } | ||
187 | }, | ||
188 | |||
189 | //========================================================================= | ||
190 | |||
191 | 'currentStaticConnection': function () { | ||
192 | if (this._currentStaticConnection == null) { | ||
193 | this._currentStaticConnection = {}; | ||
194 | } | ||
195 | |||
196 | return this._currentStaticConnection; | ||
197 | }, | ||
198 | |||
199 | //------------------------------------------------------------------------- | ||
200 | |||
201 | 'getConnectionForRequest': function (aFunctionName, someParameters) { | ||
202 | varresult; | ||
203 | |||
204 | if (this.shouldPayTolls()) { | ||
205 | if ((typeof(someParameters['toll']) != 'undefined') && (typeof(someParameters['toll']['targetValue']) != 'undefined')) { | ||
206 | result = this.tolls()[someParameters['toll']['targetValue']]['connection']; | ||
207 | if (typeof(result) == 'undefined') { | ||
208 | result = {}; | ||
209 | } | ||
210 | } else { | ||
211 | result = {}; | ||
212 | } | ||
213 | } else { | ||
214 | result = this.currentStaticConnection(); | ||
215 | } | ||
216 | |||
217 | return result; | ||
218 | }, | ||
219 | |||
220 | //------------------------------------------------------------------------- | ||
221 | |||
222 | 'storeConnectionForRequestWithConnectionAndResponse': function (aFunctionName, someParameters, aConnection, aResponse) { | ||
223 | if (this.shouldPayTolls()) { | ||
224 | if ((typeof(aResponse['toll']) != 'undefined') | ||
225 | &&(typeof(aResponse['toll']['targetValue']) != 'undefined') | ||
226 | &&(typeof(this.tolls()[aResponse['toll']['targetValue']]) != 'undefined') | ||
227 | ) { | ||
228 | this.tolls()[aResponse['toll']['targetValue']]['connection'] = aConnection; | ||
229 | } | ||
230 | } | ||
231 | }, | ||
232 | |||
233 | //========================================================================= | ||
234 | |||
235 | 'processMessage': function (aFunctionName, someParameters) { | ||
236 | var result; | ||
237 | varconnection; | ||
238 | |||
239 | connection = this.getConnectionForRequest(aFunctionName, someParameters); | ||
240 | |||
241 | switch(aFunctionName) { | ||
242 | case 'knock': | ||
243 | result = this._knock(connection, someParameters); | ||
244 | break; | ||
245 | case 'registration': | ||
246 | this.checkToll(aFunctionName, someParameters); | ||
247 | result = this._registration(connection, someParameters.parameters); | ||
248 | break; | ||
249 | case 'handshake': | ||
250 | this.checkToll(aFunctionName, someParameters); | ||
251 | result = this._handshake(connection, someParameters.parameters); | ||
252 | break; | ||
253 | case 'message': | ||
254 | this.checkToll(aFunctionName, someParameters); | ||
255 | result = this._message(connection, someParameters.parameters); | ||
256 | break; | ||
257 | case 'logout': | ||
258 | this._currentStaticConnection = null; | ||
259 | result = this._logout(connection, someParameters.parameters); | ||
260 | break; | ||
261 | } | ||
262 | |||
263 | this.storeConnectionForRequestWithConnectionAndResponse(aFunctionName, someParameters, connection, result); | ||
264 | |||
265 | return MochiKit.Async.succeed(result); | ||
266 | }, | ||
267 | |||
268 | //========================================================================= | ||
269 | |||
270 | '_knock': function(aConnection, someParameters) { | ||
271 | var result; | ||
272 | |||
273 | result = { | ||
274 | toll: this.getTollForRequestType(someParameters['requestType']) | ||
275 | } | ||
276 | |||
277 | return result; | ||
278 | }, | ||
279 | |||
280 | //------------------------------------------------------------------------- | ||
281 | |||
282 | '_registration': function(aConnection, someParameters) { | ||
283 | if (this.isReadOnly() == false) { | ||
284 | if (typeof(this.data()['users'][someParameters['credentials']['C']]) == 'undefined') { | ||
285 | this.data()['users'][someParameters['credentials']['C']] = { | ||
286 | 's': someParameters['credentials']['s'], | ||
287 | 'v': someParameters['credentials']['v'], | ||
288 | 'version':someParameters['credentials']['version'], | ||
289 | // 'lock': Clipperz.Crypto.Base.generateRandomSeed(), | ||
290 | 'userDetails': someParameters['user']['header'], | ||
291 | 'statistics': someParameters['user']['statistics'], | ||
292 | 'userDetailsVersion':someParameters['user']['version'], | ||
293 | 'records':{} | ||
294 | } | ||
295 | } else { | ||
296 | throw "user already exists"; | ||
297 | } | ||
298 | } else { | ||
299 | throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly; | ||
300 | } | ||
301 | |||
302 | result = { | ||
303 | result: { | ||
304 | 'lock': this.data()['users'][someParameters['credentials']['C']]['lock'], | ||
305 | 'result':'done' | ||
306 | }, | ||
307 | toll: this.getTollForRequestType('CONNECT') | ||
308 | } | ||
309 | |||
310 | return result; | ||
311 | }, | ||
312 | |||
313 | //------------------------------------------------------------------------- | ||
314 | |||
315 | '_handshake': function(aConnection, someParameters) { | ||
316 | var result; | ||
317 | varnextTollRequestType; | ||
318 | |||
319 | result = {}; | ||
320 | if (someParameters.message == "connect") { | ||
321 | var userData; | ||
322 | var randomBytes; | ||
323 | var v; | ||
324 | |||
325 | userData = this.data()['users'][someParameters.parameters.C]; | ||
326 | |||
327 | if ((typeof(userData) != 'undefined') && (userData['version'] == someParameters.version)) { | ||
328 | aConnection['userData'] = userData; | ||
329 | aConnection['C'] = someParameters.parameters.C; | ||
330 | } else { | ||
331 | aConnection['userData'] = this.data()['users']['catchAllUser']; | ||
332 | } | ||
333 | |||
334 | randomBytes = Clipperz.Crypto.Base.generateRandomSeed(); | ||
335 | aConnection['b'] = new Clipperz.Crypto.BigInt(randomBytes, 16); | ||
336 | v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16); | ||
337 | aConnection['B'] = v.add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n())); | ||
338 | |||
339 | aConnection['A'] = someParameters.parameters.A; | ||
340 | |||
341 | result['s'] = aConnection['userData']['s']; | ||
342 | result['B'] = aConnection['B'].asString(16); | ||
343 | |||
344 | nextTollRequestType = 'CONNECT'; | ||
345 | } else if (someParameters.message == "credentialCheck") { | ||
346 | var v, u, S, A, K, M1; | ||
347 | |||
348 | v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16); | ||
349 | u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aConnection['B'].asString(10))).toHexString(), 16); | ||
350 | A = new Clipperz.Crypto.BigInt(aConnection['A'], 16); | ||
351 | S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()); | ||
352 | |||
353 | K = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(S.asString(10))).toHexString().slice(2); | ||
354 | |||
355 | M1 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + aConnection['B'].asString(10) + K)).toHexString().slice(2); | ||
356 | if (someParameters.parameters.M1 == M1) { | ||
357 | var M2; | ||
358 | |||
359 | M2 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + someParameters.parameters.M1 + K)).toHexString().slice(2); | ||
360 | result['M2'] = M2; | ||
361 | } else { | ||
362 | throw new Error("Client checksum verification failed! Expected <" + M1 + ">, received <" + someParameters.parameters.M1 + ">.", "Error"); | ||
363 | } | ||
364 | |||
365 | nextTollRequestType = 'MESSAGE'; | ||
366 | } else if (someParameters.message == "oneTimePassword") { | ||
367 | var otpData; | ||
368 | |||
369 | otpData = this.data()['onetimePasswords'][someParameters.parameters.oneTimePasswordKey]; | ||
370 | |||
371 | try { | ||
372 | if (typeof(otpData) != 'undefined') { | ||
373 | if (otpData['status'] == 'ACTIVE') { | ||
374 | if (otpData['key_checksum'] == someParameters.parameters.oneTimePasswordKeyChecksum) { | ||
375 | result = { | ||
376 | 'data': otpData['data'], | ||
377 | 'version':otpData['version'] | ||
378 | } | ||
379 | |||
380 | otpData['status'] = 'REQUESTED'; | ||
381 | } else { | ||
382 | otpData['status'] = 'DISABLED'; | ||
383 | throw "The requested One Time Password has been disabled, due to a wrong keyChecksum"; | ||
384 | } | ||
385 | } else { | ||
386 | throw "The requested One Time Password was not active"; | ||
387 | } | ||
388 | } else { | ||
389 | throw "The requested One Time Password has not been found" | ||
390 | } | ||
391 | } catch (exception) { | ||
392 | result = { | ||
393 | 'data': Clipperz.PM.Crypto.randomKey(), | ||
394 | 'version':Clipperz.PM.Connection.communicationProtocol.currentVersion | ||
395 | } | ||
396 | } | ||
397 | nextTollRequestType = 'CONNECT'; | ||
398 | } else { | ||
399 | Clipperz.logError("Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters.message); | ||
400 | } | ||
401 | |||
402 | result = { | ||
403 | result: result, | ||
404 | toll: this.getTollForRequestType(nextTollRequestType) | ||
405 | } | ||
406 | |||
407 | return result; | ||
408 | }, | ||
409 | |||
410 | //------------------------------------------------------------------------- | ||
411 | |||
412 | '_message': function(aConnection, someParameters) { | ||
413 | var result; | ||
414 | |||
415 | result = {}; | ||
416 | |||
417 | //===================================================================== | ||
418 | // | ||
419 | // R E A D - O N L Y M e t h o d s | ||
420 | // | ||
421 | //===================================================================== | ||
422 | if (someParameters.message == 'getUserDetails') { | ||
423 | var recordsStats; | ||
424 | var recordReference; | ||
425 | |||
426 | recordsStats = {}; | ||
427 | for (recordReference in aConnection['userData']['records']) { | ||
428 | recordsStats[recordReference] = { | ||
429 | 'updateDate': aConnection['userData']['records'][recordReference]['updateDate'] | ||
430 | } | ||
431 | } | ||
432 | |||
433 | result['header'] = this.userDetails(aConnection); | ||
434 | result['statistics'] = this.statistics(aConnection); | ||
435 | result['maxNumberOfRecords'] = aConnection['userData']['maxNumberOfRecords']; | ||
436 | result['version'] = aConnection['userData']['userDetailsVersion']; | ||
437 | result['recordsStats'] = recordsStats; | ||
438 | |||
439 | if (this.isReadOnly() == false) { | ||
440 | varlock; | ||
441 | |||
442 | if (typeof(aConnection['userData']['lock']) == 'undefined') { | ||
443 | aConnection['userData']['lock'] = "<<LOCK>>"; | ||
444 | } | ||
445 | |||
446 | result['lock'] = aConnection['userData']['lock']; | ||
447 | } | ||
448 | |||
449 | //===================================================================== | ||
450 | } else if (someParameters.message == 'getRecordDetail') { | ||
451 | /* | ||
452 | varrecordData; | ||
453 | var currentVersionData; | ||
454 | |||
455 | recordData = this.userData()['records'][someParameters['parameters']['reference']]; | ||
456 | result['reference'] = someParameters['parameters']['reference']; | ||
457 | result['data'] = recordData['data']; | ||
458 | result['version'] = recordData['version']; | ||
459 | result['creationData'] = recordData['creationDate']; | ||
460 | result['updateDate'] = recordData['updateDate']; | ||
461 | result['accessDate'] = recordData['accessDate']; | ||
462 | |||
463 | currentVersionData = recordData['versions'][recordData['currentVersion']]; | ||
464 | |||
465 | result['currentVersion'] = {}; | ||
466 | result['currentVersion']['reference'] = recordData['currentVersion']; | ||
467 | result['currentVersion']['version'] = currentVersionData['version']; | ||
468 | result['currentVersion']['header'] = currentVersionData['header']; | ||
469 | result['currentVersion']['data'] = currentVersionData['data']; | ||
470 | result['currentVersion']['creationData'] = currentVersionData['creationDate']; | ||
471 | result['currentVersion']['updateDate'] = currentVersionData['updateDate']; | ||
472 | result['currentVersion']['accessDate'] = currentVersionData['accessDate']; | ||
473 | if (typeof(currentVersionData['previousVersion']) != 'undefined') { | ||
474 | result['currentVersion']['previousVersionKey'] = currentVersionData['previousVersionKey']; | ||
475 | result['currentVersion']['previousVersion'] = currentVersionData['previousVersion']; | ||
476 | } | ||
477 | */ | ||
478 | MochiKit.Base.update(result, aConnection['userData']['records'][someParameters['parameters']['reference']]); | ||
479 | result['reference'] = someParameters['parameters']['reference']; | ||
480 | |||
481 | //===================================================================== | ||
482 | // | ||
483 | // R E A D - W R I T E M e t h o d s | ||
484 | // | ||
485 | //===================================================================== | ||
486 | } else if (someParameters.message == 'upgradeUserCredentials') { | ||
487 | if (this.isReadOnly() == false) { | ||
488 | var parameters; | ||
489 | var credentials; | ||
490 | |||
491 | parameters = someParameters['parameters']; | ||
492 | credentials = parameters['credentials']; | ||
493 | |||
494 | if ((credentials['C'] == null) | ||
495 | ||(credentials['s'] == null) | ||
496 | ||(credentials['v'] == null) | ||
497 | ||(credentials['version'] != Clipperz.PM.Connection.communicationProtocol.currentVersion) | ||
498 | ) { | ||
499 | result = Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed; | ||
500 | } else { | ||
501 | varoldCValue; | ||
502 | oldCValue = aConnection['C']; | ||
503 | |||
504 | this.data()['users'][credentials['C']] = aConnection['userData']; | ||
505 | aConnection['C'] = credentials['C']; | ||
506 | |||
507 | aConnection['userData']['s'] = credentials['s']; | ||
508 | aConnection['userData']['v'] = credentials['v']; | ||
509 | aConnection['userData']['version'] = credentials['version']; | ||
510 | |||
511 | aConnection['userData']['userDetails'] = parameters['user']['header']; | ||
512 | aConnection['userData']['userDetailsVersion'] = parameters['user']['version']; | ||
513 | aConnection['userData']['statistics'] = parameters['user']['statistics']; | ||
514 | |||
515 | aConnection['userData']['lock'] = parameters['user']['lock']; | ||
516 | |||
517 | delete this.data()['users'][oldCValue]; | ||
518 | |||
519 | result = {result:"done", parameters:parameters}; | ||
520 | } | ||
521 | } else { | ||
522 | throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly; | ||
523 | } | ||
524 | //===================================================================== | ||
525 | /* } else if (someParameters.message == 'updateData') { | ||
526 | if (this.isReadOnly() == false) { | ||
527 | var i, c; | ||
528 | |||
529 | if (this.userData()['lock']!= someParameters['parameters']['user']['lock']) { | ||
530 | throw "the lock attribute is not processed correctly" | ||
531 | } | ||
532 | |||
533 | this.userData()['userDetails'] = someParameters['parameters']['user']['header']; | ||
534 | this.userData()['statistics'] = someParameters['parameters']['user']['statistics']; | ||
535 | this.userData()['userDetailsVersions']= someParameters['parameters']['user']['version']; | ||
536 | |||
537 | c = someParameters['parameters']['records'].length; | ||
538 | for (i=0; i<c; i++) { | ||
539 | var currentRecord; | ||
540 | var currentRecordData; | ||
541 | |||
542 | currentRecordData = someParameters['parameters']['records'][i]; | ||
543 | currentRecord = this.userData()['records'][currentRecordData['record']['reference']]; | ||
544 | |||
545 | if (currentRecord == null) { | ||
546 | } | ||
547 | |||
548 | currentRecord['data'] = currentRecordData['record']['data']; | ||
549 | currentRecord['version'] = currentRecordData['record']['version']; | ||
550 | currentRecord['currentVersion'] = currentRecordData['currentRecordVersion']['reference']; | ||
551 | |||
552 | currentRecord['versions'][currentRecordData['currentRecordVersion']['reference']] = { | ||
553 | 'data': currentRecordData['currentRecordVersion']['data'], | ||
554 | 'version': currentRecordData['currentRecordVersion']['version'], | ||
555 | 'previousVersion': currentRecordData['currentRecordVersion']['previousVersion'], | ||
556 | 'previousVersionKey':currentRecordData['currentRecordVersion']['previousVersionKey'] | ||
557 | } | ||
558 | } | ||
559 | |||
560 | this.userData()['lock'] = Clipperz.PM.Crypto.randomKey(); | ||
561 | result['lock'] = this.userData()['lock']; | ||
562 | result['result'] = 'done'; | ||
563 | } else { | ||
564 | throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly; | ||
565 | } | ||
566 | */ //===================================================================== | ||
567 | } else if (someParameters.message == 'saveChanges') { | ||
568 | if (this.isReadOnly() == false) { | ||
569 | var i, c; | ||
570 | |||
571 | if (aConnection['userData']['lock']!= someParameters['parameters']['user']['lock']) { | ||
572 | throw "the lock attribute is not processed correctly" | ||
573 | } | ||
574 | |||
575 | aConnection['userData']['userDetails'] = someParameters['parameters']['user']['header']; | ||
576 | aConnection['userData']['statistics'] = someParameters['parameters']['user']['statistics']; | ||
577 | aConnection['userData']['userDetailsVersion']= someParameters['parameters']['user']['version']; | ||
578 | |||
579 | c = someParameters['parameters']['records']['updated'].length; | ||
580 | for (i=0; i<c; i++) { | ||
581 | var currentRecord; | ||
582 | var currentRecordData; | ||
583 | |||
584 | currentRecordData = someParameters['parameters']['records']['updated'][i]; | ||
585 | currentRecord = aConnection['userData']['records'][currentRecordData['record']['reference']]; | ||
586 | |||
587 | if ( | ||
588 | (typeof(aConnection['userData']['records'][currentRecordData['record']['reference']]) == 'undefined') | ||
589 | && | ||
590 | (typeof(currentRecordData['currentRecordVersion']) == 'undefined') | ||
591 | ) { | ||
592 | throw "Record added without a recordVersion"; | ||
593 | } | ||
594 | |||
595 | if (currentRecord == null) { | ||
596 | currentRecord = {}; | ||
597 | currentRecord['versions'] = {}; | ||
598 | currentRecord['creationDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date()); | ||
599 | currentRecord['accessDate'] = Clipperz.PM.Date.formatDateWithUTCFormat(new Date()); | ||
600 | |||
601 | aConnection['userData']['records'][currentRecordData['record']['reference']] = currentRecord; | ||
602 | } | ||
603 | |||
604 | currentRecord['data'] = currentRecordData['record']['data']; | ||
605 | currentRecord['version']= currentRecordData['record']['version']; | ||
606 | currentRecord['updateDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date()); | ||
607 | |||
608 | if (typeof(currentRecordData['currentRecordVersion']) != 'undefined') { | ||
609 | currentRecord['currentVersion'] = currentRecordData['currentRecordVersion']['reference']; | ||
610 | currentRecord['versions'][currentRecordData['currentRecordVersion']['reference']] = { | ||
611 | 'data': currentRecordData['currentRecordVersion']['data'], | ||
612 | 'version': currentRecordData['currentRecordVersion']['version'], | ||
613 | 'previousVersion': currentRecordData['currentRecordVersion']['previousVersion'], | ||
614 | 'previousVersionKey':currentRecordData['currentRecordVersion']['previousVersionKey'], | ||
615 | 'creationDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()), | ||
616 | 'updateDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()), | ||
617 | 'accessDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()) | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | |||
622 | c = someParameters['parameters']['records']['deleted'].length; | ||
623 | for (i=0; i<c; i++) { | ||
624 | var currentRecordReference; | ||
625 | |||
626 | currentRecordReference = someParameters['parameters']['records']['deleted'][i]; | ||
627 | delete aConnection['userData']['records'][currentRecordReference]; | ||
628 | } | ||
629 | |||
630 | aConnection['userData']['lock'] = Clipperz.PM.Crypto.randomKey(); | ||
631 | result['lock'] = aConnection['userData']['lock']; | ||
632 | result['result'] = 'done'; | ||
633 | } else { | ||
634 | throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly; | ||
635 | } | ||
636 | |||
637 | //===================================================================== | ||
638 | // | ||
639 | // U N H A N D L E D M e t h o d | ||
640 | // | ||
641 | //===================================================================== | ||
642 | } else { | ||
643 | Clipperz.logError("Clipperz.PM.Proxy.Test.message - unhandled message: " + someParameters.message); | ||
644 | } | ||
645 | |||
646 | result = { | ||
647 | result: result, | ||
648 | toll: this.getTollForRequestType('MESSAGE') | ||
649 | } | ||
650 | |||
651 | // return MochiKit.Async.succeed(result); | ||
652 | return result; | ||
653 | }, | ||
654 | |||
655 | //------------------------------------------------------------------------- | ||
656 | |||
657 | '_logout': function(someParameters) { | ||
658 | // return MochiKit.Async.succeed({result: 'done'}); | ||
659 | return {result: 'done'}; | ||
660 | }, | ||
661 | |||
662 | //========================================================================= | ||
663 | //######################################################################### | ||
664 | |||
665 | 'isTestData': function(aConnection) { | ||
666 | return (typeof(aConnection['userData']['__masterkey_test_value__']) != 'undefined'); | ||
667 | }, | ||
668 | |||
669 | 'userDetails': function(aConnection) { | ||
670 | var result; | ||
671 | |||
672 | if (this.isTestData(aConnection)) { | ||
673 | var serializedHeader; | ||
674 | var version; | ||
675 | |||
676 | //Clipperz.logDebug("### test data"); | ||
677 | version = aConnection['userData']['userDetailsVersion']; | ||
678 | serializedHeader = Clipperz.Base.serializeJSON(aConnection['userData']['userDetails']); | ||
679 | result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(aConnection['userData']['__masterkey_test_value__'], serializedHeader); | ||
680 | } else { | ||
681 | //Clipperz.logDebug("### NOT test data"); | ||
682 | result = aConnection['userData']['userDetails']; | ||
683 | } | ||
684 | |||
685 | return result; | ||
686 | }, | ||
687 | |||
688 | 'statistics': function(aConnection) { | ||
689 | var result; | ||
690 | |||
691 | if (aConnection['userData']['statistics'] != null) { | ||
692 | if (this.isTestData(aConnection)) { | ||
693 | var serializedStatistics; | ||
694 | var version; | ||
695 | |||
696 | version = aConnection['userData']['userDetailsVersion']; | ||
697 | serializedStatistics = Clipperz.Base.serializeJSON(aConnection['userData']['statistics']); | ||
698 | result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(aConnection['userData']['__masterkey_test_value__'], serializedStatistics); | ||
699 | } else { | ||
700 | result = aConnection['userData']['statistics']; | ||
701 | } | ||
702 | } else { | ||
703 | result = null; | ||
704 | } | ||
705 | |||
706 | return result; | ||
707 | }, | ||
708 | |||
709 | /* | ||
710 | 'userSerializedEncryptedData': function(someData) { | ||
711 | var deferredResult; | ||
712 | var deferredContext; | ||
713 | |||
714 | deferredContext = { 'data': someData }; | ||
715 | |||
716 | deferredResult = new Clipperz.Async.Deferred('Proxy.Test.serializeUserEncryptedData', {trace:false}); | ||
717 | deferredResult.addCallback(MochiKit.Base.bind(function(aDeferredContext) { | ||
718 | aDeferredContext['user'] = this.createUserUsingConfigurationData(aDeferredContext['data']); | ||
719 | return aDeferredContext; | ||
720 | }, this)); | ||
721 | deferredResult.addCallback(function(aDeferredContext) { | ||
722 | // return aDeferredContext['user'].encryptedDataUsingVersion(aDeferredContext['data']['version']); | ||
723 | return aDeferredContext['user'].serializedDataUsingVersion(MochiKit.Base.values(aDeferredContext['user'].records()), aDeferredContext['data']['version']); | ||
724 | }); | ||
725 | deferredResult.addCallback(function(aUserEncryptedData) { | ||
726 | deferredContext['encryptedData'] = aUserEncryptedData; | ||
727 | return deferredContext; | ||
728 | }); | ||
729 | deferredResult.addCallback(function(aDeferredContext) { | ||
730 | var connection; | ||
731 | |||
732 | connection = new Clipperz.PM.Connection.communicationProtocol.versions[aDeferredContext['data']['connectionVersion']]() | ||
733 | aDeferredContext['credentials'] = connection.serverSideUserCredentials(aDeferredContext['user'].username(),aDeferredContext['user'].passphrase()); | ||
734 | |||
735 | return aDeferredContext; | ||
736 | }); | ||
737 | |||
738 | // deferredResult.addCallback(function(aDeferredContext) { | ||
739 | // return aDeferredContext['user'].serializedDataUsingVersion(MochiKit.Base.values(aDeferredContext['user'].records()), aDeferredContext['data']['version']); | ||
740 | // }, deferredContext); | ||
741 | // deferredResult.addCallback(function(aUserSerializedData) { | ||
742 | // }); | ||
743 | // | ||
744 | // deferredResult.addCallback(MochiKit.Async.succeed, deferredContext); | ||
745 | deferredResult.callback(deferredContext); | ||
746 | |||
747 | return deferredResult; | ||
748 | }, | ||
749 | |||
750 | 'createUserUsingConfigurationData': function(someData) { | ||
751 | var result; | ||
752 | var user; | ||
753 | var recordLabel; | ||
754 | |||
755 | user = new Clipperz.PM.DataModel.User(); | ||
756 | user.initForTests(); | ||
757 | user.setUsername(someData['username']); | ||
758 | user.setPassphrase(someData['passphrase']); | ||
759 | |||
760 | for (recordLabel in someData['records']) { | ||
761 | var recordData; | ||
762 | var record; | ||
763 | var i, c; | ||
764 | |||
765 | recordData = someData['records'][recordLabel]; | ||
766 | record = new Clipperz.PM.DataModel.Record({user:user, label:recordLabel}); | ||
767 | record.setNotes(recordData['notes']); | ||
768 | |||
769 | c = recordData['fields'].length; | ||
770 | for (i=0; i<c; i++) { | ||
771 | var recordField; | ||
772 | |||
773 | recordField = new Clipperz.PM.DataModel.RecordField(); | ||
774 | recordField.setLabel(recordData['fields'][i]['name']); | ||
775 | recordField.setValue(recordData['fields'][i]['value']); | ||
776 | recordField.setType(recordData['fields'][i]['type']); | ||
777 | record.addField(recordField); | ||
778 | } | ||
779 | user.addRecord(record, true); | ||
780 | } | ||
781 | |||
782 | result = user; | ||
783 | |||
784 | return result; | ||
785 | }, | ||
786 | */ | ||
787 | //========================================================================= | ||
788 | __syntaxFix__: "syntax fix" | ||
789 | }); | ||
790 | |||
791 | Clipperz.PM.Proxy.Offline.DataStore['exception'] = { | ||
792 | 'ReadOnly': new MochiKit.Base.NamedError("Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly") | ||
793 | }; \ No newline at end of file | ||
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js new file mode 100644 index 0000000..a3c238c --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | try { if (typeof(Clipperz.PM.Proxy.Offline.DataStore) == 'undefined') { throw ""; }} catch (e) { | ||
25 | throw "Clipperz.PM.Proxy.Offline.LocalStorageDataStore depends on Clipperz.PM.Proxy.Offline.DataStore!"; | ||
26 | } | ||
27 | |||
28 | //============================================================================= | ||
29 | |||
30 | Clipperz.PM.Proxy.Offline.LocalStorageDataStore = 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 | //Clipperz.PM.Proxy.Offline.LocalStorageDataStore.superclass.constructor.apply(this, arguments); | ||
41 | |||
42 | return this; | ||
43 | } | ||
44 | |||
45 | Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.LocalStorageDataStore, Clipperz.PM.Proxy.Offline.DataStore, { | ||
46 | |||
47 | //========================================================================= | ||
48 | |||
49 | '_knock': function(aConnection, someParameters) { | ||
50 | var result; | ||
51 | |||
52 | result = { | ||
53 | toll: this.getTollForRequestType(someParameters['requestType']) | ||
54 | } | ||
55 | |||
56 | return result; | ||
57 | }, | ||
58 | |||
59 | //------------------------------------------------------------------------- | ||
60 | |||
61 | '_registration': function(aConnection, someParameters) { | ||
62 | throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly; | ||
63 | }, | ||
64 | |||
65 | //------------------------------------------------------------------------- | ||
66 | |||
67 | '_handshake': function(aConnection, someParameters) { | ||
68 | var result; | ||
69 | varnextTollRequestType; | ||
70 | |||
71 | result = {}; | ||
72 | if (someParameters.message == "connect") { | ||
73 | var userData; | ||
74 | var randomBytes; | ||
75 | var v; | ||
76 | |||
77 | userData = this.data()['users'][someParameters.parameters.C]; | ||
78 | |||
79 | if ((typeof(userData) != 'undefined') && (userData['version'] == someParameters.version)) { | ||
80 | aConnection['userData'] = userData; | ||
81 | aConnection['C'] = someParameters.parameters.C; | ||
82 | } else { | ||
83 | aConnection['userData'] = this.data()['users']['catchAllUser']; | ||
84 | } | ||
85 | |||
86 | randomBytes = Clipperz.Crypto.Base.generateRandomSeed(); | ||
87 | aConnection['b'] = new Clipperz.Crypto.BigInt(randomBytes, 16); | ||
88 | v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16); | ||
89 | aConnection['B'] = v.add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n())); | ||
90 | |||
91 | aConnection['A'] = someParameters.parameters.A; | ||
92 | |||
93 | result['s'] = aConnection['userData']['s']; | ||
94 | result['B'] = aConnection['B'].asString(16); | ||
95 | |||
96 | nextTollRequestType = 'CONNECT'; | ||
97 | } else if (someParameters.message == "credentialCheck") { | ||
98 | var v, u, S, A, K, M1; | ||
99 | |||
100 | v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16); | ||
101 | u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aConnection['B'].asString(10))).toHexString(), 16); | ||
102 | A = new Clipperz.Crypto.BigInt(aConnection['A'], 16); | ||
103 | S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()); | ||
104 | |||
105 | K = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(S.asString(10))).toHexString().slice(2); | ||
106 | |||
107 | M1 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + aConnection['B'].asString(10) + K)).toHexString().slice(2); | ||
108 | if (someParameters.parameters.M1 == M1) { | ||
109 | var M2; | ||
110 | |||
111 | M2 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + someParameters.parameters.M1 + K)).toHexString().slice(2); | ||
112 | result['M2'] = M2; | ||
113 | } else { | ||
114 | throw new Error("Client checksum verification failed! Expected <" + M1 + ">, received <" + someParameters.parameters.M1 + ">.", "Error"); | ||
115 | } | ||
116 | |||
117 | nextTollRequestType = 'MESSAGE'; | ||
118 | } else if (someParameters.message == "oneTimePassword") { | ||
119 | var otpData; | ||
120 | |||
121 | otpData = this.data()['onetimePasswords'][someParameters.parameters.oneTimePasswordKey]; | ||
122 | |||
123 | try { | ||
124 | if (typeof(otpData) != 'undefined') { | ||
125 | if (otpData['status'] == 'ACTIVE') { | ||
126 | if (otpData['key_checksum'] == someParameters.parameters.oneTimePasswordKeyChecksum) { | ||
127 | result = { | ||
128 | 'data': otpData['data'], | ||
129 | 'version':otpData['version'] | ||
130 | } | ||
131 | |||
132 | otpData['status'] = 'REQUESTED'; | ||
133 | } else { | ||
134 | otpData['status'] = 'DISABLED'; | ||
135 | throw "The requested One Time Password has been disabled, due to a wrong keyChecksum"; | ||
136 | } | ||
137 | } else { | ||
138 | throw "The requested One Time Password was not active"; | ||
139 | } | ||
140 | } else { | ||
141 | throw "The requested One Time Password has not been found" | ||
142 | } | ||
143 | } catch (exception) { | ||
144 | result = { | ||
145 | 'data': Clipperz.PM.Crypto.randomKey(), | ||
146 | 'version':Clipperz.PM.Connection.communicationProtocol.currentVersion | ||
147 | } | ||
148 | } | ||
149 | nextTollRequestType = 'CONNECT'; | ||
150 | } else { | ||
151 | Clipperz.logError("Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters.message); | ||
152 | } | ||
153 | |||
154 | result = { | ||
155 | result: result, | ||
156 | toll: this.getTollForRequestType(nextTollRequestType) | ||
157 | } | ||
158 | |||
159 | return result; | ||
160 | }, | ||
161 | |||
162 | //------------------------------------------------------------------------- | ||
163 | |||
164 | '_message': function(aConnection, someParameters) { | ||
165 | var result; | ||
166 | |||
167 | result = {}; | ||
168 | |||
169 | //===================================================================== | ||
170 | // | ||
171 | // R E A D - O N L Y M e t h o d s | ||
172 | // | ||
173 | //===================================================================== | ||
174 | if (someParameters.message == 'getUserDetails') { | ||
175 | var recordsStats; | ||
176 | var recordReference; | ||
177 | |||
178 | recordsStats = {}; | ||
179 | for (recordReference in aConnection['userData']['records']) { | ||
180 | recordsStats[recordReference] = { | ||
181 | 'updateDate': aConnection['userData']['records'][recordReference]['updateDate'] | ||
182 | } | ||
183 | } | ||
184 | |||
185 | result['header'] = this.userDetails(aConnection); | ||
186 | result['statistics'] = this.statistics(aConnection); | ||
187 | result['maxNumberOfRecords'] = aConnection['userData']['maxNumberOfRecords']; | ||
188 | result['version'] = aConnection['userData']['userDetailsVersion']; | ||
189 | result['recordsStats'] = recordsStats; | ||
190 | |||
191 | if (this.isReadOnly() == false) { | ||
192 | varlock; | ||
193 | |||
194 | if (typeof(aConnection['userData']['lock']) == 'undefined') { | ||
195 | aConnection['userData']['lock'] = "<<LOCK>>"; | ||
196 | } | ||
197 | |||
198 | result['lock'] = aConnection['userData']['lock']; | ||
199 | } | ||
200 | |||
201 | //===================================================================== | ||
202 | } else if (someParameters.message == 'getRecordDetail') { | ||
203 | /* | ||
204 | varrecordData; | ||
205 | var currentVersionData; | ||
206 | |||
207 | recordData = this.userData()['records'][someParameters['parameters']['reference']]; | ||
208 | result['reference'] = someParameters['parameters']['reference']; | ||
209 | result['data'] = recordData['data']; | ||
210 | result['version'] = recordData['version']; | ||
211 | result['creationData'] = recordData['creationDate']; | ||
212 | result['updateDate'] = recordData['updateDate']; | ||
213 | result['accessDate'] = recordData['accessDate']; | ||
214 | |||
215 | currentVersionData = recordData['versions'][recordData['currentVersion']]; | ||
216 | |||
217 | result['currentVersion'] = {}; | ||
218 | result['currentVersion']['reference'] = recordData['currentVersion']; | ||
219 | result['currentVersion']['version'] = currentVersionData['version']; | ||
220 | result['currentVersion']['header'] = currentVersionData['header']; | ||
221 | result['currentVersion']['data'] = currentVersionData['data']; | ||
222 | result['currentVersion']['creationData'] = currentVersionData['creationDate']; | ||
223 | result['currentVersion']['updateDate'] = currentVersionData['updateDate']; | ||
224 | result['currentVersion']['accessDate'] = currentVersionData['accessDate']; | ||
225 | if (typeof(currentVersionData['previousVersion']) != 'undefined') { | ||
226 | result['currentVersion']['previousVersionKey'] = currentVersionData['previousVersionKey']; | ||
227 | result['currentVersion']['previousVersion'] = currentVersionData['previousVersion']; | ||
228 | } | ||
229 | */ | ||
230 | MochiKit.Base.update(result, aConnection['userData']['records'][someParameters['parameters']['reference']]); | ||
231 | result['reference'] = someParameters['parameters']['reference']; | ||
232 | |||
233 | //===================================================================== | ||
234 | // | ||
235 | // R E A D - W R I T E M e t h o d s | ||
236 | // | ||
237 | //===================================================================== | ||
238 | } else if (someParameters.message == 'upgradeUserCredentials') { | ||
239 | if (this.isReadOnly() == false) { | ||
240 | var parameters; | ||
241 | var credentials; | ||
242 | |||
243 | parameters = someParameters['parameters']; | ||
244 | credentials = parameters['credentials']; | ||
245 | |||
246 | if ((credentials['C'] == null) | ||
247 | ||(credentials['s'] == null) | ||
248 | ||(credentials['v'] == null) | ||
249 | ||(credentials['version'] != Clipperz.PM.Connection.communicationProtocol.currentVersion) | ||
250 | ) { | ||
251 | result = Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed; | ||
252 | } else { | ||
253 | varoldCValue; | ||
254 | oldCValue = aConnection['C']; | ||
255 | |||
256 | this.data()['users'][credentials['C']] = aConnection['userData']; | ||
257 | aConnection['C'] = credentials['C']; | ||
258 | |||
259 | aConnection['userData']['s'] = credentials['s']; | ||
260 | aConnection['userData']['v'] = credentials['v']; | ||
261 | aConnection['userData']['version'] = credentials['version']; | ||
262 | |||
263 | aConnection['userData']['userDetails'] = parameters['user']['header']; | ||
264 | aConnection['userData']['userDetailsVersion'] = parameters['user']['version']; | ||
265 | aConnection['userData']['statistics'] = parameters['user']['statistics']; | ||
266 | |||
267 | aConnection['userData']['lock'] = parameters['user']['lock']; | ||
268 | |||
269 | delete this.data()['users'][oldCValue]; | ||
270 | |||
271 | result = {result:"done", parameters:parameters}; | ||
272 | } | ||
273 | } else { | ||
274 | throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly; | ||
275 | } | ||
276 | |||
277 | //===================================================================== | ||
278 | |||
279 | } else if (someParameters.message == 'saveChanges') { | ||
280 | if (this.isReadOnly() == false) { | ||
281 | var i, c; | ||
282 | |||
283 | if (aConnection['userData']['lock']!= someParameters['parameters']['user']['lock']) { | ||
284 | throw "the lock attribute is not processed correctly" | ||
285 | } | ||
286 | |||
287 | aConnection['userData']['userDetails'] = someParameters['parameters']['user']['header']; | ||
288 | aConnection['userData']['statistics'] = someParameters['parameters']['user']['statistics']; | ||
289 | aConnection['userData']['userDetailsVersion']= someParameters['parameters']['user']['version']; | ||
290 | |||
291 | c = someParameters['parameters']['records']['updated'].length; | ||
292 | for (i=0; i<c; i++) { | ||
293 | var currentRecord; | ||
294 | var currentRecordData; | ||
295 | |||
296 | currentRecordData = someParameters['parameters']['records']['updated'][i]; | ||
297 | currentRecord = aConnection['userData']['records'][currentRecordData['record']['reference']]; | ||
298 | |||
299 | if ( | ||
300 | (typeof(aConnection['userData']['records'][currentRecordData['record']['reference']]) == 'undefined') | ||
301 | && | ||
302 | (typeof(currentRecordData['currentRecordVersion']) == 'undefined') | ||
303 | ) { | ||
304 | throw "Record added without a recordVersion"; | ||
305 | } | ||
306 | |||
307 | if (currentRecord == null) { | ||
308 | currentRecord = {}; | ||
309 | currentRecord['versions'] = {}; | ||
310 | currentRecord['creationDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date()); | ||
311 | currentRecord['accessDate'] = Clipperz.PM.Date.formatDateWithUTCFormat(new Date()); | ||
312 | |||
313 | aConnection['userData']['records'][currentRecordData['record']['reference']] = currentRecord; | ||
314 | } | ||
315 | |||
316 | currentRecord['data'] = currentRecordData['record']['data']; | ||
317 | currentRecord['version']= currentRecordData['record']['version']; | ||
318 | currentRecord['updateDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date()); | ||
319 | |||
320 | if (typeof(currentRecordData['currentRecordVersion']) != 'undefined') { | ||
321 | currentRecord['currentVersion'] = currentRecordData['currentRecordVersion']['reference']; | ||
322 | currentRecord['versions'][currentRecordData['currentRecordVersion']['reference']] = { | ||
323 | 'data': currentRecordData['currentRecordVersion']['data'], | ||
324 | 'version': currentRecordData['currentRecordVersion']['version'], | ||
325 | 'previousVersion': currentRecordData['currentRecordVersion']['previousVersion'], | ||
326 | 'previousVersionKey':currentRecordData['currentRecordVersion']['previousVersionKey'], | ||
327 | 'creationDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()), | ||
328 | 'updateDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()), | ||
329 | 'accessDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()) | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | |||
334 | c = someParameters['parameters']['records']['deleted'].length; | ||
335 | for (i=0; i<c; i++) { | ||
336 | var currentRecordReference; | ||
337 | |||
338 | currentRecordReference = someParameters['parameters']['records']['deleted'][i]; | ||
339 | delete aConnection['userData']['records'][currentRecordReference]; | ||
340 | } | ||
341 | |||
342 | aConnection['userData']['lock'] = Clipperz.PM.Crypto.randomKey(); | ||
343 | result['lock'] = aConnection['userData']['lock']; | ||
344 | result['result'] = 'done'; | ||
345 | } else { | ||
346 | throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly; | ||
347 | } | ||
348 | |||
349 | //===================================================================== | ||
350 | // | ||
351 | // U N H A N D L E D M e t h o d | ||
352 | // | ||
353 | //===================================================================== | ||
354 | } else { | ||
355 | Clipperz.logError("Clipperz.PM.Proxy.Test.message - unhandled message: " + someParameters.message); | ||
356 | } | ||
357 | |||
358 | result = { | ||
359 | result: result, | ||
360 | toll: this.getTollForRequestType('MESSAGE') | ||
361 | } | ||
362 | |||
363 | // return MochiKit.Async.succeed(result); | ||
364 | return result; | ||
365 | }, | ||
366 | |||
367 | //------------------------------------------------------------------------- | ||
368 | |||
369 | '_logout': function(someParameters) { | ||
370 | // return MochiKit.Async.succeed({result: 'done'}); | ||
371 | return {result: 'done'}; | ||
372 | }, | ||
373 | |||
374 | //========================================================================= | ||
375 | //######################################################################### | ||
376 | /* | ||
377 | 'userDetails': function(aConnection) { | ||
378 | var result; | ||
379 | |||
380 | if (this.isTestData(aConnection)) { | ||
381 | var serializedHeader; | ||
382 | var version; | ||
383 | |||
384 | //Clipperz.logDebug("### test data"); | ||
385 | version = aConnection['userData']['userDetailsVersion']; | ||
386 | serializedHeader = Clipperz.Base.serializeJSON(aConnection['userData']['userDetails']); | ||
387 | result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(aConnection['userData']['__masterkey_test_value__'], serializedHeader); | ||
388 | } else { | ||
389 | //Clipperz.logDebug("### NOT test data"); | ||
390 | result = aConnection['userData']['userDetails']; | ||
391 | } | ||
392 | |||
393 | return result; | ||
394 | }, | ||
395 | |||
396 | 'statistics': function(aConnection) { | ||
397 | var result; | ||
398 | |||
399 | if (aConnection['userData']['statistics'] != null) { | ||
400 | if (this.isTestData(aConnection)) { | ||
401 | var serializedStatistics; | ||
402 | var version; | ||
403 | |||
404 | version = aConnection['userData']['userDetailsVersion']; | ||
405 | serializedStatistics = Clipperz.Base.serializeJSON(aConnection['userData']['statistics']); | ||
406 | result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(aConnection['userData']['__masterkey_test_value__'], serializedStatistics); | ||
407 | } else { | ||
408 | result = aConnection['userData']['statistics']; | ||
409 | } | ||
410 | } else { | ||
411 | result = null; | ||
412 | } | ||
413 | |||
414 | return result; | ||
415 | }, | ||
416 | */ | ||
417 | //========================================================================= | ||
418 | __syntaxFix__: "syntax fix" | ||
419 | }); | ||
420 | |||
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 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | try { 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 | |||
30 | Clipperz.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 | |||
43 | Clipperz.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 | |||
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.js new file mode 100644 index 0000000..6d6ee1e --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.js | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | if (typeof(Clipperz) == 'undefined') { Clipperz = {}; } | ||
25 | if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; } | ||
26 | |||
27 | //============================================================================= | ||
28 | |||
29 | Clipperz.PM.Proxy.Offline = function(args) { | ||
30 | args = args || {}; | ||
31 | |||
32 | Clipperz.PM.Proxy.Offline.superclass.constructor.call(this, args); | ||
33 | |||
34 | this._dataStore = args.dataStore || new Clipperz.PM.Proxy.Offline.DataStore(args); | ||
35 | |||
36 | return this; | ||
37 | } | ||
38 | |||
39 | Clipperz.Base.extend(Clipperz.PM.Proxy.Offline, Clipperz.PM.Proxy, { | ||
40 | |||
41 | 'toString': function () { | ||
42 | return "Clipperz.PM.Proxy.Offline"; | ||
43 | }, | ||
44 | |||
45 | //------------------------------------------------------------------------- | ||
46 | |||
47 | 'dataStore': function () { | ||
48 | return this._dataStore; | ||
49 | }, | ||
50 | |||
51 | //------------------------------------------------------------------------- | ||
52 | |||
53 | '_sendMessage': function(aFunctionName, aVersion, someParameters) { | ||
54 | return this.dataStore().processMessage(aFunctionName, someParameters); | ||
55 | }, | ||
56 | |||
57 | //------------------------------------------------------------------------- | ||
58 | |||
59 | 'isReadOnly': function () { | ||
60 | return this.dataStore().isReadOnly(); | ||
61 | }, | ||
62 | |||
63 | 'canRegisterNewUsers': function () { | ||
64 | return this.dataStore().canRegisterNewUsers(); | ||
65 | }, | ||
66 | |||
67 | //------------------------------------------------------------------------- | ||
68 | |||
69 | __syntaxFix__: "syntax fix" | ||
70 | |||
71 | }); | ||
72 | |||
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Test.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Test.js new file mode 100644 index 0000000..83d9244 --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Test.js | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | if (typeof(Clipperz) == 'undefined') { Clipperz = {}; } | ||
25 | if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; } | ||
26 | if (typeof(Clipperz.PM.Proxy) == 'undefined') { Clipperz.PM.Proxy = {}; } | ||
27 | |||
28 | //============================================================================= | ||
29 | |||
30 | Clipperz.PM.Proxy.Test = function(args) { | ||
31 | Clipperz.PM.Proxy.Test.superclass.constructor.call(this, args); | ||
32 | |||
33 | args = args || {}; | ||
34 | |||
35 | this._expectedRequests = (args.shouldCheckExpectedRequests === true) ? [] : null; | ||
36 | this._isExpectingRequests = true; | ||
37 | this._unexpectedRequests = []; | ||
38 | |||
39 | this.dataStore().resetData(); | ||
40 | |||
41 | return this; | ||
42 | } | ||
43 | |||
44 | Clipperz.Base.extend(Clipperz.PM.Proxy.Test, Clipperz.PM.Proxy.Offline, { | ||
45 | |||
46 | 'toString': function() { | ||
47 | return "Clipperz.PM.Proxy.Test"; | ||
48 | }, | ||
49 | |||
50 | //========================================================================= | ||
51 | |||
52 | 'expectedRequests': function () { | ||
53 | return this._expectedRequests; | ||
54 | }, | ||
55 | |||
56 | //------------------------------------------------------------------------- | ||
57 | |||
58 | 'shouldCheckExpectedRequests': function () { | ||
59 | return (this._expectedRequests != null); | ||
60 | }, | ||
61 | |||
62 | 'setShouldCheckExpectedRequests': function(aValue) { | ||
63 | if (aValue) { | ||
64 | this._expectedRequests = aValue; | ||
65 | } else { | ||
66 | this._expectedRequests = null; | ||
67 | } | ||
68 | }, | ||
69 | |||
70 | //------------------------------------------------------------------------- | ||
71 | |||
72 | 'shouldNotReceiveAnyFurtherRequest': function () { | ||
73 | this._isExpectingRequests = false; | ||
74 | }, | ||
75 | |||
76 | 'mayReceiveMoreRequests': function () { | ||
77 | this._isExpectingRequests = true; | ||
78 | this.resetUnexpectedRequests(); | ||
79 | }, | ||
80 | |||
81 | 'isExpectingRequests': function () { | ||
82 | return this._isExpectingRequests; | ||
83 | }, | ||
84 | |||
85 | //------------------------------------------------------------------------- | ||
86 | |||
87 | 'unexpectedRequests': function () { | ||
88 | return this._unexpectedRequests; | ||
89 | }, | ||
90 | |||
91 | 'resetUnexpectedRequests': function () { | ||
92 | this._unexpectedRequests = []; | ||
93 | }, | ||
94 | |||
95 | //------------------------------------------------------------------------- | ||
96 | |||
97 | 'testExpectedRequestParameters': function (aPath, anActualRequest, anExpectedRequest) { | ||
98 | var aKey; | ||
99 | for (aKey in anExpectedRequest) { | ||
100 | if (typeof(anActualRequest[aKey]) == 'undefined') { | ||
101 | throw "the expected paramter [" + aKey + "] is missing from the actual request"; | ||
102 | } | ||
103 | if (typeof(anExpectedRequest[aKey]) == 'object') { | ||
104 | this.testExpectedRequestParameters(aPath + "." + aKey, anActualRequest[aKey], anExpectedRequest[aKey]) | ||
105 | } else { | ||
106 | if (! anExpectedRequest[aKey](anActualRequest[aKey])) { | ||
107 | throw "wrong value for paramter [" + aKey + "]; got '" + anActualRequest[aKey] + "'"; | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | }, | ||
112 | |||
113 | //------------------------------------------------------------------------- | ||
114 | |||
115 | 'checkRequest': function(aFunctionName, someParameters) { | ||
116 | if (this.shouldCheckExpectedRequests()) { | ||
117 | var expectedRequest; | ||
118 | |||
119 | expectedRequest = this.expectedRequests().pop(); | ||
120 | if (expectedRequest == null) { | ||
121 | throw "Proxy.Test.sentMessage: no expected result specified. Got request '" + aFunctionName + "': " + someParameters; | ||
122 | } | ||
123 | |||
124 | try { | ||
125 | if (aFunctionName != expectedRequest.functionName) { | ||
126 | throw "wrong function name. Got '" + aFunctionName + "', expected '" + expectedRequest.request.functionName + "'"; | ||
127 | } | ||
128 | |||
129 | this.testExpectedRequestParameters("parameters", someParameters, expectedRequest.parameters); | ||
130 | } catch(exception) { | ||
131 | throw "Proxy.Test.sentMessage[" + expectedRequest.name + "]: " + exception; | ||
132 | } | ||
133 | } | ||
134 | }, | ||
135 | |||
136 | //========================================================================= | ||
137 | |||
138 | '_sendMessage': function(aFunctionName, aVersion, someParameters) { | ||
139 | var result; | ||
140 | |||
141 | if (this.isExpectingRequests() == false) { | ||
142 | // throw Clipperz.PM.Connection.exception.UnexpectedRequest; | ||
143 | Clipperz.log("UNEXPECTED REQUEST " + aFunctionName /* + ": " + Clipperz.Base.serializeJSON(someParameters) */); | ||
144 | this.unexpectedRequests().push({'functionName':aFunctionName, 'someParameters': someParameters}); | ||
145 | }; | ||
146 | //if (aFunctionName == 'knock') { | ||
147 | //console.log(">>> send message - " + aFunctionName, someParameters); | ||
148 | //} else { | ||
149 | //console.log(">>> SEND MESSAGE - " + aFunctionName + " [" + someParameters['parameters']['message'] + "]", someParameters['parameters']['parameters']); | ||
150 | //} | ||
151 | this.checkRequest(aFunctionName, someParameters); | ||
152 | result = Clipperz.PM.Proxy.Test.superclass._sendMessage.call(this, aFunctionName, aVersion, someParameters); | ||
153 | |||
154 | return result; | ||
155 | }, | ||
156 | |||
157 | //========================================================================= | ||
158 | __syntaxFix__: "syntax fix" | ||
159 | |||
160 | }); | ||
161 | |||