summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/PM
Unidiff
Diffstat (limited to 'frontend/delta/js/Clipperz/PM') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/PM/BookmarkletProcessor.js191
-rw-r--r--frontend/delta/js/Clipperz/PM/Connection.js636
-rw-r--r--frontend/delta/js/Clipperz/PM/Crypto.js546
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DirectLogin.js1086
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DirectLoginBinding.js120
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DirectLoginFormValue.js101
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DirectLoginInput.js192
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js542
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/OneTimePassword.js350
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/Record.Version.Field.js186
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js328
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/Record.js891
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Header.Legacy.js182
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js117
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Header.Preferences.js48
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js685
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.Subscription.js53
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/User.js827
-rw-r--r--frontend/delta/js/Clipperz/PM/Date.js196
-rw-r--r--frontend/delta/js/Clipperz/PM/PIN.js132
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy.js186
-rwxr-xr-xfrontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js86
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js793
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js420
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.MemoryDataStore.js643
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.js72
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy/Proxy.Test.js161
-rw-r--r--frontend/delta/js/Clipperz/PM/Strings.js285
-rw-r--r--frontend/delta/js/Clipperz/PM/Strings/MessagePanelConfigurations.js384
-rw-r--r--frontend/delta/js/Clipperz/PM/Strings/Strings_defaults.js385
-rw-r--r--frontend/delta/js/Clipperz/PM/Strings/Strings_en-US.js1336
-rw-r--r--frontend/delta/js/Clipperz/PM/Toll.js189
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js142
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/CardList.js161
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js46
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js150
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js122
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js33
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/RegistrationWizard.js240
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js256
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/MainController.js491
41 files changed, 13990 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/PM/BookmarkletProcessor.js b/frontend/delta/js/Clipperz/PM/BookmarkletProcessor.js
new file mode 100644
index 0000000..4818b76
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/BookmarkletProcessor.js
@@ -0,0 +1,191 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24/*
25if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
26if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
27
28Clipperz.PM.BookmarkletProcessor = function(aConfiguration) {
29 this._configuration = aConfiguration;
30
31 this._editableFields = null;
32 this._favicon = null;
33
34 return this;
35}
36
37Clipperz.PM.BookmarkletProcessor.prototype = MochiKit.Base.update(null, {
38
39 'toString': function() {
40 return "Clipperz.PM.BookmarkletProcessor";
41 },
42
43 //-------------------------------------------------------------------------
44
45 'configuration': function() {
46 return this._configuration;
47 },
48
49 //-------------------------------------------------------------------------
50
51 'pageTitle': function() {
52 return this.configuration().page.title;
53 },
54
55 //-------------------------------------------------------------------------
56
57 'fields': function() {
58 return this.configuration().form.inputs;
59 },
60
61 //-------------------------------------------------------------------------
62
63 'editableFields': function() {
64 if (this._editableFields == null) {
65 this._editableFields = MochiKit.Base.filter(function(aField) {
66 var result;
67 var type;
68
69 type = aField['type'].toLowerCase();
70 result = ((type != 'hidden') && (type != 'submit') && (type != 'checkbox') && (type != 'radio') && (type != 'select'));
71
72 return result;
73 }, this.fields())
74 }
75
76 return this._editableFields;
77 },
78
79 //-------------------------------------------------------------------------
80
81 'hostname': function() {
82 if (this._hostname == null) {
83 var actionUrl;
84
85 actionUrl = this.configuration()['form']['attributes']['action'];
86 this._hostname = actionUrl.replace(/ ^ h t t p s ? : \ / \ / ( [ ^ \ / ] * ) \ / . * /, '$1');
87 }
88
89 return this._hostname;
90 },
91
92 'favicon': function() {
93 if (this._favicon == null) {
94 this._favicon = "http://" + this.hostname() + "/favicon.ico";
95 }
96
97 return this._favicon;
98 },
99
100 //-------------------------------------------------------------------------
101 __syntaxFix__: "syntax fix"
102});
103
104//#############################################################################
105/ *
106Clipperz.PM.BookmarkletProcessor.createRecordFromBookmarkletConfiguration = function(anUser, aConfiguration) {
107 var processor;
108 var record;
109 var recordVersion;
110 var directLogin;
111 var bindings;
112 var i,c;
113
114 processor = new Clipperz.PM.BookmarkletProcessor(aConfiguration);
115
116 record = new Clipperz.PM.DataModel.Record({
117 'label':processor.pageTitle(),
118 'notes':"",
119 'user': anUser
120 });
121 recordVersion = new Clipperz.PM.DataModel.Record.Version(record, {})
122 record.setCurrentVersion(recordVersion);
123
124 bindings = {};
125
126 c = processor.editableFields().length;
127 for (i=0; i<c; i++) {
128 var formField;
129 var recordField;
130
131 formField = processor.editableFields()[i];
132 recordField = new Clipperz.PM.DataModel.RecordField({
133 'label':formField['name'],
134 'value':formField['value'],
135 'type': Clipperz.PM.Strings.inputTypeToRecordFieldType[formField['type']],
136 'hidden': false,
137 'recordVersion':recordVersion
138 });
139 recordVersion.addField(recordField);
140
141 bindings[formField['name']] = recordField.key();
142 }
143
144 directLogin = new Clipperz.PM.DataModel.DirectLogin({
145 'record': record,
146 'label': processor.pageTitle(),
147 'favicon': processor.favicon(),
148 'formData': processor.configuration()['form'],
149 'bindingData':bindings,
150 'bookmarkletVersion':'0.2'
151 });
152 record.addDirectLogin(directLogin);
153
154 anUser.addRecord(record);
155
156 return record;
157};
158* /
159//-----------------------------------------------------------------------------
160
161Clipperz.PM.BookmarkletProcessor.sanitizeBookmarkletConfiguration = function(aConfiguration) {
162 var result;
163
164 //throw "XSS Bookmarklet attempt";
165
166 result = aConfiguration;
167
168 return result;
169};
170
171//-----------------------------------------------------------------------------
172
173Clipperz.PM.BookmarkletProcessor.checkBookmarkletConfiguration = function(aConfiguration) {
174 var result;
175
176 try {
177 result = Clipperz.Base.evalJSON(aConfiguration);
178 result = Clipperz.PM.BookmarkletProcessor.sanitizeBookmarkletConfiguration(result);
179
180 if (result['version'] != '0.2.3') {
181 throw "WrongBookmarkletVersion";
182 }
183 } catch (exception) {
184 throw exception;
185 }
186
187 return result;
188};
189
190//-----------------------------------------------------------------------------
191*/ \ No newline at end of file
diff --git a/frontend/delta/js/Clipperz/PM/Connection.js b/frontend/delta/js/Clipperz/PM/Connection.js
new file mode 100644
index 0000000..c02125f
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Connection.js
@@ -0,0 +1,636 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26
27//-----------------------------------------------------------------------------
28//
29 // Abstract C O N N E C T I O N class
30//
31//-----------------------------------------------------------------------------
32
33Clipperz.PM.Connection = function (args) {
34 args = args || {};
35
36 this._proxy = args.proxy || Clipperz.PM.Proxy.defaultProxy;
37 this._getCredentialsFunction = args.getCredentialsFunction;
38
39 this._clipperz_pm_crypto_version = null;
40 this._connectionId = null;
41 this._sharedSecret = null;
42 this._serverLockValue = null;
43
44 return this;
45}
46
47Clipperz.PM.Connection.prototype = MochiKit.Base.update(null, {
48
49 'toString': function() {
50 return "Connection [" + this.version() + "]";
51 },
52
53 //=========================================================================
54
55 'version': function() {
56 throw Clipperz.Base.exception.AbstractMethod;
57 },
58
59 'clipperz_pm_crypto_version': function() {
60 if (this._clipperz_pm_crypto_version == null) {
61 var connectionVersions;
62 varversions;
63 varversion;
64 var i, c;
65
66 version = null;
67 connectionVersions = Clipperz.PM.Connection.communicationProtocol.versions;
68 versions = MochiKit.Base.keys(connectionVersions);
69 c = versions.length;
70 for (i=0; i<c; i++) {
71 if (! (versions[i] == 'current')) {
72 if (this instanceof connectionVersions[versions[i]]) {
73 version = versions[i];
74 };
75 }
76 }
77
78 this._clipperz_pm_crypto_version = version;
79 }
80
81 return this._clipperz_pm_crypto_version;
82 },
83
84 //-------------------------------------------------------------------------
85
86 'defaultErrorHandler': function(anErrorString, anException) {
87 // Clipperz.logError("### Connection.defaultErrorHandler: " + anErrorString, anException);
88 Clipperz.logError("### Connection.defaultErrorHandler: " + anErrorString + " (" + anException + ")");
89 },
90
91 //-------------------------------------------------------------------------
92
93 'getCredentialsFunction': function () {
94 return this._getCredentialsFunction;
95 },
96
97 'normalizedCredentials': function(someValues) {
98 throw Clipperz.Base.exception.AbstractMethod;
99 },
100
101 //=========================================================================
102
103 'proxy': function () {
104 return this._proxy;
105 },
106
107 //=========================================================================
108
109 'register': function () {
110 throw Clipperz.Base.exception.AbstractMethod;
111 },
112
113 'login': function() {
114 throw Clipperz.Base.exception.AbstractMethod;
115 },
116
117 //-------------------------------------------------------------------------
118
119 'message': function(someArguments, aCallback) {
120 throw Clipperz.Base.exception.AbstractMethod;
121 },
122
123 //-------------------------------------------------------------------------
124
125 'serverSideUserCredentials': function() {
126 throw Clipperz.Base.exception.AbstractMethod;
127 },
128
129 //=========================================================================
130
131 'sharedSecret': function () {
132 return this._sharedSecret;
133 },
134
135 'setSharedSecret': function (aValue) {
136 this._sharedSecret = aValue;
137 },
138
139 //-------------------------------------------------------------------------
140
141 'connectionId': function() {
142 return this._connectionId;
143 },
144
145 'setConnectionId': function(aValue) {
146 this._connectionId = aValue;
147 },
148
149 //-------------------------------------------------------------------------
150
151 'serverLockValue': function () {
152 return this._serverLockValue;
153 },
154
155 'setServerLockValue': function (aValue) {
156 this._serverLockValue = aValue;
157 },
158
159 //=========================================================================
160/*
161 //TODO: ?????
162 'oneTimePassword': function() {
163 return this._oneTimePassword;
164 },
165
166 'setOneTimePassword': function(aValue) {
167 this._oneTimePassword = aValue;
168 },
169*/
170 //=========================================================================
171
172 'reset': function() {
173 this.setSharedSecret(null);
174 this.setConnectionId(null);
175 },
176
177 //=========================================================================
178 __syntaxFix__: "syntax fix"
179
180}
181);
182
183
184if (typeof(Clipperz.PM.Connection.SRP) == 'undefined') { Clipperz.PM.Connection.SRP = {}; }
185//-----------------------------------------------------------------------------
186//
187 // S R P [ 1 . 0 ] C O N N E C T I O N class
188//
189//-----------------------------------------------------------------------------
190
191Clipperz.PM.Connection.SRP['1.0'] = function (args) {
192 Clipperz.PM.Connection.call(this, args);
193
194 return this;
195}
196
197Clipperz.PM.Connection.SRP['1.0'].prototype = MochiKit.Base.update(new Clipperz.PM.Connection(), {
198
199 'version': function() {
200 return '1.0';
201 },
202
203 //=========================================================================
204
205 'register': function (someUserData) {
206 vardeferredResult;
207 var cryptoVersion;
208 var srpConnection;
209
210 cryptoVersion = this.clipperz_pm_crypto_version();
211
212 deferredResult = new Clipperz.Async.Deferred("Connection.registerWithVersion", {trace:false});
213 deferredResult.collectResults({
214 'credentials': [
215 this.getCredentialsFunction(),
216 MochiKit.Base.method(this, 'normalizedCredentials'),
217 MochiKit.Base.bind(function(someCredentials) {
218 var srpConnection;
219 var result;
220
221 srpConnection = new Clipperz.Crypto.SRP.Connection({ C:someCredentials['username'], P:someCredentials['password'], hash:this.hash() });
222 result = srpConnection.serverSideCredentials();
223 result['version'] = Clipperz.PM.Connection.communicationProtocol.currentVersion;
224
225 return result;
226 }, this)
227 ],
228 'user': MochiKit.Base.partial(MochiKit.Async.succeed, someUserData),
229 'version':MochiKit.Base.partial(MochiKit.Async.succeed, Clipperz.PM.Connection.communicationProtocol.currentVersion),
230 'message':MochiKit.Base.partial(MochiKit.Async.succeed, 'completeRegistration')
231 });
232 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
233 deferredResult.addMethod(this.proxy(), 'registration');
234 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
235
236 deferredResult.callback();
237
238 return deferredResult;
239 },
240
241 //-------------------------------------------------------------------------
242
243 'updateCredentials': function (aUsername, aPassphrase, someUserData) {
244 vardeferredResult;
245
246 deferredResult = new Clipperz.Async.Deferred("Connection.updateCredentials", {trace:false});
247 deferredResult.collectResults({
248 'credentials': [
249 MochiKit.Base.method(this, 'normalizedCredentials', {username:aUsername, password:aPassphrase}),
250 MochiKit.Base.bind(function(someCredentials) {
251 var srpConnection;
252 var result;
253
254 srpConnection = new Clipperz.Crypto.SRP.Connection({ C:someCredentials['username'], P:someCredentials['password'], hash:this.hash() });
255 result = srpConnection.serverSideCredentials();
256 result['version'] = Clipperz.PM.Connection.communicationProtocol.currentVersion;
257
258 return result;
259 }, this)
260 ],
261 'user': MochiKit.Base.partial(MochiKit.Async.succeed, someUserData)
262 });
263 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
264 deferredResult.addMethod(this, 'message', 'upgradeUserCredentials');
265 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
266 deferredResult.callback();
267
268 return deferredResult;
269
270 },
271
272 //=========================================================================
273
274 'redeemOneTimePassword': function (someParameters) {
275/*
276 //=========================================================================
277 //LOGIN WITH PASSPHRASE, extracted from the TRUNK version (LoginPanel.js)
278 deferredResult.addCallback(function(anUsername, aOneTimePassword) {
279 var args;
280
281 args = {
282 'message': 'oneTimePassword',
283 'version': Clipperz.PM.Crypto.communicationProtocol.currentVersion,
284 'parameters': {
285 'oneTimePasswordKey': Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(anUsername, aOneTimePassword),
286 'oneTimePasswordKeyChecksum': Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(anUsername, aOneTimePassword)
287 }
288 }
289
290 return args;
291 }, anUsername, oneTimePassword);
292 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'OTP_login_loadingOTP');
293 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Proxy.defaultProxy, 'handshake'));
294 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'OTP_login_extractingPassphrase');
295 deferredResult.addCallback(function(aResult) {
296 return Clipperz.PM.Crypto.deferredDecrypt(oneTimePassword, aResult['data'], aResult['version']);
297 });
298 deferredResult.addCallback(function(aResult) {
299 return (new Clipperz.ByteArray().appendBase64String(aResult['passphrase'])).asString();
300 });
301 deferredResult.addMethod(this, 'doLoginWithUsernameAndPassphrase', anUsername),
302*/
303 var args;
304 var normalizedOTP;
305
306 normalizedOTP = Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(someParameters['password']);
307
308 args = {
309 'message': 'oneTimePassword',
310 'version': Clipperz.PM.Connection.communicationProtocol.currentVersion,
311 'parameters': {
312 'oneTimePasswordKey': Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(someParameters['username'], normalizedOTP),
313 'oneTimePasswordKeyChecksum':Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(someParameters['username'], normalizedOTP)
314 }
315 }
316
317 return Clipperz.Async.callbacks("Connction.redeemOTP", [
318 MochiKit.Base.method(this.proxy(), 'handshake', args),
319 function(aResult) {
320 return Clipperz.PM.Crypto.deferredDecrypt({
321 value:aResult['data'],
322 key:normalizedOTP,
323 version:aResult['version']
324 });
325 },
326 function(aResult) {
327 return (new Clipperz.ByteArray().appendBase64String(aResult['passphrase'])).asString();
328 }
329 ], {trace:false})
330 },
331
332 'login': function(isReconnecting) {
333 vardeferredResult;
334 var cryptoVersion;
335 var srpConnection;
336
337 cryptoVersion = this.clipperz_pm_crypto_version();
338 deferredResult = new Clipperz.Async.Deferred("Connection.login", {trace:false});
339 deferredResult.addCallback(this.getCredentialsFunction());
340 deferredResult.addMethod(this, 'normalizedCredentials');
341 // deferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'updatedProgressState', 'connection_sendingCredentials');
342 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
343 deferredResult.addCallback(MochiKit.Base.bind(function(someCredentials) {
344 srpConnection = new Clipperz.Crypto.SRP.Connection({ C:someCredentials['username'], P:someCredentials['password'], hash:this.hash() });
345 }, this));
346 deferredResult.addCallback(function() {
347 var result;
348
349 result = {
350 message: 'connect',
351 version: cryptoVersion,
352 parameters: {
353 C: srpConnection.C(),
354 A: srpConnection.A().asString(16)
355 // reconnecting: this.connectionId()
356 }
357 };
358
359 // TODO: ?????
360 // if (isReconnecting == true) {
361 // args.parameters['reconnecting'] = aConnection.connectionId();
362 // }
363
364 return result;
365 });
366 deferredResult.addMethod(this.proxy(), 'handshake');
367 // deferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'updatedProgressState', 'connection_credentialVerification');
368 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
369 deferredResult.addCallback(function(someParameters) {
370 var result;
371
372 srpConnection.set_s(new Clipperz.Crypto.BigInt(someParameters['s'], 16));
373 srpConnection.set_B(new Clipperz.Crypto.BigInt(someParameters['B'], 16));
374
375 //TODO: ?????
376 // if (typeof(someParameters['oneTimePassword']) != 'undefined') {
377 // this.setOneTimePassword(someParameters['oneTimePassword']);
378 // }
379
380 result = {
381 message: 'credentialCheck',
382 version: cryptoVersion,
383 parameters: {
384 M1: srpConnection.M1()
385 }
386 };
387
388 return result;
389 });
390 deferredResult.addMethod(this.proxy(), 'handshake');
391 deferredResult.addCallback(function(someParameters) {
392 var result;
393
394 if (someParameters['M2'] == srpConnection.M2()) {
395 result = MochiKit.Async.succeed(someParameters);
396 } else {
397 result = MochiKit.Async.fail(Clipperz.PM.Connection.exception.WrongChecksum);
398 }
399
400 return result;
401 });
402 deferredResult.addCallback(MochiKit.Base.bind(function(someParameters) {
403 this.setConnectionId(someParameters['connectionId']);
404 this.setSharedSecret(srpConnection.K());
405 // TODO: ?????
406 // if (this.oneTimePassword() != null) {
407 /// ?? result = this.user().oneTimePasswordManager().archiveOneTimePassword(this.oneTimePassword()));
408 // }
409
410 if ((isReconnecting == true) && (this.serverLockValue() != someParameters['lock'])) {
411 throw Clipperz.PM.Connection.exception.StaleData;
412 } else {
413 this.setServerLockValue(someParameters['lock']);
414 }
415
416 return someParameters;
417 }, this));
418 // deferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'updatedProgressState', 'connection_loggedIn');
419 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
420 // deferredResult.addCallback(MochiKit.Async.succeed, {result:"done"});
421
422 deferredResult.callback();
423
424 return deferredResult;
425 },
426
427 //=========================================================================
428
429 'logout': function() {
430 return Clipperz.Async.callbacks("Connection.logout", [
431 MochiKit.Base.method(this, 'setSharedSecret'),
432 MochiKit.Base.method(this.proxy(), 'logout', {})
433 ], {trace:false});
434 },
435
436 //=========================================================================
437
438 'ping': function () {
439 //TODO: ping the server in order to have a valid session
440 },
441
442 //=========================================================================
443
444 'message': function(aMessageName, someParameters) {
445 var args;
446 var parameters;
447
448 parameters = someParameters || {};
449 if (typeof(parameters['user']) != 'undefined') {
450 parameters['user']['lock'] = this.serverLockValue();
451 }
452
453 args = {
454 message: aMessageName,
455 srpSharedSecret: this.sharedSecret(),
456 // parameters: (someParameters || {})
457 parameters: parameters
458 }
459
460 return this.sendMessage(args);
461 },
462
463 //-------------------------------------------------------------------------
464
465 'sendMessage': function(someArguments) {
466 vardeferredResult;
467
468 deferredResult = new Clipperz.Async.Deferred("Connection.sendMessage", {trace:false});
469 deferredResult.addMethod(this.proxy(), 'message', someArguments);
470 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
471 if (typeof(res['lock']) != 'undefined') {
472 this.setServerLockValue(res['lock']);
473 }
474 return res;
475 }, this));
476
477 deferredResult.addErrback(MochiKit.Base.method(this, 'messageExceptionHandler'), someArguments);
478 deferredResult.callback();
479
480 return deferredResult
481 },
482
483 //-------------------------------------------------------------------------
484
485 'messageExceptionHandler': function(anOriginalMessageArguments, anError) {
486 var result;
487
488Clipperz.log(">>> Connection.messageExceptionHandler: " + anError.message, anError);
489 if (anError instanceof MochiKit.Async.CancelledError) {
490 result = anError;
491 } else {
492 if ((anError.message == 'Trying to communicate without an active connection')||
493 (anError.message == 'No tollManager available for current session')
494 ) {
495 result = this.reestablishConnection(anOriginalMessageArguments);
496 } else if (anError.message == 'Session with stale data') {
497 MochiKit.Signal.signal(this, 'EXCEPTION');
498 } else {
499 result = anError;
500 }
501 }
502Clipperz.log("<<< Connection.messageExceptionHandler")
503
504 return result;;
505 },
506
507 //=========================================================================
508
509 'reestablishConnection': function(anOriginalMessageArguments) {
510 var deferredResult;
511
512 deferredResult = new Clipperz.Async.Deferred("Connection.reestablishConnection");
513 deferredResult.addMethod(this, 'reset');
514 deferredResult.addMethod(this, 'login', true);
515 deferredResult.addCallback(MochiKit.Base.bind(function(aMessage) {
516 aMessage['srpSharedSecret'] = this.sharedSecret();
517 return aMessage;
518 }, this), anOriginalMessageArguments);
519 deferredResult.addMethod(this, 'sendMessage');
520 deferredResult.addErrback(MochiKit.Signal.signal, this, 'EXCEPTION', null);
521 deferredResult.callback();
522
523 return deferredResult;
524 },
525
526 //=========================================================================
527
528 'serverSideUserCredentials': function(aUsername, aPassword) {
529 varresult;
530 varnewSrpConnection;
531 var normalizedAttributes;
532
533 normalizedAttributes = this.normalizedCredentials({username:aUsername, password:aPassword});
534 newSrpConnection = new Clipperz.Crypto.SRP.Connection({ C:normalizedAttributes['username'], P:normalizedAttributes['password'], hash:this.hash() });
535 result = newSrpConnection.serverSideCredentials();
536 result['version'] = this.clipperz_pm_crypto_version();
537
538 return result;
539 },
540
541 //=========================================================================
542
543 'normalizedCredentials': function(someValues) {
544 var result;
545
546 result = {}
547 result['username'] = this.hash()(new Clipperz.ByteArray(someValues['username'])).toHexString().substring(2);
548 result['password'] = this.hash()(new Clipperz.ByteArray(someValues['password'] + someValues['username'])).toHexString().substring(2);
549
550 return result;
551 },
552
553 //-----------------------------------------------------------------------------
554
555 'hash': function() {
556 return Clipperz.PM.Crypto.encryptingFunctions.versions['0.1'].hash;
557 },
558
559 //-----------------------------------------------------------------------------
560 __syntaxFix__: "syntax fix"
561
562});
563
564
565
566//-----------------------------------------------------------------------------
567//
568 // S R P [ 1 . 1 ] C O N N E C T I O N class
569//
570//-----------------------------------------------------------------------------
571
572Clipperz.PM.Connection.SRP['1.1'] = function (args) {
573 Clipperz.PM.Connection.SRP['1.0'].call(this, args);
574
575 return this;
576}
577
578Clipperz.PM.Connection.SRP['1.1'].prototype = MochiKit.Base.update(new Clipperz.PM.Connection.SRP['1.0'](), {
579
580 'version': function() {
581 return '1.1';
582 },
583
584 //-----------------------------------------------------------------------------
585
586 'normalizedCredentials': function(someValues) {
587 var result;
588
589 result = {}
590 result['username'] = this.hash()(new Clipperz.ByteArray(someValues['username'] + someValues['password'])).toHexString().substring(2);
591 result['password'] = this.hash()(new Clipperz.ByteArray(someValues['password'] + someValues['username'])).toHexString().substring(2);
592
593 return result;
594 },
595
596 //-----------------------------------------------------------------------------
597
598 'hash': function() {
599 return Clipperz.PM.Crypto.encryptingFunctions.versions['0.2'].hash;
600 },
601
602 //-----------------------------------------------------------------------------
603 __syntaxFix__: "syntax fix"
604
605});
606
607Clipperz.PM.Connection.exception = {
608 WrongChecksum: new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.InvalidValue"),
609 StaleData: new MochiKit.Base.NamedError("Stale data"),
610 UnexpectedRequest:new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.UnexpectedRequest")
611};
612
613
614Clipperz.PM.Connection.communicationProtocol = {
615 'currentVersion': '0.2',
616 'versions': {
617 '0.1': Clipperz.PM.Connection.SRP['1.0'],//Clipperz.Crypto.SRP.versions['1.0'].Connection,
618 '0.2': Clipperz.PM.Connection.SRP['1.1']//Clipperz.Crypto.SRP.versions['1.1'].Connection
619 },
620 'fallbackVersions': {
621 // 'current':'0.1',
622 '0.2': '0.1',
623 '0.1': null
624 }
625};
626
627MochiKit.Base.update(Clipperz.PM.Connection.communicationProtocol.versions, {
628 'current': Clipperz.PM.Connection.communicationProtocol.versions[Clipperz.PM.Connection.communicationProtocol.currentVersion]
629});
630
631MochiKit.Base.update(Clipperz.PM.Connection.communicationProtocol.fallbackVersions, {
632 'current': Clipperz.PM.Connection.communicationProtocol.fallbackVersions[Clipperz.PM.Connection.communicationProtocol.currentVersion]
633});
634
635
636
diff --git a/frontend/delta/js/Clipperz/PM/Crypto.js b/frontend/delta/js/Clipperz/PM/Crypto.js
new file mode 100644
index 0000000..7edf17f
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Crypto.js
@@ -0,0 +1,546 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.Crypto) == 'undefined') { Clipperz.PM.Crypto = {}; }
27
28Clipperz.PM.Crypto.VERSION = "0.2";
29Clipperz.PM.Crypto.NAME = "Clipperz.PM.Crypto";
30
31Clipperz.PM.Crypto.encryptingFunctions = {};
32
33MochiKit.Base.update(Clipperz.PM.Crypto, {
34
35 '__repr__': function () {
36 return "[" + this.NAME + " " + this.VERSION + "]";
37 },
38
39 //-------------------------------------------------------------------------
40
41 'toString': function () {
42 return this.__repr__();
43 },
44
45 //-------------------------------------------------------------------------
46/*
47 'communicationProtocol': {
48 'currentVersion': '0.2',
49 'versions': {
50 '0.1': Clipperz.PM.Connection.SRP['1.0'],//Clipperz.Crypto.SRP.versions['1.0'].Connection,
51 '0.2': Clipperz.PM.Connection.SRP['1.1']//Clipperz.Crypto.SRP.versions['1.1'].Connection
52 },
53 'fallbackVersions': {
54 'current':'0.1',
55 '0.2': '0.1',
56 '0.1': null
57 }
58 },
59*/
60 //-------------------------------------------------------------------------
61
62 'encryptingFunctions': {
63 'currentVersion': '0.4',
64 'versions': {
65
66 //#####################################################################
67
68 '0.1': {
69 'encrypt': function(aKey, aValue) {
70 return Clipperz.Crypto.Base.encryptUsingSecretKey(aKey, Clipperz.Base.serializeJSON(aValue));
71 },
72
73 'deferredEncrypt': function(aKey, aValue) {
74 var deferredResult;
75
76 deferredResult = new Clipperz.Async.Deferred("Crypto[0.1].deferredEncrypt");
77 deferredResult.addCallback(Clipperz.PM.Crypto.encryptingFunctions.versions['0.1'].encrypt, aKey, aValue);
78 deferredResult.callback();
79
80 return deferredResult;
81 },
82
83 'decrypt': function(aKey, aValue) {
84 var result;
85
86 if (aValue != null) {
87 result = Clipperz.Base.evalJSON(Clipperz.Crypto.Base.decryptUsingSecretKey(aKey, aValue));
88 } else {
89 result = null;
90 }
91
92 return result;
93 },
94
95 'deferredDecrypt': function(aKey, aValue) {
96 var deferredResult;
97
98 deferredResult = new Clipperz.Async.Deferred("Crypto.[0.1].deferredDecrypt");
99 deferredResult.addCallback(Clipperz.PM.Crypto.encryptingFunctions.versions['0.1'].decrypt, aKey, aValue);
100 deferredResult.callback();
101
102 return deferredResult;
103 },
104
105 'hash': function(aValue) {
106 var result;
107 var strngResult;
108
109 stringResult = Clipperz.Crypto.Base.computeHashValue(aValue.asString()); //!!!!!!!
110 result = new Clipperz.ByteArray("0x" + stringResult);
111
112 return result;
113 },
114
115 'deriveKey': function(aStringValue) {
116 return Clipperz.Crypto.Base.computeHashValue(aStringValue);
117 }
118 },
119
120 //#####################################################################
121
122 '0.2': {
123 'encrypt': function(aKey, aValue, aNonce) {
124 var result;
125 varkey, value;
126 var dataToEncrypt;
127 var encryptedData;
128
129 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
130 value = new Clipperz.ByteArray(Clipperz.Base.serializeJSON(aValue));
131 dataToEncrypt = Clipperz.Crypto.SHA.sha_d256(value).appendBlock(value);
132 encryptedData = Clipperz.Crypto.AES.encrypt(key, dataToEncrypt, aNonce);
133 result = encryptedData.toBase64String();
134
135 return result;
136 },
137
138 'deferredEncrypt': function(aKey, aValue, aNonce) {
139 var deferredResult;
140 varkey, value;
141 var dataToEncrypt;
142 // var encryptedData;
143
144 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
145 value = new Clipperz.ByteArray(Clipperz.Base.serializeJSON(aValue));
146 dataToEncrypt = Clipperz.Crypto.SHA.sha_d256(value).appendBlock(value);
147
148 deferredResult = new Clipperz.Async.Deferred("Crypto[0.2].deferredEncrypt")
149 deferredResult.addCallback(Clipperz.Crypto.AES.deferredEncrypt, key, dataToEncrypt, aNonce);
150 deferredResult.addCallback(function(aResult) {
151 return aResult.toBase64String();
152 })
153 deferredResult.callback();
154
155 return deferredResult;
156 },
157
158 'decrypt': function(aKey, aValue) {
159 var result;
160
161 if (aValue != null) {
162 var key, value;
163 var decryptedData;
164 var decryptedValue;
165
166 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
167 value = new Clipperz.ByteArray().appendBase64String(aValue);
168
169 decryptedData = Clipperz.Crypto.AES.decrypt(key, value);
170 decryptedValue = decryptedData.split((256/8));
171
172 try {
173 result = Clipperz.Base.evalJSON(decryptedValue.asString());
174 } catch (exception) {
175 Clipperz.logError("Error while decrypting data [1]");
176 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
177 }
178 } else {
179 result = null;
180 }
181
182 return result;
183 },
184
185 'deferredDecrypt': function(aKey, aValue) {
186 var result;
187
188 if (aValue != null) {
189 var deferredResult;
190 var key, value;
191 // var decryptedData;
192
193 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
194 value = new Clipperz.ByteArray().appendBase64String(aValue);
195
196 deferredResult = new Clipperz.Async.Deferred("Crypto.[0.2].deferredDecrypt");
197 deferredResult.addCallback(Clipperz.Crypto.AES.deferredDecrypt, key, value);
198 deferredResult.addCallback(function(aResult) {
199 var result;
200 var decryptedData;
201
202 decryptedData = aResult.split((256/8));
203
204 try {
205 result = Clipperz.Base.evalJSON(decryptedData.asString());
206 } catch (exception) {
207 Clipperz.logError("Error while decrypting data [2]");
208 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
209 }
210
211 return result;
212 })
213 deferredResult.callback();
214
215 result = deferredResult;
216 } else {
217 result = MochiKit.Async.succeed(null);
218 }
219
220 return result;
221 },
222
223 'hash': Clipperz.Crypto.SHA.sha_d256,
224
225 'deriveKey': function(aStringValue) {
226 varbyteData;
227 var result;
228
229 byteData = new Clipperz.ByteArray(aStringValue);
230 result = Clipperz.Crypto.SHA.sha_d256(byteData);
231
232 return result;
233 }
234 },
235
236 //#####################################################################
237
238 '0.3': {
239 'encrypt': function(aKey, aValue, aNonce) {
240 var result;
241 varkey, value;
242 var data;
243 var dataToEncrypt;
244 var encryptedData;
245
246 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
247 value = Clipperz.Base.serializeJSON(aValue);
248 data = new Clipperz.ByteArray(value);
249 encryptedData = Clipperz.Crypto.AES.encrypt(key, data, aNonce);
250 result = encryptedData.toBase64String();
251
252 return result;
253 },
254
255 'deferredEncrypt': function(aKey, aValue, aNonce) {
256 var deferredResult;
257 varkey, value;
258 var data;
259 var dataToEncrypt;
260 var encryptedData;
261
262 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
263 value = Clipperz.Base.serializeJSON(aValue);
264 data = new Clipperz.ByteArray(value);
265
266 deferredResult = new Clipperz.Async.Deferred("Crypto[0.3].deferredEncrypt")
267 deferredResult.addCallback(Clipperz.Crypto.AES.deferredEncrypt, key, data, aNonce);
268 deferredResult.addCallback(function(aResult) {
269 return aResult.toBase64String();
270 })
271 deferredResult.callback();
272
273 return deferredResult;
274 },
275
276 'decrypt': function(aKey, aValue) {
277 var result;
278
279 if (aValue != null) {
280 var key, value;
281 var decryptedData;
282
283 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
284 value = new Clipperz.ByteArray().appendBase64String(aValue);
285
286 decryptedData = Clipperz.Crypto.AES.decrypt(key, value);
287
288 value = decryptedData.asString();
289 try {
290 result = Clipperz.Base.evalJSON(value);
291 } catch (exception) {
292 Clipperz.logError("Error while decrypting data [3]");
293 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
294 }
295 } else {
296 result = null;
297 }
298
299 return result;
300 },
301
302 'deferredDecrypt': function(aKey, aValue) {
303 var deferredResult;
304
305 deferredResult = new Clipperz.Async.Deferred("Crypto[0.3].deferredDecrypt", {trace: false});
306 // now = new Date;
307
308 if (aValue != null) {
309 var key, value;
310 // var decryptedData;
311
312 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
313 value = new Clipperz.ByteArray().appendBase64String(aValue);
314
315 deferredResult.addCallback(Clipperz.Crypto.AES.deferredDecrypt, key, value);
316 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
317 deferredResult.addCallback(function(aResult) {
318 return aResult.asString();
319 });
320 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
321 deferredResult.addCallback(Clipperz.Base.evalJSON);
322 deferredResult.addErrback(function(anError) {
323console.log("PIPPO_1", anError)
324 Clipperz.logError("Error while decrypting data [4]");
325 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
326 })
327 } else {
328 deferredResult.addCallback(function() {
329 return null;
330 });
331 }
332 deferredResult.callback();
333
334 return deferredResult;
335 },
336
337 'hash': Clipperz.Crypto.SHA.sha_d256,
338
339 'deriveKey': function(aStringValue) {
340 varbyteData;
341 var result;
342
343 byteData = new Clipperz.ByteArray(aStringValue);
344 result = Clipperz.Crypto.SHA.sha_d256(byteData);
345
346 return result;
347 }
348 },
349
350 //#####################################################################
351
352 '0.4': {
353 'encrypt': function(aKey, aValue, aNonce) {
354 var result;
355 varkey, value;
356 var data;
357 var dataToEncrypt;
358 var encryptedData;
359
360 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
361 value = Clipperz.Base.serializeJSON(aValue);
362 data = new Clipperz.ByteArray(value);
363 encryptedData = Clipperz.Crypto.AES_2.encrypt(key, data, aNonce);
364 result = encryptedData.toBase64String();
365
366 return result;
367 },
368
369 'deferredEncrypt': function(aKey, aValue, aNonce) {
370 var deferredResult;
371 varkey, value;
372 var data;
373 var dataToEncrypt;
374 var encryptedData;
375
376 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
377 value = Clipperz.Base.serializeJSON(aValue);
378 data = new Clipperz.ByteArray(value);
379
380 deferredResult = new Clipperz.Async.Deferred("Crypto[0.4].deferredEncrypt")
381 deferredResult.addCallback(Clipperz.Crypto.AES_2.deferredEncrypt, key, data, aNonce);
382 deferredResult.addCallback(function(aResult) {
383 return aResult.toBase64String();
384 })
385 deferredResult.callback();
386
387 return deferredResult;
388 },
389
390 'decrypt': function(aKey, aValue) {
391 var result;
392
393 if (aValue != null) {
394 var key, value;
395 var decryptedData;
396
397 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
398 value = new Clipperz.ByteArray().appendBase64String(aValue);
399
400 decryptedData = Clipperz.Crypto.AES_2.decrypt(key, value);
401
402 value = decryptedData.asString();
403 try {
404 result = Clipperz.Base.evalJSON(value);
405 } catch (exception) {
406 console.log("PIPPO_2", anError)
407 Clipperz.logError("Error while decrypting data [4]");
408 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
409 }
410 } else {
411 result = null;
412 }
413
414 return result;
415 },
416
417 'deferredDecrypt': function(aKey, aValue) {
418 var deferredResult;
419
420 deferredResult = new Clipperz.Async.Deferred("Crypto[0.4].deferredDecrypt", {trace: false});
421
422 if (aValue != null) {
423 var key, value;
424
425 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
426 value = new Clipperz.ByteArray().appendBase64String(aValue);
427
428 deferredResult.addCallback(Clipperz.Crypto.AES_2.deferredDecrypt, key, value);
429 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
430 deferredResult.addCallback(function(aResult) {
431 return aResult.asString();
432 });
433 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
434 deferredResult.addCallback(Clipperz.Base.evalJSON);
435 deferredResult.addErrback(function(anError) {
436 Clipperz.logError("Error while decrypting data [4]");
437 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
438 })
439 } else {
440 deferredResult.addCallback(function() {
441 return null;
442 });
443 }
444 deferredResult.callback();
445
446 return deferredResult;
447 },
448
449 'hash': Clipperz.Crypto.SHA.sha_d256,
450
451 'deriveKey': function(aStringValue) {
452 varbyteData;
453 var result;
454
455 byteData = new Clipperz.ByteArray(aStringValue);
456 result = Clipperz.Crypto.SHA.sha_d256(byteData);
457
458 return result;
459 }
460 },
461
462 //#####################################################################
463 __syntaxFix__: "syntax fix"
464 }
465 },
466
467 //-------------------------------------------------------------------------
468
469 'encrypt': function(aKey, aValue, aVersion) {
470 return Clipperz.PM.Crypto.encryptingFunctions.versions[aVersion].encrypt(aKey, aValue);
471 },
472
473 'deferredEncrypt': function(someParameters) {
474 return Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters['version']].deferredEncrypt(someParameters['key'], someParameters['value']);
475 },
476
477 //.........................................................................
478
479 'decrypt': function(aKey, aValue, aVersion) {
480 return Clipperz.PM.Crypto.encryptingFunctions.versions[aVersion].decrypt(aKey, aValue);
481 },
482
483 'deferredDecrypt': function(someParameters) {
484 return Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters['version']].deferredDecrypt(someParameters['key'], someParameters['value']);
485 },
486
487 //-------------------------------------------------------------------------
488
489 'hash': function(aValue) {
490 return Clipperz.PM.Crypto.encryptingFunctions.versions[Clipperz.PM.Crypto.encryptingFunctions.currentVersion]['hash'](aValue);
491 },
492
493 //-------------------------------------------------------------------------
494
495 'randomKey': function() {
496 return Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
497 },
498
499 //-------------------------------------------------------------------------
500
501 'deriveKey': function(aValue) {
502 return Clipperz.PM.Crypto.encryptingFunctions.versions[Clipperz.PM.Crypto.encryptingFunctions.currentVersion].deriveKey(aValue);
503 },
504
505 //-------------------------------------------------------------------------
506
507 'passwordEntropy': function(aValue) {
508 var result;
509 varbitPerChar;
510
511 bitPerChar = 4;
512 if (/[a-z]/.test(aValue)) {
513 bitPerChar ++;
514 }
515 if (/[A-Z]/.test(aValue)) {
516 bitPerChar ++;
517 }
518 if (/[^a-zA-Z0-9]/.test(aValue)) {
519 bitPerChar ++;
520 }
521
522 result = aValue.length * bitPerChar;
523
524 return result;
525 },
526
527 //-------------------------------------------------------------------------
528
529 'nullValue': '####',
530
531 //-------------------------------------------------------------------------
532 __syntaxFix__: "syntax fix"
533
534});
535
536//*****************************************************************************
537
538//MochiKit.Base.update(Clipperz.PM.Connection.communicationProtocol.versions, {
539 //'current': Clipperz.PM.Connection.communicationProtocol.versions[Clipperz.PM.Connection.communicationProtocol.currentVersion]
540//});
541
542MochiKit.Base.update(Clipperz.PM.Crypto.encryptingFunctions.versions, {
543 'current': Clipperz.PM.Crypto.encryptingFunctions.versions[Clipperz.PM.Crypto.encryptingFunctions.currentVersion]
544});
545
546//*****************************************************************************
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DirectLogin.js b/frontend/delta/js/Clipperz/PM/DataModel/DirectLogin.js
new file mode 100644
index 0000000..8db90de
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DirectLogin.js
@@ -0,0 +1,1086 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.Base.module('Clipperz.PM.DataModel');
25
26Clipperz.PM.DataModel.DirectLogin = function(args) {
27 args = args || {};
28
29 Clipperz.PM.DataModel.DirectLogin.superclass.constructor.apply(this, arguments);
30
31 this._reference =args.reference
32 ||Clipperz.PM.Crypto.randomKey();
33 this._record =args.record
34 ||Clipperz.Base.exception.raise('MandatoryParameter');
35
36 this._retrieveIndexDataFunction = args.retrieveIndexDataFunction
37 ||this.record().retrieveDirectLoginIndexDataFunction()
38 ||Clipperz.Base.exception.raise('MandatoryParameter');
39 this._setIndexDataFunction = args.setIndexDataFunction
40 ||this.record().setDirectLoginIndexDataFunction()
41 ||Clipperz.Base.exception.raise('MandatoryParameter');
42 this._removeIndexDataFunction =args.removeIndexDataFunction
43 ||this.record().removeDirectLoginIndexDataFunction()
44 ||Clipperz.Base.exception.raise('MandatoryParameter');
45
46 this._inputs = null;
47 this._bindings = null;
48 this._formValues = null;
49
50 // this._inputsDeferredLock = new MochiKit.Async.DeferredLock();
51 // this._bindingsDeferredLock = new MochiKit.Async.DeferredLock();
52 // this._formValuesDeferredLock = new MochiKit.Async.DeferredLock();
53
54 this._transientState = null;
55
56 this._isBrandNew = MochiKit.Base.isUndefinedOrNull(args.reference);
57
58 this.record().addDirectLogin(this);
59
60 return this;
61}
62
63Clipperz.Base.extend(Clipperz.PM.DataModel.DirectLogin, Object, {
64
65 'toString': function() {
66 return "DirectLogin (" + this.reference() + ")";
67 },
68
69 //=========================================================================
70
71 'reference': function () {
72 return this._reference;
73 },
74
75 //-------------------------------------------------------------------------
76
77 'record': function () {
78 return this._record;
79 },
80
81 //=========================================================================
82
83 'isBrandNew': function () {
84 return this._isBrandNew;
85 },
86
87 //=========================================================================
88
89 'removeIndexDataFunction': function () {
90 return this._removeIndexDataFunction;
91 },
92
93 'remove': function () {
94 return Clipperz.Async.callbacks("DirectLogin.remove", [
95 MochiKit.Base.partial(this.removeIndexDataFunction(), this.reference()),
96 MochiKit.Base.method(this.record(), 'removeDirectLogin', this)
97 ], {trace:false});
98 },
99
100 //=========================================================================
101 /*
102 'inputsDeferredLock': function () {
103 return this._inputsDeferredLock;
104 },
105
106 'bindingsDeferredLock': function () {
107 return this._bindingsDeferredLock;
108 },
109
110 'formValuesDeferredLock': function () {
111 return this._formValuesDeferredLock;
112 },
113*/
114 //=========================================================================
115
116 'label': function () {
117 return this.getIndexDataForKey('label');
118 },
119
120 'setLabelKeepingBackwardCompatibilityWithBeta': function (aValue) {
121 return Clipperz.Async.callbacks("DirectLogin.setLabelKeepingBackwardCompatibilityWithBeta", [
122 MochiKit.Base.method(this, 'setIndexDataForKey', 'label', aValue),
123 MochiKit.Base.method(this, 'setValue', 'label', aValue)
124 ], {trace:false});
125 },
126
127 'setLabel': function (aValue) {
128 return this.setLabelKeepingBackwardCompatibilityWithBeta(aValue);
129 // return this.setIndexDataForKey('label', aValue);
130 },
131
132 //=========================================================================
133
134 'favicon': function () {
135 return this.getIndexDataForKey('favicon');
136 },
137
138 'setFavicon': function (aValue) {
139 return this.setIndexDataForKey('favicon', aValue);
140 },
141
142 'faviconUrlWithBookmarkletConfiguration': function (aBookmarkletConfiguration) {
143 varresult;
144
145 if (! MochiKit.Base.isUndefinedOrNull(aBookmarkletConfiguration['page']['favicon'])) {
146 result = aBookmarkletConfiguration['page']['favicon'];
147 } else if (! MochiKit.Base.isUndefinedOrNull(aBookmarkletConfiguration['form']['attributes']['action'])) {
148 var actionUrl;
149 var hostname;
150
151 actionUrl = aBookmarkletConfiguration['form']['attributes']['action'];
152 hostname = actionUrl.replace(/^https?:\/\/([^\/]*)\/.*/, '$1');
153 result = "http://" + hostname + "/favicon.ico";
154 } else {
155 result = null;
156 }
157
158
159 return result;
160 },
161
162 //-------------------------------------------------------------------------
163/*
164 'faviconData': function () {
165 var regexp = new RegExp('^data\:\/\/.*', 'i');
166
167 return Clipperz.Async.callbacks("DirectLogin.favicon", [
168 MochiKit.Base.method(this, 'getIndexDataForKey', 'favicon'),
169 MochiKit.Base.method(regexp, 'test'),
170 Clipperz.Async.deferredIf("is data URL", [
171 MochiKit.Base.method(this, 'getIndexDataForKey', 'favicon')
172 ], [
173 MochiKit.Base.method(this, 'transientState'),
174 MochiKit.Base.itemgetter('faviconData'),
175 Clipperz.Async.deferredIf('has a chaced value for the favicon data', [
176 MochiKit.Base.operator.identity
177 ], [
178 MochiKit.Base.method(this, 'getIndexDataForKey', 'favicon'),
179 MochiKit.Base.method(this, 'loadFaviconDataFromURL')
180 ])
181
182 ])
183 ], {trace:false});
184 },
185
186 //-------------------------------------------------------------------------
187
188 'loadFaviconDataFromURL': function (anURL) {
189 var deferredResult;
190 var image;
191
192 deferredResult = new Clipperz.Async.Deferred("DirectLogin.loadFaviconDataFromURL", {trace:false});
193 deferredResult.addCallback(function (anEvent) {
194 var image = anEvent.src();
195 var canvas = document.createElement("canvas");
196 var result;
197
198 canvas.width = image.width;
199 canvas.height = image.height;
200
201 var ctx = canvas.getContext("2d");
202 ctx.drawImage(image, 0, 0);
203
204 result = canvas.toDataURL(/*"image/png"* /);
205
206 return result;
207 });
208 deferredResult.addErrback(MochiKit.Async.succeed, Clipperz.PM.Strings.getValue('defaultFaviconUrl'));
209 deferredResult.addBoth(MochiKit.Base.bind(function (aDataUrl) {
210 this.transientState()['faviconData'] = aDataUrl;
211
212 return aDataUrl;
213 }, this));
214
215 image = new Image();
216 MochiKit.Signal.connect(image, 'onload', MochiKit.Base.method(deferredResult, 'callback'));
217 MochiKit.Signal.connect(image, 'onerror', MochiKit.Base.method(deferredResult, 'errback'));
218 MochiKit.Signal.connect(image, 'onabort', MochiKit.Base.method(deferredResult, 'errback'));
219
220 image.src = anURL;
221
222 return deferredResult;
223 },
224*/
225
226 //=========================================================================
227
228 'type': function () {
229 return this.getValue('formData.attributes.type')
230 },
231
232 //=========================================================================
233
234 'serializedData': function () {
235 return Clipperz.Async.collectResults("DirectLogin.serializedData", {
236 'bookmarkletVersion': MochiKit.Base.method(this, 'getValue', 'bookmarkletVersion'),
237 'formData': MochiKit.Base.method(this, 'getValue', 'formData'),
238 'formValues': MochiKit.Base.method(this, 'getValue', 'formValues'),
239 'bindingData': [
240 MochiKit.Base.method(this, 'bindings'),
241 function (someBindings) {
242 var result;
243 var bindingKey;
244
245 result = {}
246 for (bindingKey in someBindings) {
247 result[bindingKey] = someBindings[bindingKey].serializedData();
248 }
249
250 return result;
251 }
252 ]
253 }, {trace:false})()
254 },
255
256 //=========================================================================
257/*
258 'fixFormDataFromBookmarkletVersion_0_1': function(aValue) {
259//{"type":"radio", "name":"action", "value":"new-user", "checked":false }, { "type":"radio", "name":"action", "value":"sign-in", "checked":true }
260 // ||
261 // \ /
262 // \/
263//{"name":"dominio", "type":"radio", "options":[{"value":"@alice.it", "checked":true}, {"value":"@tin.it", "checked":false}, {"value":"@virgilio.it", "checked":false}, {"value":"@tim.it", "checked":false}]}
264 var result;
265 var inputs;
266 var updatedInputs;
267 var radios;
268
269 result = aValue;
270 inputs = aValue['inputs'];
271
272 updatedInputs = MochiKit.Base.filter(function(anInput) {
273 varresult;
274 var type;
275
276 type = anInput['type'] || 'text';
277 result = type.toLowerCase() != 'radio';
278
279 return result;
280 }, inputs);
281 radios = MochiKit.Base.filter(function(anInput) {
282 varresult;
283 var type;
284
285 type = anInput['type'] || 'text';
286 result = type.toLowerCase() == 'radio';
287
288 return result;
289 }, inputs);
290
291 if (radios.length > 0) {
292 var updatedRadios;
293
294 updatedRadios = {};
295 MochiKit.Iter.forEach(radios, MochiKit.Base.bind(function(aRadio) {
296 varradioConfiguration;
297
298 radioConfiguration = updatedRadios[aRadio['name']];
299 if (radioConfiguration == null) {
300 radioConfiguration = {type:'radio', name:aRadio['name'], options:[]};
301 updatedRadios[aRadio['name']] = radioConfiguration;
302 }
303
304 //TODO: remove the value: field and replace it with element.dom.value = <some value>
305 radioConfiguration.options.push({value:aRadio['value'], checked:aRadio['checked']});
306
307 //TODO: shoud remove the 'formValues' call, as it is now deferred
308 // if ((aRadio['checked'] == true) && (this.formValues()[aRadio['name']] == null)) {
309 // this.formValues()[aRadio['name']] = aRadio['value'];
310 // }
311 }, this))
312
313 updatedInputs = MochiKit.Base.concat(updatedInputs, MochiKit.Base.values(updatedRadios));
314 }
315
316 delete result.inputs;
317 result.inputs = updatedInputs;
318
319 return result;
320 },
321
322 '_fixConfiguration': function (aConfiguration) {
323 var fixedConfiguration;
324 // var inputs;
325 // var bindings;
326 // var i,c;
327
328 fixedConfiguration = Clipperz.Base.deepClone(aConfiguration);
329
330//Clipperz.log("PROCESS CONFIGURATION", aConfiguration);
331 switch (aConfiguration['bookmarkletVersion']) {
332 case '0.1':
333 fixedConfiguration['formData'] = this.fixFormDataFromBookmarkletVersion_0_1(aConfiguration['formData']);
334 break;
335 case '0.2':
336 fixedConfiguration['formData'] = aConfiguration['formData'];
337 break;
338 }
339
340 / *
341 aConfiguration['_inputs'] = [];
342 c = formData['inputs'].length;
343 for (i=0; i<c; i++) {
344 aConfiguration['_inputs'].push(new Clipperz.PM.DataModel.DirectLoginInput(formData['inputs'][i]));
345 }
346* /
347/ *
348 aConfiguration['_bindings'] = {};
349 if (aConfiguration['legacyBindingData'] == null) {
350 if (aConfiguration['bindingData'] != null) {
351 var bindingKey;
352
353 for (bindingKey in aConfiguration['bindingData']) {
354 var newBinding;
355
356 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(bindingKey, {fieldKey:aConfiguration['bindingData'][bindingKey]});
357 aConfiguration['_bindings'][newBinding.key()] = newBinding;
358 }
359 } else {
360 var editableFields;
361
362 editableFields = MochiKit.Base.filter(function(aField) {
363 var result;
364 var type;
365
366 type = aField['type'].toLowerCase();
367 result = ((type != 'hidden') && (type != 'submit') && (type != 'checkbox') && (type != 'radio') && (type != 'select'));
368
369 return result;
370 }, aConfiguration['_inputs']);
371
372 MochiKit.Iter.forEach(editableFields, MochiKit.Base.bind(function(anEditableField) {
373 var newBinding;
374
375 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(anEditableField['name']);
376 aConfiguration['_bindings'][newBinding.key()] = newBinding;
377 }, this));
378 }
379
380 } else {
381 var bindingKey;
382
383 for (bindingKey in aConfiguration['legacyBindingData']) {
384 var newBinding;
385
386 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(bindingKey, {fieldName:aConfiguration['legacyBindingData'][bindingKey]});
387 aConfiguration['_bindings'][newBinding.key()] = newBinding;
388 }
389 }
390* /
391
392 return fixedConfiguration;
393 },
394
395 //-------------------------------------------------------------------------
396
397 'getObjectDataStore': function () {
398 var deferredResult;
399
400 deferredResult = new Clipperz.Async.Deferred("DirectLogin.getObjectDataStore", {trace:false});
401 deferredResult.acquireLock(this.objectDataStoreDeferredLock());
402 deferredResult.addCallback(MochiKit.Base.bind(function () {
403 var innerDeferredResult;
404
405 if (this._objectDataStore == null) {
406 this._objectDataStore = new Clipperz.KeyValueObjectStore();
407
408 innerDeferredResult = new Clipperz.Async.Deferred("DirectLogin.getObjectDataStore <inner deferred>", {trace:false});
409 // innerDeferredResult.addMethod(this.record(), 'getValue', 'directLogins' + '.' + this.reference());
410 innerDeferredResult.addMethod(this, 'getValue', ''),
411 innerDeferredResult.addMethod(this, 'setOriginalState');
412 innerDeferredResult.addMethod(this, '_fixConfiguration');
413 innerDeferredResult.addMethod(this._objectDataStore, 'initWithValues');
414 // innerDeferredResult.addMethod(this._objectDataStore, 'setValues');
415 innerDeferredResult.callback();
416 } else {
417 innerDeferredResult = MochiKit.Async.succeed(this._objectDataStore);
418 }
419
420 return innerDeferredResult;
421 }, this));
422 deferredResult.releaseLock(this.objectDataStoreDeferredLock());
423 deferredResult.callback();
424
425 return deferredResult;
426 },
427
428 //-------------------------------------------------------------------------
429
430 'hasInitiatedObjectDataStore': function () {
431 return (this._objectDataStore != null);
432 },
433
434 //-------------------------------------------------------------------------
435
436 'resetObjectDataStore': function () {
437 this._objectDataStore.removeAllData();
438 this._objectDataStore = null;
439 },
440*/
441 //=========================================================================
442
443 'bookmarkletConfiguration': function () {
444 return Clipperz.Async.callbacks("DirectLogin.bookmarkletConfiguration", [
445 Clipperz.Async.collectResults("DirectLogin.bookmarkletConfiguration <inner results>", {
446 'label': MochiKit.Base.method(this, 'label'),
447 'configuration': MochiKit.Base.method(this, 'getValue', '')
448 }, {trace:false}),
449 function (someValues) {
450 var result;
451
452 if (someValues['configuration'] != null) {
453 varconfiguration;
454
455 configuration = {
456 'page': {
457 'title': someValues['label']
458 //'favicon'
459 // 'url'
460 },
461 'form': someValues['configuration']['formData'],
462 'version':someValues['configuration']['bookmarkletVersion']
463 }
464
465 result = Clipperz.Base.formatJSON(configuration);
466 } else {
467 result = '';
468 }
469
470 return result;
471 }
472 ], {trace:false});
473
474 },
475
476 //-------------------------------------------------------------------------
477
478 'setBookmarkletConfiguration': function (aValue) {
479 var bookmarkletConfiguration;
480
481 bookmarkletConfiguration = Clipperz.PM.DataModel.DirectLogin.checkBookmarkletConfiguration(aValue);
482
483 return Clipperz.Async.callbacks("DirectLogin.setBookmarkletConfiguration", [
484 MochiKit.Base.method(this, 'setValue', 'formData', bookmarkletConfiguration['form']),
485 MochiKit.Base.method(this, 'setValue', 'bookmarkletVersion', bookmarkletConfiguration['version']),
486
487 MochiKit.Base.method(this, 'favicon'),
488 Clipperz.Async.deferredIf("the favicon is not set", [
489 ], [
490 MochiKit.Base.method(this, 'faviconUrlWithBookmarkletConfiguration', bookmarkletConfiguration),
491 MochiKit.Base.method(this, 'setFavicon')
492 ]),
493
494 MochiKit.Base.method(this, 'updateInputsAfterChangingBookmarkletConfiguration'),
495 MochiKit.Base.method(this, 'updateFormValuesAfterChangingBookmarkletConfiguration'),
496 MochiKit.Base.method(this, 'updateBindingsAfterChangingBookmarkletConfiguration'),
497
498 MochiKit.Base.noop
499 ], {trace:false});
500 },
501
502 //=========================================================================
503
504 'formAttributes': function () {
505 return this.getValue('formData.attributes');
506 },
507
508 //=========================================================================
509
510 'inputs': function () {
511 return Clipperz.Async.callbacks("DirectLogin.inputs", [
512 Clipperz.Async.deferredIf("this._inputs is defined", [
513 ], [
514 MochiKit.Base.method(this, 'updateInputsAfterChangingBookmarkletConfiguration')
515 ])
516 ], {trace:false}, this._inputs);
517 },
518
519 'setInputWithFormDataConfiguration': function (aFormDataConfiguration) {
520 this._inputs = {};
521
522 if (aFormDataConfiguration != null) {
523 MochiKit.Iter.forEach(aFormDataConfiguration['inputs'], MochiKit.Base.bind(function (anInputData) {
524 var newInput;
525
526 newInput = new Clipperz.PM.DataModel.DirectLoginInput(anInputData);
527 this._inputs[newInput.name()] = newInput;
528 }, this));
529 }
530
531 return this._inputs;
532 },
533
534 'updateInputsAfterChangingBookmarkletConfiguration': function () {
535 return Clipperz.Async.callbacks("DirectLogin.updateInputsAfterChangingBookmarkletConfiguration", [
536 MochiKit.Base.method(this, 'getValue', 'formData'),
537 MochiKit.Base.method(this, 'setInputWithFormDataConfiguration')
538 ], {trace:false});
539 },
540
541 //=========================================================================
542
543 'inputValues': function () {
544 return Clipperz.Async.callbacks("DirectLogin.inputValues", [
545 MochiKit.Base.method(this, 'inputs'),
546 MochiKit.Base.values,
547 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.partial(MochiKit.Base.method(this, 'inputValue'))),
548 Clipperz.Async.collectAll,
549 Clipperz.Base.mergeItems
550 ], {trace:false});
551 },
552
553 'inputValue': function (anInput) {
554 vardeferredResult;
555
556 deferredResult = new Clipperz.Async.Deferred("DirectLogin.inputValue", {trace:false});
557
558 if (anInput.needsFormValue()) {
559 deferredResult.addMethod(this, 'formValues');
560 deferredResult.addCallback(MochiKit.Base.itemgetter(anInput.name()));
561 deferredResult.addMethodcaller('value');
562 } else if (anInput.needsBinding()) {
563 deferredResult.addMethod(this, 'bindings');
564 deferredResult.addCallback(MochiKit.Base.itemgetter(anInput.name()));
565 deferredResult.addMethodcaller('field');
566 deferredResult.addMethodcaller('value');
567 } else {
568 deferredResult.addCallback(MochiKit.Async.succeed, anInput.value());
569 }
570 deferredResult.addCallback(function (anActualValue) {
571 return [anInput.name(), anActualValue];
572 });
573
574 deferredResult.callback();
575
576 return deferredResult;
577 },
578
579 //=========================================================================
580
581 'bindings': function () {
582 return Clipperz.Async.callbacks("DirectLogin.bindings", [
583 Clipperz.Async.deferredIf("this._bindings is defined", [
584 ], [
585 MochiKit.Base.method(this, 'updateBindingsAfterChangingBookmarkletConfiguration'),
586 MochiKit.Base.bind(function () { return this._bindings;}, this)
587 ])
588 ], {trace:false}, this._bindings);
589 },
590
591 'bindFormFieldWithLabelToRecordFieldWithLabel': function (aFormFieldLabel, aRecordFieldLabel) {
592 return Clipperz.Async.callbacks("DirectLogin.bindFormFieldWithLabelToCardFieldWithLabel", [
593 Clipperz.Async.collectResults("DirectLogin.bindFormFieldWithLabelToCardFieldWithLabel - collect results", {
594 'binding': [
595 MochiKit.Base.method(this, 'bindings'),
596 MochiKit.Base.itemgetter(aFormFieldLabel)
597 ],
598 'field': [
599 MochiKit.Base.method(this.record(), 'fieldWithLabel', aRecordFieldLabel)
600 ]
601 }),
602 function (someValues) {
603 someValues['binding'].setField(someValues['field'])
604 }
605 ], {trace:false});
606 },
607
608 //-------------------------------------------------------------------------
609/*
610 'bindingValues': function () {
611 return Clipperz.Async.callbacks("DirectLogin.bindingValues", [
612 Clipperz.Async.collectResults("DirectLogin.bindingValues [collectResults]", {
613 'fieldValues': [
614 MochiKit.Base.method(this, 'record'),
615 MochiKit.Base.methodcaller('getFieldsValues')
616 ],
617 'bindings': MochiKit.Base.method(this, 'bindings')
618 }, {trace:false}),
619 function (someData) {
620 var result;
621 varbindingKey;
622
623 result = {};
624 for (bindingKey in someData['bindings']) {
625 result[bindingKey] = someData['fieldValues'][someData['bindings'][bindingKey].fieldKey()]['value'];
626 }
627
628 return result;
629 }
630 ], {trace:false});
631 },
632*/
633 //-------------------------------------------------------------------------
634
635 'updateBindingsAfterChangingBookmarkletConfiguration': function () {
636 return Clipperz.Async.callbacks("DirectLogin.updateBindingsAfterChangingBookmarkletConfiguration", [
637 Clipperz.Async.collectResults("DirectLogin.updateBindingsAfterChangingBookmarkletConfiguration<collect results>", {
638 'currentValues':MochiKit.Base.method(this, 'getValue', ''),
639 'originalValues':MochiKit.Base.method(this, 'originalConfiguration'),
640 'inputs': MochiKit.Base.method(this, 'inputs')
641 }, {trace:false}),
642 MochiKit.Base.bind(function (someValues) {
643 var availableBindingValues;
644 var inputRequiringBindingValues;
645 var newBindingValues;
646
647 if (MochiKit.Base.isUndefinedOrNull(someValues['originalValues']) || MochiKit.Base.isUndefinedOrNull(someValues['originalValues']['bindingData'])) {
648 availableBindingValues = {};
649 } else {
650 availableBindingValues = Clipperz.Base.deepClone(someValues['originalValues']['bindingData'])
651 }
652
653 if (someValues['currentValues'] != null) {
654 MochiKit.Base.update(availableBindingValues, someValues['currentValues']['bindingData']);
655 }
656
657 this._bindings = {};
658 newBindingValues = {}
659 MochiKit.Iter.forEach(MochiKit.Base.filter(MochiKit.Base.methodcaller('needsBinding'), MochiKit.Base.values(someValues['inputs'])), MochiKit.Base.bind(function (anInput) {
660 varnewBinding;
661
662 newBindingValues[anInput.name()] = availableBindingValues[anInput.name()];
663 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(this, {
664 'key': anInput.name(),
665 'field':availableBindingValues[anInput.name()]
666 });
667
668 this._bindings[anInput.name()] = newBinding;
669 }, this))
670
671 return newBindingValues;
672
673/*
674 this._bindings = {};
675
676 if (someValues['currentValues'] != null) {
677 if (someValues['currentValues']['bindingData'] != null) {
678 var bindingKey;
679
680 for (bindingKey in someValues['currentValues']['bindingData']) {
681 var newBinding;
682
683 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(this, {
684 'key': bindingKey,
685 'field':someValues['currentValues']['bindingData'][bindingKey]
686 });
687 this._bindings[newBinding.key()] = newBinding;
688 }
689 } else if (someValues['currentValues']['legacyBindingData'] == null) {
690 var bindingKey;
691
692 for (bindingKey in someValues['currentValues']['legacyBindingData']) {
693 var newBinding;
694
695 newBinding = new Clipperz.PM.DataModel.DirectLoginBinding(this, {
696 'key': bindingKey,
697 'field':someValues['currentValues']['legacyBindingData'][bindingKey]
698 });
699 this._bindings[newBinding.key()] = newBinding;
700 }
701 } else {
702 WTF = TODO;
703 }
704 }
705
706 return this._bindings;
707*/
708 }, this),
709 MochiKit.Base.method(this, 'setValue', 'bindingData')
710 ], {trace:false});
711 },
712
713 //=========================================================================
714
715 'formValues': function () {
716 return Clipperz.Async.callbacks("DirectLogin.formValues", [
717 Clipperz.Async.deferredIf("this._formValues is defined", [
718 ], [
719 MochiKit.Base.method(this, 'updateFormValuesAfterChangingBookmarkletConfiguration'),
720 MochiKit.Base.bind(function () { return this._formValues;}, this)
721 ])
722 ], {trace:false}, this._formValues);
723 },
724
725 //-------------------------------------------------------------------------
726
727 'updateFormValuesAfterChangingBookmarkletConfiguration': function () {
728 return Clipperz.Async.callbacks("DirectLogin.updateFormValuesAfterChangingBookmarkletConfiguration", [
729 Clipperz.Async.collectResults("DirectLogin.updateFormValuesAfterChangingBookmarkletConfiguration <collect results>", {
730 'currentValues':MochiKit.Base.method(this, 'getValue', ''),
731 'originalValues':MochiKit.Base.method(this, 'originalConfiguration'),
732 'inputs': MochiKit.Base.method(this, 'inputs')
733 }, {trace:false}),
734 MochiKit.Base.bind(function (someValues) {
735 var availableFormValues;
736 var inputRequiringFormValues;
737 var newFormValues;
738
739 if (MochiKit.Base.isUndefinedOrNull(someValues['originalValues']) || MochiKit.Base.isUndefinedOrNull(someValues['originalValues']['formValues'])) {
740 availableFormValues = {};
741 } else {
742 availableFormValues = Clipperz.Base.deepClone(someValues['originalValues']['formValues'])
743 }
744
745 MochiKit.Base.update(availableFormValues, someValues['currentValues']['formValues']);
746
747 this._formValues = {};
748 newFormValues = {};
749 MochiKit.Iter.forEach(MochiKit.Base.filter(MochiKit.Base.methodcaller('needsFormValue'), MochiKit.Base.values(someValues['inputs'])), MochiKit.Base.bind(function (anInput) {
750 varnewFormValue;
751 var fieldOptions;
752
753 fieldOptions = {
754 'type': anInput.type(),
755 'options':anInput.options()
756 };
757
758 newFormValues[anInput.name()] = availableFormValues[anInput.name()]
759 newFormValue = new Clipperz.PM.DataModel.DirectLoginFormValue(this, {
760 'key': anInput.name(),
761 'fieldOptions':fieldOptions,
762 'value': availableFormValues[anInput.name()]
763 });
764
765 this._formValues[anInput.name()] = newFormValue;
766 }, this))
767
768 return newFormValues;
769 }, this),
770 MochiKit.Base.method(this, 'setValue', 'formValues')
771 ], {trace:false});
772 },
773
774 //=========================================================================
775
776 'retrieveIndexDataFunction': function () {
777 return this._retrieveIndexDataFunction;
778 },
779
780 'getIndexDataForKey': function (aKey) {
781 return Clipperz.Async.callbacks("DirectLogin.getIndexDataForKey", [
782 MochiKit.Base.partial(this.retrieveIndexDataFunction(), this.reference()),
783 Clipperz.Async.deferredIf("DirectLogin.getIndexDataForKey - index data not null", [
784 MochiKit.Base.itemgetter(aKey)
785 ],[
786 MochiKit.Async.succeed
787 ])
788 ], {trace:false});
789 },
790
791 //-------------------------------------------------------------------------
792
793 'setIndexDataForKey': function (aKey, aValue) {
794 return Clipperz.Async.callbacks("DirectLogin.setValueForKey", [
795 MochiKit.Base.method(this, 'getIndexDataForKey', aKey),
796 MochiKit.Base.bind(function (anActualValue) {
797 var transientStateKey;
798
799 transientStateKey = 'original_' + aKey;
800 if (MochiKit.Base.isUndefinedOrNull(this.transientState()[transientStateKey])) {
801 if (anActualValue != aValue) {
802 this.transientState()[transientStateKey] = anActualValue;
803 }
804 } else if (this.transientState()[transientStateKey] == aValue) {
805 this.transientState()[transientStateKey] = null;
806 }
807 }, this),
808 MochiKit.Base.partial(this._setIndexDataFunction, this.reference(), aKey, aValue)
809 ], {trace:false})
810 },
811
812 //-------------------------------------------------------------------------
813/*
814 'setValueForKey': function (aKey, aValue) {
815 return Clipperz.Async.callbacks("DirectLogin.setValueForKey", [
816 MochiKit.Base.method(this, 'getIndexDataForKey', aKey),
817 MochiKit.Base.bind(function (anActualValue) {
818 var transientStateKey;
819
820 transientStateKey = 'original_' + aKey;
821 if (MochiKit.Base.isUndefinedOrNull(this.transientState()[transientStateKey])) {
822 if (anActualValue != aValue) {
823 this.transientState()[transientStateKey] = anActualValue;
824 }
825 } else if (this.transientState()[transientStateKey] == aValue) {
826 this.transientState()[transientStateKey] = null;
827 }
828 }, this),
829 MochiKit.Base.method(this, 'setIndexDataForKey', aKey, aValue)
830 ], {trace:false})
831 },
832*/
833 //=========================================================================
834/*
835 'storedConfiguration': function () {
836 return this.record().getValue('directLogins' + '.' + this.reference());
837 },
838
839 //'setStoredConfiguration': function (aValue) {
840 // return this.record().setValue('directLogins' + '.' + this.reference(), aValue);
841 //},
842*/
843 //=========================================================================
844
845 'hasPendingChanges': function () {
846 varresult;
847 var deferredResult;
848
849 result = false;
850 result = result || this.isBrandNew();
851 result = result || (! MochiKit.Base.isUndefinedOrNull(this.transientState()['original_label']));
852 result = result || (! MochiKit.Base.isUndefinedOrNull(this.transientState()['original_favicon']));
853
854 if ((result == false) && (this.originalConfiguration() != null)) {
855 deferredResult = Clipperz.Async.callbacks("DirectLogin.hasPendingChanges", [
856 MochiKit.Base.method(this, 'serializedData'),
857 MochiKit.Base.bind(function (aCurrentConfiguration) {
858 varoriginalConfiguration;
859 var currentConfiguration;
860 var result;
861
862 originalConfiguration = this.originalConfiguration();
863 currentConfiguration = aCurrentConfiguration;
864
865 result = false;
866 result = result || (MochiKit.Base.compare(originalConfiguration['bookmarkletVersion'], currentConfiguration['bookmarkletVersion'])!= 0);
867 result = result || (MochiKit.Base.compare(originalConfiguration['formData'], currentConfiguration['formData']) != 0);
868 result = result || (MochiKit.Base.compare(originalConfiguration['formValues'], currentConfiguration['formValues']) != 0);
869 result = result || (MochiKit.Base.compare(originalConfiguration['bindingData'], currentConfiguration['bindingData']) != 0);
870
871 return result;
872 }, this)
873 ], {trace:false});
874 } else {
875 deferredResult = MochiKit.Async.succeed(result);
876 }
877
878 return deferredResult;
879 },
880
881 //-------------------------------------------------------------------------
882
883 'revertChanges': function () {
884 var deferredResult;
885
886 if (this.transientState()['original_label'] != null) {
887 this.setLabel(this.transientState()['original_label']);
888 }
889
890 if (this.transientState()['original_favicon'] != null) {
891 this.setFavicon(this.transientState()['original_favicon']);
892 }
893
894 if (this.originalConfiguration() != null) {
895 deferredResult = this.setValue('', this.originalConfiguration());
896 } else {
897 deferredResult = MochiKit.Async.succeed();
898 }
899
900 this._inputs = null;
901 this._bindings = null;
902 this._formValues= null;
903
904 this.resetTransientState(false);
905
906/*
907 if (this.hasInitiatedObjectDataStore()) {
908 deferredResult = Clipperz.Async.callbacks("DirectLogin.revertChanges", [
909 // MochiKit.Base.method(this.record(), 'setValue', 'directLogins' + '.' + this.reference(), this.originalState()),
910 MochiKit.Base.method(this, 'setValue', '', this.originalState()),
911 MochiKit.Base.method(this, 'resetObjectDataStore')
912 ], {trace:false})
913 } else {
914 deferredResult = MochiKit.Async.succeed();
915 }
916*/
917 return deferredResult;
918 },
919
920
921 //=========================================================================
922
923 'transientState': function () {
924 if (this._transientState == null) {
925 this._transientState = {}
926 }
927
928 return this._transientState;
929 },
930
931 'resetTransientState': function (isCommitting) {
932 this._transientState = null;
933 },
934
935 'commitTransientState': function (isCommitting) {
936 this._transientState = null;
937 this._isBrandNew = false;
938 },
939
940 //-------------------------------------------------------------------------
941
942 'originalConfiguration': function () {
943 return this.transientState()['original_configuration'];
944 },
945
946 'setOriginalConfiguration': function (aConfiguration) {
947 this.transientState()['original_configuration'] = Clipperz.Base.deepClone(aConfiguration);
948 },
949
950 //=========================================================================
951
952 'actualKey': function (aValueKey) {
953 var actualKey;
954
955 actualKey = 'directLogins' + '.' + this.reference();
956 if (aValueKey != '') {
957 actualKey = actualKey + '.' + aValueKey;
958 }
959
960 return actualKey;
961 },
962
963 //-------------------------------------------------------------------------
964
965 'getValue': function (aValueKey) {
966 return this.record().getValue(this.actualKey(aValueKey));
967 },
968
969 'setValue': function (aValueKey, aValue) {
970 // return this.record().setValue(this.actualKey(aValueKey), aValue);
971
972 return Clipperz.Async.callbacks("DirectLogin.setValue", [
973 MochiKit.Base.method(this, 'getValue', ''),
974 MochiKit.Base.bind(function (aValue) {
975 if (this.originalConfiguration() == null) {
976 this.setOriginalConfiguration(aValue);
977 }
978 }, this),
979 // MochiKit.Base.method(this, 'originalConfiguration'),
980 // Clipperz.Async.deferredIf("originalConfiguration has been set", [
981 // ], [
982 // MochiKit.Base.method(this, 'getValue', ''),
983 // MochiKit.Base.method(this, 'setOriginalConfiguration')
984 // ]),
985 MochiKit.Base.method(this.record(), 'setValue', this.actualKey(aValueKey), aValue)
986 ], {trace:false});
987 },
988
989 'removeValue': function (aValueKey) {
990 // return this.record().removeValue(this.actualKey(aValueKey));
991
992 return Clipperz.Async.callbacks("DirectLogin.setValue", [
993 MochiKit.Base.method(this, 'originalConfiguration'),
994 Clipperz.Async.deferredIf("originalConfiguration has been set", [
995 ], [
996 MochiKit.Base.method(this, 'getValue', ''),
997 MochiKit.Base.method(this, 'setOriginalConfiguration')
998 ]),
999 MochiKit.Base.method(this.record(), 'removeValue', this.actualKey(aValueKey))
1000 ], {trace:false});
1001 },
1002
1003 //=========================================================================
1004
1005 'content': function () {
1006 // return this.serializedData();
1007 // return MochiKit.Async.succeed(this);
1008
1009 var deferredResult;
1010 varfieldValues;
1011
1012 fieldValues = {};
1013 deferredResult = new Clipperz.Async.Deferred("DirectLogin.content", {trace:false});
1014 deferredResult.addMethod(this, 'reference');
1015 deferredResult.addCallback(function (aValue) { fieldValues['reference'] = aValue; });
1016 deferredResult.addMethod(this, 'label');
1017 deferredResult.addCallback(function (aValue) { fieldValues['label'] = aValue; });
1018 deferredResult.addMethod(this, 'favicon');
1019 deferredResult.addCallback(function (aValue) { fieldValues['favicon'] = aValue; });
1020 deferredResult.addCallback(function () { return fieldValues; });
1021 deferredResult.callback();
1022
1023 return deferredResult;
1024 },
1025
1026 //=========================================================================
1027
1028 'deleteAllCleanTextData': function () {
1029 this._inputs = null;
1030 this._bindings = null;
1031 this._formValues = null;
1032
1033 this.resetTransientState();
1034 },
1035
1036 //-------------------------------------------------------------------------
1037
1038 'hasAnyCleanTextData': function () {
1039 var result;
1040
1041 result = false;
1042
1043 result = result || (this._inputs != null);
1044 result = result || (this._bindings != null);
1045 result = result || (this._formValues != null);
1046 result = result || (MochiKit.Base.keys(this.transientState()).length != 0);
1047
1048 return MochiKit.Async.succeed(result);
1049 },
1050
1051 //=========================================================================
1052 __syntaxFix__: "syntax fix"
1053});
1054
1055//#############################################################################
1056
1057Clipperz.PM.DataModel.DirectLogin.exception = {
1058 'WrongBookmarkletConfiguration': new MochiKit.Base.NamedError("Clipperz.PM.DataModel.DirectLogin.exception.WrongBookmarkletConfiguration")
1059};
1060
1061Clipperz.PM.DataModel.DirectLogin.checkBookmarkletConfiguration = function(aConfiguration) {
1062 var configuration;
1063
1064 try {
1065 configuration = Clipperz.Base.evalJSON(aConfiguration);
1066 // configuration = Clipperz.PM.BookmarkletProcessor.sanitizeBookmarkletConfiguration(configuration);
1067
1068 if (MochiKit.Base.isUndefinedOrNull(configuration['page']['title'])
1069 ||MochiKit.Base.isUndefinedOrNull(configuration['form']['attributes']['action'])
1070 // ||MochiKit.Base.isUndefinedOrNull(configuration['form']['attributes']['method'])
1071 ||MochiKit.Base.isUndefinedOrNull(configuration['form']['inputs'])
1072 ||MochiKit.Base.isUndefinedOrNull(configuration['version'])
1073 ) {
1074 throw Clipperz.PM.DataModel.DirectLogin.exception.WrongBookmarkletConfiguration;
1075 }
1076
1077 // if (MochiKit.Base.isUndefinedOrNull(configuration['favicon'])) {
1078 // throw Clipperz.PM.DataModel.DirectLogin.exception.WrongBookmarkletConfiguration;
1079 // }
1080
1081 } catch (exception) {
1082 throw exception;
1083 }
1084
1085 return configuration;
1086};
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginBinding.js b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginBinding.js
new file mode 100644
index 0000000..a8ebb97
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginBinding.js
@@ -0,0 +1,120 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29//#############################################################################
30
31Clipperz.PM.DataModel.DirectLoginBinding = function(aDirectLogin, args) {
32 args = args || {};
33
34 this._directLogin = aDirectLogin|| Clipperz.Base.exception.raise('MandatoryParameter');
35
36 this._key = args.key|| Clipperz.Base.exception.raise('MandatoryParameter');
37 this._fieldKey = args.field || /* this.directLogin().fieldWithName(args.fieldName).reference() || */null;
38
39 return this;
40}
41
42Clipperz.PM.DataModel.DirectLoginBinding.prototype = MochiKit.Base.update(null, {
43
44 'toString': function() {
45 return "DirectLoginBinding (" + this.key() + ", " + this.fieldKey() + ")";
46 },
47
48 //-------------------------------------------------------------------------
49
50 'directLogin': function () {
51 return this._directLogin;
52 },
53
54 //-------------------------------------------------------------------------
55
56 'key': function() {
57 return this._key;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'fieldKey': function() {
63 return this._fieldKey;
64 },
65
66 'setFieldKey': function(aValue) {
67 this._fieldKey = aValue;
68
69 return this.directLogin().setValue('bindingData' + '.' + this.key(), aValue);
70 },
71
72 //'fieldName': function() {
73 // return this._fieldName;
74 //},
75
76 //-------------------------------------------------------------------------
77
78 'field': function() {
79 var deferredResult;
80
81 if (this.fieldKey() != null) {
82 deferredResult = Clipperz.Async.callbacks("DirectLoginBinding.field [1]", [
83 MochiKit.Base.method(this.directLogin().record(), 'fields'),
84 MochiKit.Base.itemgetter(this.fieldKey())
85 ], {trace:false});
86 // } else if (this.fieldName() != null) {
87 // WTF = TODO;
88 // result = this.directLogin().record().fieldWithName(this.fieldName());
89 //
90 // this.setFieldKey(result.key());
91 } else {
92 deferredResult = MochiKit.Async.succeed(null);
93 }
94
95 return deferredResult;
96 },
97
98 'setField': function (aField) {
99 this.setFieldKey(aField.reference());
100 },
101
102 //-------------------------------------------------------------------------
103/*
104 'fieldValue': function () {
105 return Clipperz.Async.callbacks("DirectLoginBinding.fieldValue", [
106 MochiKit.Base.method('field'),
107 MochiKit.Base.methodcaller('value')
108 ], {trace:false});
109 },
110*/
111 //-------------------------------------------------------------------------
112
113 'serializedData': function() {
114 return this.fieldKey();
115 },
116
117 //-------------------------------------------------------------------------
118 __syntaxFix__: "syntax fix"
119});
120
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginFormValue.js b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginFormValue.js
new file mode 100644
index 0000000..2429f88
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginFormValue.js
@@ -0,0 +1,101 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29//#############################################################################
30
31Clipperz.PM.DataModel.DirectLoginFormValue = function(aDirectLogin, args) {
32 args = args || {};
33
34 this._directLogin = aDirectLogin|| Clipperz.Base.exception.raise('MandatoryParameter');
35
36 this._key = args.key || Clipperz.Base.exception.raise('MandatoryParameter');
37 this._fieldOptions = args.fieldOptions|| Clipperz.Base.exception.raise('MandatoryParameter');
38 this._value = args.value || null;
39
40 return this;
41}
42
43Clipperz.PM.DataModel.DirectLoginFormValue.prototype = MochiKit.Base.update(null, {
44
45 'toString': function() {
46 return "DirectLoginFormValue (" + this.key() + ", " + this.value() + ")";
47 },
48
49 //-------------------------------------------------------------------------
50
51 'directLogin': function () {
52 return this._directLogin;
53 },
54
55 //-------------------------------------------------------------------------
56
57 'key': function() {
58 return this._key;
59 },
60
61 //-------------------------------------------------------------------------
62
63 'fieldOptions': function() {
64 return this._fieldOptions;
65 },
66
67 //-------------------------------------------------------------------------
68
69 'type': function () {
70 return this.fieldOptions()['type'];
71 },
72
73 //-------------------------------------------------------------------------
74
75 'value': function() {
76 varresult;
77
78 result = this._value;
79
80 // if ((result == null) && (this.type() == 'checkbox')) {
81 // result = false;
82 // };
83
84 return result;
85 },
86
87 'setValue': function (aValue) {
88 this._value = aValue;
89 return this.directLogin().setValue('formValues' + '.' + this.key(), aValue);
90 },
91
92 //-------------------------------------------------------------------------
93/*
94 'serializedData': function() {
95 return this.value();
96 },
97*/
98 //-------------------------------------------------------------------------
99 __syntaxFix__: "syntax fix"
100});
101
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginInput.js b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginInput.js
new file mode 100644
index 0000000..d9995fc
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DirectLoginInput.js
@@ -0,0 +1,192 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28//#############################################################################
29
30Clipperz.PM.DataModel.DirectLoginInput = function(args) {
31 this._args = args;
32
33 return this;
34}
35
36Clipperz.PM.DataModel.DirectLoginInput.prototype = MochiKit.Base.update(null, {
37
38 'args': function() {
39 return this._args;
40 },
41
42 //-------------------------------------------------------------------------
43
44 'name': function() {
45 return this.args()['name'];
46 },
47
48 //-------------------------------------------------------------------------
49
50 'type': function() {
51 var result;
52
53 result = this.args()['type'];
54
55 if (result != null) {
56 result = result.toLowerCase();
57 }
58 return result;
59 },
60
61 //-------------------------------------------------------------------------
62
63 'options': function() {
64 return this.args()['options'];
65 },
66
67 //-------------------------------------------------------------------------
68
69 'value': function() {
70 return this.args()['value'];
71 },
72
73 //-------------------------------------------------------------------------
74 /*
75 'formConfiguration': function(someFormValues, someBindings, someFields) {
76 var result;
77
78 if (this.shouldSetValue()) {
79 switch (this.type()) {
80 case 'select':
81 var currentValue;
82 var options;
83
84 // currentValue = this.directLogin()._configuration['formValues'][this.name()];
85 currentValue = someFormValues[this.name()];
86 options = this.args()['options'];
87
88 result = MochiKit.DOM.SELECT({name:this.name()},
89 MochiKit.Base.map(function(anOption) {
90 var options;
91
92 options = {value:anOption['value']};
93 if (currentValue == anOption['value']) {
94 options.selected = true;
95 }
96
97 return MochiKit.DOM.OPTION(options, anOption['label'])
98 }, options)
99 )
100 break;
101 case 'checkbox':
102 var options;
103
104 options = {type:'checkbox', name: this.name()};
105 // if (this.directLogin()._configuration['formValues'][this.name()] == true) {
106 if (someFormValues[this.name()] == true) {
107 options['checked'] = true;
108 };
109
110 result = MochiKit.DOM.INPUT(options, null);
111 break;
112 case 'radio':
113 var currentName;
114 var currentValue;
115 var options;
116
117 currentName = this.name();
118 // currentValue = this.directLogin()._configuration['formValues'][this.name()];
119 currentValue = someFormValues[this.name()];
120 options = this.args()['options'];
121
122 result = MochiKit.DOM.DIV(null,
123 MochiKit.Base.map(function(anOption) {
124 var options;
125 var isChecked;
126 var inputNode;
127 var divNode;
128
129 options = {type:'radio', name:currentName, value:anOption['value']}
130 isChecked = (currentValue == anOption['value']);
131 if (isChecked) {
132 options.checked = true;
133 }
134
135 if (Clipperz_IEisBroken == true) {
136 var checkedValue;
137
138 checkedValue = (isChecked ? " CHECKED" : "");
139 inputNode = MochiKit.DOM.currentDocument().createElement("<INPUT TYPE='RADIO' NAME='" + currentName + "' VALUE='" + anOption['value'] + "'" + checkedValue + ">");
140 } else {
141 inputNode = MochiKit.DOM.INPUT(options, anOption['value']);
142 }
143 divNode = MochiKit.DOM.DIV(null, inputNode);
144
145 return divNode;
146 }, options)
147 );
148 break;
149 }
150 } else {
151 var binding;
152 // binding = this.directLogin().bindings()[this.name()];
153 binding = someBindings[this.name()];
154
155 result = MochiKit.DOM.INPUT({
156 type:((this.type() != 'password') ? this.type() : 'text'),
157 name:this.name(),
158 // value:((binding != null)? binding.field().value() : this.value())
159 value:((binding != null)? someFields[binding.fieldKey()]['value'] : this.value())
160 // value:((binding != null)? someFields[binding.fieldKey()].value() : this.value())
161 }, null);
162 }
163
164 return result;
165 },
166 */
167 //-------------------------------------------------------------------------
168
169 'needsFormValue': function() {
170 var type;
171 var result;
172
173 type = this.type();
174 result = ((type == 'checkbox') || (type == 'radio') || (type == 'select'));
175
176 return result;
177 },
178
179 'needsBinding': function() {
180 var type;
181 var result;
182
183 type = this.type();
184 result = ((type == 'text') || (type == 'password'));
185
186 return result;
187 },
188
189 //-------------------------------------------------------------------------
190 __syntaxFix__: "syntax fix"
191});
192
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js b/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js
new file mode 100644
index 0000000..1aa7a52
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js
@@ -0,0 +1,542 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.KeyValueObjectStore) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.EncryptedRemoteObject depends on Clipperz.KeyValueObjectStore!";
26}
27
28if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
29if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
30
31Clipperz.PM.DataModel.EncryptedRemoteObject = function(args) {
32 args = args || {};
33
34 this._name = args.name || null;
35 this._reference = args.reference || Clipperz.PM.Crypto.randomKey();
36 this._isBrandNew = ((args.reference == null) && (args.remoteData == null));
37
38 if ((this._isBrandNew == false) && (args['retrieveKeyFunction'] == null)) {
39 Clipperz.Base.exception.raise('MandatoryParameter');
40 } else {
41 this._retrieveKeyFunction = args['retrieveKeyFunction'];
42 }
43
44 this._retrieveRemoteDataFunction = args.retrieveRemoteDataFunction|| null;
45 this._remoteData = args.remoteData || null;
46 // this._remoteData = args.remoteData ? Clipperz.Base.deepClone(args.remoteData) : null;
47 if ((!this._isBrandNew) && ((this._retrieveRemoteDataFunction == null) && (this._remoteData == null))) {
48 Clipperz.Base.exception.raise('MandatoryParameter');
49 }
50
51
52 this._encryptedDataKeypath = args.encryptedDataKeypath || 'data'; //Clipperz.Base.exception.raise('MandatoryParameter');
53 this._encryptedVersionKeypath = args.encryptedVersionKeypath || 'version';//Clipperz.Base.exception.raise('MandatoryParameter');
54
55
56 this._transientState = null;
57 this._deferredLocks = {};
58
59 if (this._isBrandNew == true) {
60 this._objectDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.objectDataStore [1]'}*/);
61 } else {
62 this._objectDataStore = null;
63 }
64
65 return this;
66}
67
68//
69 // Basic data workflow
70 //=======================
71//
72 //getRemoteData
73 // unpackRemoteData
74 // getDecryptData [encryptedDataKeypath, encryptedVersionKeypath]
75 // unpackData
76 //
77 //
78 // ?? packData
79 // ?? encryptDataWithKey
80 // ??packRemoteData [encryptedDataKeypath (?), encryptedVersionKeypath (?)]
81//
82
83Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(null, {
84
85 'toString': function () {
86 return "Clipperz.PM.DataModel.EncryptedRemoteObject" + (this.name() != null ? " - " + this.name() : "");
87 },
88
89 //-------------------------------------------------------------------------
90
91 'name': function () {
92 return this._name;
93 },
94
95 //-------------------------------------------------------------------------
96
97 'reference': function () {
98 return this._reference;
99 },
100
101 'setReference': function (aValue) {
102 this._reference = aValue;
103
104 return this._reference;
105 },
106
107 //-------------------------------------------------------------------------
108
109 'transientState': function () {
110 if (this._transientState == null) {
111 this._transientState = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.transientState [2]'}*/);
112 }
113
114 return this._transientState;
115 },
116
117 'resetTransientState': function (isCommitting) {
118 if (this._transientState != null) {
119 this._transientState.removeAllData();
120 }
121
122 this._transientState = null;
123 },
124
125 //-------------------------------------------------------------------------
126
127 'isBrandNew': function () {
128 return this._isBrandNew;
129 },
130
131 //-------------------------------------------------------------------------
132
133 'getKey': function () {
134 var deferredResult;
135 var deferredLock;
136
137 deferredLock = this.getDeferredLockForKey('key');
138
139 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.getKey", {trace:false});
140 deferredResult.acquireLock(deferredLock);
141 deferredResult.addMethod(
142 this.decryptedDataStore(),
143 'deferredGetOrSet',
144 'decryptionKey',
145 MochiKit.Base.partial(this.retrieveKeyFunction(), this.reference())
146 );
147 deferredResult.releaseLock(deferredLock);
148 deferredResult.callback();
149
150 return deferredResult;
151 },
152
153 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
154
155 'retrieveKeyFunction': function () {
156 return this._retrieveKeyFunction;
157 },
158
159 'setRetrieveKeyFunction': function (aFunction) {
160 this._retrieveKeyFunction = aFunction;
161 },
162
163 //-------------------------------------------------------------------------
164
165 'hasLoadedRemoteData': function () {
166 return (this._remoteData != null);
167 },
168
169 'getRemoteData': function () {
170 var deferredResult;
171 vardeferredLock;
172
173 deferredLock = this.getDeferredLockForKey('remoteData');
174
175 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObjects.getRemoteData", {trace:false});
176 deferredResult.acquireLock(deferredLock);
177 deferredResult.addCallback(MochiKit.Base.bind(function () {
178 var innerDeferredResult;
179
180 if (this._remoteData != null) {
181 innerDeferredResult = MochiKit.Async.succeed(this._remoteData);
182 } else {
183 innerDeferredResult = Clipperz.Async.callbacks("EncryptedRemoteObjects.getRemoteData <inner deferred>", [
184 MochiKit.Base.partial(this.retrieveRemoteDataFunction(), this.reference()),
185 MochiKit.Base.method(this, 'unpackRemoteData'),
186 MochiKit.Base.bind(function (someData) {
187 this._remoteData = someData;
188 return this._remoteData;
189 }, this)
190 ], {trace:false});
191 }
192
193 return innerDeferredResult;
194 }, this))
195 deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
196 deferredResult.releaseLock(deferredLock);
197
198 deferredResult.callback();
199
200 return deferredResult;
201 },
202
203 //-------------------------------------------------------------------------
204
205 'unpackRemoteData': function (someData) {
206 return MochiKit.Async.succeed(someData);
207 },
208
209 //.........................................................................
210
211 'packRemoteData': function (someData) {
212 var result;
213
214 result = {
215 'reference':this.reference(),
216 'data': someData,
217 'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion
218 };
219
220 return MochiKit.Async.succeed(result);
221 },
222
223 //-------------------------------------------------------------------------
224
225 'retrieveRemoteDataFunction': function () {
226 return this._retrieveRemoteDataFunction;
227 },
228
229 'setRetrieveRemoteDataFunction': function (aFunction) {
230 this._retrieveRemoteDataFunction = aFunction;
231 },
232
233 //-------------------------------------------------------------------------
234
235 'decryptedDataStore': function () {
236 if (this._decryptedDataStore == null) {
237 this._decryptedDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.decryptedDataStore [3]'}*/);
238 };
239
240 return this._decryptedDataStore;
241 },
242
243 //.........................................................................
244
245 'getDecryptedData': function () {
246 var deferredResult;
247 var deferredLock;
248
249 deferredLock = this.getDeferredLockForKey('decryptedData');
250
251 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.getDecryptedData", {trace:false});
252 deferredResult.acquireLock(deferredLock);
253 deferredResult.addMethod(this, 'decryptedDataStore');
254 deferredResult.addCallback(MochiKit.Base.methodcaller('deferredGetOrSet', 'decryptedData', MochiKit.Base.bind(function () {
255 varinnerDeferredResult;
256
257 innerDeferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.getDecryptedData <inner deferred>", {trace:false});
258
259 innerDeferredResult.addMethod(this, 'getRemoteData');
260 innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
261 innerDeferredResult.collectResults({
262 'key': MochiKit.Base.method(this, 'getKey'),
263 'value':MochiKit.Base.itemgetter(this._encryptedDataKeypath),
264 'version':MochiKit.Base.itemgetter(this._encryptedVersionKeypath)
265 });
266
267 innerDeferredResult.addCallback(Clipperz.PM.Crypto.deferredDecrypt);
268 innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
269 innerDeferredResult.addMethod(this, 'unpackData');
270 innerDeferredResult.callback();
271
272 return innerDeferredResult;
273 }, this)));
274 deferredResult.releaseLock(deferredLock);
275 deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
276 deferredResult.callback();
277
278 return deferredResult;
279 },
280
281 //-------------------------------------------------------------------------
282
283 'setValue': function(aKey, aValue) {
284 var deferredResult;
285
286 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.setValue", {trace:false});
287 deferredResult.addMethod(this, '_getObjectDataStore');
288 deferredResult.addCallback(MochiKit.Base.methodcaller('setValue', aKey, aValue));
289 deferredResult.callback();
290
291 return deferredResult;
292 },
293
294 //.........................................................................
295
296 'getValue': function (aKey) {
297 return Clipperz.Async.callbacks("EncryptedRemoteObject.getValue", [
298 MochiKit.Base.method(this, '_getObjectDataStore'),
299 MochiKit.Base.methodcaller('getValue', aKey)
300 ], {trace:false});
301 },
302
303 //.........................................................................
304
305 'removeValue': function (aKey) {
306 return Clipperz.Async.callbacks("EncryptedRemoteObject.removeValue", [
307 MochiKit.Base.method(this, '_getObjectDataStore'),
308 MochiKit.Base.methodcaller('removeValue', aKey)
309 ], {trace:false});
310 },
311
312 //.........................................................................
313
314 'values': function () {
315 return Clipperz.Async.callbacks("EncryptedRemoteObject.values", [
316 MochiKit.Base.method(this, '_getObjectDataStore'),
317 MochiKit.Base.methodcaller('values')
318 ], {trace:false});
319 },
320
321 'setValues': function (someValues) {
322 return Clipperz.Async.callbacks("EncryptedRemoteObject.values", [
323 MochiKit.Base.method(this, '_getObjectDataStore'),
324 MochiKit.Base.methodcaller('setValues', someValues)
325 ], {trace:false});
326 },
327
328 //.........................................................................
329
330 '_getObjectDataStore': function () {
331 var deferredResult;
332 var deferredLock;
333
334 deferredLock = this.getDeferredLockForKey('objectDataStore');
335
336 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject._getObjectDataStore", {trace:false});
337 deferredResult.acquireLock(deferredLock);
338 deferredResult.addCallback(MochiKit.Base.bind(function () {
339 var innerDeferredResult;
340
341 if (this._objectDataStore == null) {
342 this._objectDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.objectDataStore [4]'}*/);
343
344 innerDeferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject._getObjectDataStore <inner deferred>", {trace:false});
345 innerDeferredResult.addMethod(this, 'getDecryptedData');
346 innerDeferredResult.addMethod(this._objectDataStore, 'initWithValues');
347 innerDeferredResult.callback();
348 } else {
349 innerDeferredResult = MochiKit.Async.succeed(this._objectDataStore);
350 }
351
352 return innerDeferredResult;
353 }, this));
354 deferredResult.releaseLock(deferredLock);
355 deferredResult.callback();
356
357 return deferredResult;
358 },
359
360 'hasInitiatedObjectDataStore': function () {
361 return (this._objectDataStore != null);
362 },
363
364 //-------------------------------------------------------------------------
365
366 'getDeferredLockForKey': function (aKey) {
367 var result;
368
369 result = this._deferredLocks[aKey];
370
371 if (typeof(result) == 'undefined') {
372 result = new MochiKit.Async.DeferredLock();
373 this._deferredLocks[aKey] = result;
374 }
375
376 return result;
377 },
378
379 //-------------------------------------------------------------------------
380
381 'unpackData': function (someData) { //++
382 return someData;
383 },
384
385 'packData': function (someData) { //++
386 return someData;
387 },
388
389 //-------------------------------------------------------------------------
390
391 'hasPendingChanges': function () {
392 var deferredResult;
393 var tempObj = this;
394
395 if (this.isBrandNew()) {
396 // deferredResult = MochiKit.Async.succeed(true);
397 deferredResult = this.hasPendingChangesWhenBrandNew();
398 } else if (this.hasInitiatedObjectDataStore()) {
399 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.hasPendingChanges", {trace:false});
400 deferredResult.collectResults({
401 'decryptedData': [
402 MochiKit.Base.method(this, 'getDecryptedData'),
403 Clipperz.Base.serializeJSON
404 ],
405 'objectData': [
406 MochiKit.Base.method(this, '_getObjectDataStore'),
407 MochiKit.Base.methodcaller('values'),
408 Clipperz.Base.serializeJSON
409 ]
410 });
411 deferredResult.addCallback(function (someValues) {
412 return (someValues['decryptedData'] != someValues['objectData']);
413 });
414 deferredResult.callback();
415 } else {
416 deferredResult = MochiKit.Async.succeed(false);
417 }
418
419 return deferredResult;
420 },
421
422 'hasPendingChangesWhenBrandNew': function () {
423 return MochiKit.Async.succeed(true);
424 },
425
426 //-------------------------------------------------------------------------
427
428 'commitTransientState': function () {
429 var deferredResult;
430
431 // if (this.transientState().getValue('__prepareRemoteData') == true) {
432 if (this.transientState().getValue('packedRemoteData') != null) {
433 deferredResult = Clipperz.Async.callbacks("EncryptedRemoteObject.commitTransientState - prepareRemoteData", [
434 MochiKit.Base.bind(function (someData) {
435 this._remoteData = this.transientState().getValue('packedRemoteData');
436 }, this),
437
438 MochiKit.Base.method(this, '_getObjectDataStore'),
439 MochiKit.Base.methodcaller('values'),
440 Clipperz.Base.deepClone,
441 MochiKit.Base.method(this.decryptedDataStore(), 'setValue', 'decryptedData'),
442
443 MochiKit.Base.method(this, 'resetTransientState', true)
444 ], {trace:false});
445
446 } else {
447 deferredResult = Clipperz.Async.callbacks("EncryptedRemoteObject.commitTransientState - NO prepareRemoteData", [
448 MochiKit.Base.method(this, 'resetTransientState', true)
449 ], {trace:false});
450 }
451
452 this._isBrandNew = false;
453
454 return deferredResult;
455 },
456
457 //-------------------------------------------------------------------------
458
459 'revertChanges': function () {
460 if (this.hasInitiatedObjectDataStore()) {
461 this._objectDataStore.removeAllData();
462 this._objectDataStore = null;
463 }
464 this.resetTransientState(false);
465
466 return MochiKit.Async.succeed();
467 },
468
469 //-------------------------------------------------------------------------
470
471 'deleteAllCleanTextData': function () {
472 var deferredResult;
473
474 deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.deleteAllCleanTextData", {trace:false});
475
476 deferredResult.addMethod(this, 'resetTransientState', false);
477
478 deferredResult.acquireLock(this.getDeferredLockForKey('decryptedData'));
479 deferredResult.addCallback(MochiKit.Base.bind(function () {
480 if (this._decryptedDataStore != null) {
481 this._decryptedDataStore.removeAllData();
482 }
483 }, this));
484 deferredResult.releaseLock(this.getDeferredLockForKey('decryptedData'));
485
486 deferredResult.acquireLock(this.getDeferredLockForKey('objectDataStore'));
487 deferredResult.addCallback(MochiKit.Base.bind(function () {
488 if (this._objectDataStore != null) {
489 this._objectDataStore.removeAllData();
490 this._objectDataStore = null;
491 }
492 }, this));
493 deferredResult.releaseLock(this.getDeferredLockForKey('objectDataStore'));
494
495 deferredResult.callback();
496
497 return deferredResult;
498 },
499
500 //.........................................................................
501
502 'hasAnyCleanTextData': function () {
503 var result;
504
505 result = false;
506
507 result = result || (! this.decryptedDataStore().isEmpty());
508 result = result || (! this.transientState().isEmpty());
509 if (this.hasInitiatedObjectDataStore()) {
510 result = result || (! this._objectDataStore.isEmpty());
511 }
512
513 return MochiKit.Async.succeed(result);
514 },
515
516 //-------------------------------------------------------------------------
517
518 'prepareRemoteDataWithKey': function (aKey) {
519 return Clipperz.Async.callbacks("EncryptedRemoteObject.prepareRemoteDataWithKey", [
520 // MochiKit.Base.method(this.transientState(), 'setValue', '__prepareRemoteData', true),
521 MochiKit.Base.method(this, '_getObjectDataStore'),
522 MochiKit.Base.methodcaller('values'),
523 MochiKit.Base.method(this, 'packData'),
524 function (someData) {
525 return Clipperz.PM.Crypto.deferredEncrypt({
526 'key': aKey,
527 'value':someData,
528 'version':Clipperz.PM.Crypto.encryptingFunctions.currentVersion
529 })
530 },
531 MochiKit.Base.method(this, 'packRemoteData'),
532 MochiKit.Base.method(this.transientState(), 'setValue', 'packedRemoteData'),
533 function (someData) {
534 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'advanceProgress');
535 return someData;
536 }
537 ], {trace:false});
538 },
539
540 //-------------------------------------------------------------------------
541 __syntaxFix__: "syntax fix"
542});
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/OneTimePassword.js b/frontend/delta/js/Clipperz/PM/DataModel/OneTimePassword.js
new file mode 100644
index 0000000..fbca1ff
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/OneTimePassword.js
@@ -0,0 +1,350 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29//#############################################################################
30
31Clipperz.PM.DataModel.OneTimePassword = function(args) {
32 args = args || {};
33
34 //this._user = args['user'];
35 this._reference = args['reference']|| Clipperz.PM.Crypto.randomKey();
36 this._password = args['password'];
37 this._passwordValue = Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(args['password']);
38 this._creationDate = args['created'] ? Clipperz.PM.Date.parseDateWithUTCFormat(args['created']) : new Date();
39 this._usageDate = args['used'] ? Clipperz.PM.Date.parseDateWithUTCFormat(args['used']) : null;
40
41 this._status = args['status'] || 'ACTIVE'; //'REQUESTED', 'USED', 'DISABLED'
42 this._connectionInfo= null;
43
44 this._key = null;
45 this._keyChecksum= null;
46
47 return this;
48}
49
50Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
51
52 'toString': function() {
53 return "Clipperz.PM.DataModel.OneTimePassword";
54 },
55/*
56 //-------------------------------------------------------------------------
57
58 'user': function() {
59 return this._user;
60 },
61
62 //-------------------------------------------------------------------------
63
64 'password': function() {
65 return this._password;
66 },
67
68 //-------------------------------------------------------------------------
69
70 'passwordValue': function() {
71 return this._passwordValue;
72 },
73
74 //-------------------------------------------------------------------------
75
76 'creationDate': function() {
77 return this._creationDate;
78 },
79
80 //-------------------------------------------------------------------------
81
82 'reference': function() {
83 return this._reference;
84 },
85
86 //-------------------------------------------------------------------------
87
88 'key': function() {
89 if (this._key == null) {
90 this._key = Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(this.user().username(), this.passwordValue());
91 }
92
93 return this._key;
94 },
95
96 //-------------------------------------------------------------------------
97
98 'keyChecksum': function() {
99 if (this._keyChecksum == null) {
100 this._keyChecksum = Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(this.user().username(), this.passwordValue());
101 }
102
103 return this._keyChecksum;
104 },
105*/
106 //-------------------------------------------------------------------------
107
108 'status': function() {
109 return this._status;
110 },
111
112 'setStatus': function(aValue) {
113 this._status = aValue;
114 },
115
116 //-------------------------------------------------------------------------
117/*
118 'serializedData': function() {
119 var result;
120
121 result = {
122 'password': this.password(),
123 'created': this.creationDate() ? Clipperz.PM.Date.formatDateWithUTCFormat(this.creationDate()) : null,
124 'used': this.usageDate() ? Clipperz.PM.Date.formatDateWithUTCFormat(this.usageDate()) : null,
125 'status': this.status()
126 };
127
128 return result;
129 },
130
131 //-------------------------------------------------------------------------
132
133 'packedPassphrase': function() {
134 var result;
135 var packedPassphrase;
136 var encodedPassphrase;
137 varprefixPadding;
138 var suffixPadding;
139 var getRandomBytes;
140
141 getRandomBytes = MochiKit.Base.method(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'getRandomBytes');
142
143 encodedPassphrase = new Clipperz.ByteArray(this.user().passphrase()).toBase64String();
144//Clipperz.logDebug("--- encodedPassphrase.length: " + encodedPassphrase.length);
145 prefixPadding = getRandomBytes(getRandomBytes(1).byteAtIndex(0)).toBase64String();
146//Clipperz.logDebug("--- prefixPadding.length: " + prefixPadding.length);
147 suffixPadding = getRandomBytes((500 - prefixPadding.length - encodedPassphrase.length) * 6 / 8).toBase64String();
148//Clipperz.logDebug("--- suffixPadding.length: " + suffixPadding.length);
149//Clipperz.logDebug("--- total.length: " + (prefixPadding.length + encodedPassphrase.length + suffixPadding.length));
150
151 packedPassphrase = {
152 'prefix': prefixPadding,
153 'passphrase': encodedPassphrase,
154 'suffix': suffixPadding
155 };
156
157 // result = Clipperz.Base.serializeJSON(packedPassphrase);
158 result = packedPassphrase;
159//Clipperz.logDebug("===== OTP packedPassprase: [" + result.length + "]" + result);
160//Clipperz.logDebug("<<< OneTimePassword.packedPassphrase");
161
162 return result;
163 },
164
165 //-------------------------------------------------------------------------
166
167 'encryptedPackedPassphrase': function() {
168 return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(this.passwordValue(), this.packedPassphrase())
169 },
170
171 //-------------------------------------------------------------------------
172
173 'encryptedData': function() {
174 var deferredResult;
175 varresult;
176
177//Clipperz.logDebug(">>> OneTimePassword.encryptedData");
178//Clipperz.logDebug("--- OneTimePassword.encryptedData - id: " + this.reference());
179 result = {
180 'reference': this.reference(),
181 'key': this.key(),
182 'keyChecksum': this.keyChecksum(),
183 'data': "",
184 'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion
185 }
186//Clipperz.logDebug("--- OneTimePassword.encryptedData - 2: " + Clipperz.Base.serializeJSON(result));
187 deferredResult = new MochiKit.Async.Deferred();
188//Clipperz.logDebug("--- OneTimePassword.encryptedData - 3");
189//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 1: " + res); return res;});
190 //# deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion, this.passwordValue(), this.packedPassphrase());
191 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedPackedPassphrase'));
192//Clipperz.logDebug("--- OneTimePassword.encryptedData - 4");
193//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 2: [" + res.length + "]" + res); return res;});
194 deferredResult.addCallback(function(aResult, res) {
195 aResult['data'] = res;
196 return aResult;
197 }, result);
198//Clipperz.logDebug("--- OneTimePassword.encryptedData - 5");
199//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.encryptedData - 3: " + Clipperz.Base.serializeJSON(res)); return res;});
200 deferredResult.callback();
201//Clipperz.logDebug("--- OneTimePassword.encryptedData - 6");
202
203 return deferredResult;
204 },
205
206 //-------------------------------------------------------------------------
207
208 'saveChanges': function() {
209 var deferredResult;
210 varresult;
211
212//Clipperz.logDebug(">>> OneTimePassword.saveChanges");
213 result = {};
214 deferredResult = new MochiKit.Async.Deferred();
215
216 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptUserData');
217 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'encryptedData'));
218 deferredResult.addCallback(function(aResult, res) {
219 aResult['user'] = res;
220 return aResult;
221 }, result);
222
223 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptOTPData');
224 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedData'));
225 deferredResult.addCallback(function(aResult, res) {
226 aResult['oneTimePassword'] = res;
227 return aResult;
228 }, result);
229
230 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_sendingData');
231//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 1: " + Clipperz.Base.serializeJSON(res)); return res;});
232 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'addNewOneTimePassword');
233
234 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_updatingInterface');
235//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 2: " + res); return res;});
236 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'OTPUpdated');
237 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'oneTimePassword_saveChanges_done', null);
238//deferredResult.addBoth(function(res) {Clipperz.logDebug("OneTimePassword.saveChanges - 2: " + res); return res;});
239 deferredResult.callback();
240//Clipperz.logDebug("<<< OneTimePassword.saveChanges");
241
242 return deferredResult;
243 },
244
245 //-------------------------------------------------------------------------
246
247 'usageDate': function() {
248 return this._usageDate;
249 },
250
251 'setUsageDate': function(aValue) {
252 this._usageDate = aValue;
253 },
254
255 //-------------------------------------------------------------------------
256
257 'connectionInfo': function() {
258 return this._connectionInfo;
259 },
260
261 'setConnectionInfo': function(aValue) {
262 this._connectionInfo = aValue;
263 },
264
265 //-------------------------------------------------------------------------
266
267 'isExpired': function() {
268 return (this.usageDate() != null);
269 },
270
271 //-------------------------------------------------------------------------
272
273 'updateStatusWithValues': function(someValues) {
274 var result;
275
276 result = false;
277
278 if (someValues['status'] != this.status()) {
279 result = true;
280 }
281
282 this.setStatus(someValues['status']);
283 this.setUsageDate(Clipperz.PM.Date.parseDateWithUTCFormat(someValues['requestDate']));
284 this.setConnectionInfo(someValues['connection']);
285
286 return result;
287 },
288 */
289 //-------------------------------------------------------------------------
290 __syntaxFix__: "syntax fix"
291});
292
293//#############################################################################
294
295Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword = function(anUsername, aPassword) {
296 return Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aPassword)).toHexString().substring(2);
297}
298
299Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword = function(anUsername, aPassword) {
300 return Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(anUsername + aPassword)).toHexString().substring(2);
301}
302
303//=============================================================================
304
305Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue = function(aPassword) {
306 var result;
307
308 //"yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg"
309 if (aPassword.replace(/[\s\-]/g, '').length == 32) {
310 try {
311 var passwordByteArray;
312
313 passwordByteArray = new Clipperz.ByteArray();
314 passwordByteArray.appendBase32String(aPassword);
315
316 result = true;
317 } catch(exception) {
318 result = false;
319 }
320 } else {
321 result = false;
322 }
323
324 return result;
325}
326
327//=============================================================================
328
329Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword = function(aPassword) {
330 varresult;
331
332 if (aPassword.replace(/[\s\-]/g, '').length == 32) {
333 try {
334 var passwordByteArray;
335
336 passwordByteArray = new Clipperz.ByteArray();
337 passwordByteArray.appendBase32String(aPassword);
338
339 result = passwordByteArray.toBase64String();
340 } catch(exception) {
341 result = aPassword;
342 }
343 } else {
344 result = aPassword;
345 }
346
347 return result;
348}
349
350//#############################################################################
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.Field.js b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.Field.js
new file mode 100644
index 0000000..01e7196
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.Field.js
@@ -0,0 +1,186 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.DataModel.Record.Version) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.Record.Version.Field depends on Clipperz.PM.DataModel.Record.Version!";
26}
27
28Clipperz.PM.DataModel.Record.Version.Field = function(args) {
29 Clipperz.PM.DataModel.Record.Version.Field.superclass.constructor.apply(this, arguments);
30
31 this._recordVersion = args.recordVersion|| Clipperz.Base.exception.raise('MandatoryParameter');
32 this._reference = args.reference || Clipperz.PM.Crypto.randomKey();
33
34 return this;
35}
36
37
38Clipperz.Base.extend(Clipperz.PM.DataModel.Record.Version.Field, Object, {
39
40 'toString': function() {
41 return "Record.Version.Field (" + this.reference() + ")";
42 },
43
44 //-------------------------------------------------------------------------
45
46 'recordVersion': function () {
47 return this._recordVersion;
48 },
49
50 //-------------------------------------------------------------------------
51
52 'reference': function () {
53 return this._reference;
54 },
55
56 //-------------------------------------------------------------------------
57
58 'getItem': function (aKey) {
59 return Clipperz.Async.callbacks("Clipperz.PM.DataModel.Record.Version.Field.getItem", [
60 MochiKit.Base.method(this, 'recordVersion'),
61 MochiKit.Base.methodcaller('getValue', 'fields' + '.' + this.reference() + '.' + aKey)
62 ], {trace:false});
63 },
64
65 'setItem': function (aKey, aValue) {
66 return Clipperz.Async.callbacks("Clipperz.PM.DataModel.Record.Version.Field.getItem", [
67 MochiKit.Base.method(this, 'recordVersion'),
68 MochiKit.Base.methodcaller('setValue', 'fields' + '.' + this.reference() + '.' + aKey, aValue)
69 ], {trace:false});
70 },
71
72 //-------------------------------------------------------------------------
73
74 'label': function () {
75 return this.getItem('label');
76 },
77
78 'setLabel': function (aValue) {
79 return this.setItem('label', aValue);
80 },
81
82 //-------------------------------------------------------------------------
83
84 'value': function () {
85 return this.getItem('value');
86 },
87
88 'setValue': function (aValue) {
89 return this.setItem('value', aValue);
90 },
91
92 //-------------------------------------------------------------------------
93
94 'actionType': function () {
95 return Clipperz.Async.callbacks("Clipperz.PM.DataModel.Record.Version.Field.actionType", [
96 Clipperz.Async.collectResults("Clipperz.PM.DataModel.Record.Version.Field.actionType [collect results]", {
97 'isHidden':MochiKit.Base.method(this, 'isHidden'),
98 'value':MochiKit.Base.method(this, 'value')
99 }, {trace:false}),
100 function (someValues) {
101 var result; //'NONE', 'URL', 'EMAIL', 'PASSWORD'
102
103 result = 'NONE';
104
105 if (someValues['isHidden']) {
106 result = 'PASSWORD';
107 } else if (Clipperz.Base.isUrl(someValues['value'])) {
108 result = 'URL'
109 } else if (Clipperz.Base.isEmail(someValues['value'])) {
110 result = 'EMAIL'
111 };
112
113 return result;
114 }
115 ], {trace:false});
116 },
117
118 //-------------------------------------------------------------------------
119
120 'isHidden': function () {
121 return this.getItem('hidden');
122 },
123
124 'setIsHidden': function (aValue) {
125 return this.setItem('hidden', aValue);
126 },
127
128 //-------------------------------------------------------------------------
129
130 'isEmpty': function () {
131 var deferredResult;
132
133 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.Field.isEmpty", {trace:false});
134
135 deferredResult.collectResults({
136 'label': [
137 MochiKit.Base.method(this, 'label'),
138 MochiKit.Base.partial(MochiKit.Base.operator.eq, '')
139 ],
140 'value': [
141 MochiKit.Base.method(this, 'value'),
142 MochiKit.Base.partial(MochiKit.Base.operator.eq, '')
143 ],
144 'isHidden': [
145 MochiKit.Base.method(this, 'isHidden'),
146 MochiKit.Base.partial(MochiKit.Base.operator.eq, false)
147 ]
148 });
149 deferredResult.addCallback(MochiKit.Base.values);
150 deferredResult.addCallback(function(someValues) {
151 return MochiKit.Iter.every(someValues, MochiKit.Base.operator.identity);
152 });
153 deferredResult.callback();
154
155 return deferredResult;
156 },
157
158 //-------------------------------------------------------------------------
159
160 'content': function () {
161 var deferredResult;
162 varfieldValues;
163
164 fieldValues = {};
165 deferredResult = new Clipperz.Async.Deferred("Record.Version.Field.content", {trace:false});
166 deferredResult.addMethod(this, 'reference');
167 deferredResult.addCallback(function (aValue) { fieldValues['reference'] = aValue; });
168 deferredResult.addMethod(this, 'label');
169 deferredResult.addCallback(function (aValue) { fieldValues['label'] = aValue; });
170 deferredResult.addMethod(this, 'value');
171 deferredResult.addCallback(function (aValue) { fieldValues['value'] = aValue; });
172 deferredResult.addMethod(this, 'actionType');
173 deferredResult.addCallback(function (aValue) { fieldValues['actionType'] = aValue; });
174 deferredResult.addMethod(this, 'isHidden');
175 deferredResult.addCallback(function (aValue) { fieldValues['isHidden'] = aValue; });
176 deferredResult.addCallback(function () { return fieldValues; });
177 deferredResult.callback();
178
179 return deferredResult;
180 },
181
182 //-------------------------------------------------------------------------
183 __syntaxFix__: "syntax fix"
184});
185
186
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js
new file mode 100644
index 0000000..87b319c
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js
@@ -0,0 +1,328 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.DataModel.Record) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.Record.Version depends on Clipperz.PM.DataModel.Record!";
26}
27
28Clipperz.PM.DataModel.Record.Version = function(args) {
29 Clipperz.PM.DataModel.Record.Version.superclass.constructor.apply(this, arguments);
30
31 this._getVersionFunction = args.getVersion|| Clipperz.Base.exception.raise('MandatoryParameter');
32 this._fields = null;
33
34 return this;
35}
36
37
38Clipperz.Base.extend(Clipperz.PM.DataModel.Record.Version, Clipperz.PM.DataModel.EncryptedRemoteObject, {
39
40 'toString': function() {
41 return "Record.Version (" + this.reference() + ")";
42 },
43
44 //-------------------------------------------------------------------------
45
46 'reference': function () {
47 return this._reference;
48 },
49
50 //-------------------------------------------------------------------------
51/*
52 'hasPendingChanges': function () {
53 var deferredResult;
54
55 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.hasPendingChanges", {trace:false});
56 deferredResult.addCallback(MochiKit.Base.bind(Clipperz.PM.DataModel.Record.Version.superclass.hasPendingChanges, this));
57 deferredResult.callback();
58
59 return deferredResult;
60 },
61*/
62 //-------------------------------------------------------------------------
63
64
65 'hasPendingChangesWhenBrandNew': function () {
66 var deferredResult;
67
68 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.hasPendingChangesWhenBrandNew", {trace:false});
69 deferredResult.addMethod(this, 'fields');
70 deferredResult.addCallback(MochiKit.Base.values);
71 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.methodcaller('isEmpty'))
72 deferredResult.addCallback(Clipperz.Async.collectAll);
73 deferredResult.addCallback(function(someValues) {
74 return MochiKit.Iter.every(someValues, MochiKit.Base.operator.identity);
75 });
76 deferredResult.addCallback(MochiKit.Base.operator.lognot)
77 deferredResult.callback();
78
79 return deferredResult;
80 },
81
82 //=========================================================================
83
84 'commitTransientState': function () {
85 var deferredResult;
86
87 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.commitTransientState", {trace:false});
88 deferredResult.addCallback(MochiKit.Base.bind(Clipperz.PM.DataModel.Record.Version.superclass.commitTransientState, this));
89 deferredResult.callback();
90
91 return deferredResult;
92 },
93
94 //=========================================================================
95
96 'unpackData': function (someData) { //++
97 varresult;
98
99 result = someData;
100 if ((someData['fields'] != null) && (someData['fields'] instanceof Array)) {
101 varfields;
102 var i,c;
103
104 fields = someData['fields'];
105 delete someData['fields'];
106
107 someData['fields'] = {};
108 c = fields.length;
109 for (i=0; i<c; i++) {
110 someData['fields'][i] = fields[i];
111 }
112 }
113
114
115
116 return result;
117 },
118
119 //=========================================================================
120
121 'fields': function () {
122 vardeferredResult;
123 var deferredLock;
124
125 deferredLock = this.getDeferredLockForKey('fields');
126
127 deferredResult = new Clipperz.Async.Deferred("Record.Version.fields", {trace:false});
128 deferredResult.acquireLock(deferredLock);
129 deferredResult.addCallback(MochiKit.Base.bind(function () {
130 var innerDeferredResult;
131
132 if (this._fields == null) {
133 innerDeferredResult = new Clipperz.Async.Deferred("Record.Version.fields <inner deferred>", {trace:false});
134 innerDeferredResult.addMethod(this, 'getValue', 'fields');
135 innerDeferredResult.addCallback(MochiKit.Base.bind(function (someObjectData) {
136 var reference;
137
138 this._fields = {};
139
140 for (reference in someObjectData) {
141 varrecordVersionField;
142
143 recordVersionField = new Clipperz.PM.DataModel.Record.Version.Field({
144 'recordVersion':this,
145 'reference': reference
146 });
147
148 this._fields[reference] = recordVersionField;
149 }
150
151 return this._fields;
152 }, this));
153 innerDeferredResult.callback();
154 } else {
155 innerDeferredResult = MochiKit.Async.succeed(this._fields);
156 }
157
158 return innerDeferredResult;
159 }, this));
160 deferredResult.releaseLock(deferredLock);
161 deferredResult.callback();
162
163 return deferredResult;
164 },
165
166 //-------------------------------------------------------------------------
167
168 'getFieldsValues': function () {
169 return this.getValue('fields');
170 },
171
172 //-------------------------------------------------------------------------
173
174 'addField': function (someParameters) {
175 varnewField;
176
177 newField = new Clipperz.PM.DataModel.Record.Version.Field({recordVersion:this});
178
179 return Clipperz.Async.callbacks("Record.Version.addField", [
180 MochiKit.Base.method(this, 'fields'),
181
182 MochiKit.Base.method(this, '_getObjectDataStore'),
183 MochiKit.Base.methodcaller('values'),
184 Clipperz.Base.serializeJSON,
185
186 MochiKit.Base.bind(function () { this._fields[newField.reference()] = newField; }, this),
187 MochiKit.Base.method(newField, 'setLabel', someParameters['label']),
188 MochiKit.Base.method(newField, 'setValue', someParameters['value']),
189 MochiKit.Base.method(newField, 'setIsHidden',someParameters['isHidden']),
190
191 MochiKit.Base.method(this, '_getObjectDataStore'),
192 MochiKit.Base.methodcaller('values'),
193 Clipperz.Base.serializeJSON,
194
195 MochiKit.Base.partial(MochiKit.Async.succeed, newField)
196 ], {trace:false});
197 },
198
199 //-------------------------------------------------------------------------
200
201 'removeField': function (aField) {
202 return Clipperz.Async.callbacks("Record.Version.removeField", [
203 MochiKit.Base.method(this, 'fields'),
204 MochiKit.Base.bind(function () { delete this._fields[aField.reference()]; }, this),
205 MochiKit.Base.method(this, 'removeValue', 'fields' + '.' + aField.reference())
206 ], {trace:false});
207 },
208
209 //-------------------------------------------------------------------------
210/*
211 'sortFieldReference': function (someSortedFieldReferences) {
212
213
214
215 },
216*/
217 //=========================================================================
218/*
219 'directLogins': function () {
220 return MochiKit.Base.values(this._directLogins);
221 },
222
223 'addDirectLogin': function (aDirectLogin) {
224 this._directLogins[aDirectLogin.reference()] = aDirectLogin;
225 },
226*/
227
228 //=========================================================================
229/*
230 'updateValues': function (anotherVersion) {
231 return Clipperz.Async.callbacks("Record.Version.updateValue", [
232 MochiKit.Base.partial(MochiKit.Async.succeed, this)
233 ], {trace:false});
234 },
235*/
236 //=========================================================================
237
238 'setRemoteData': function (aValue) {
239 this._remoteData = aValue;
240
241 return aValue;
242 },
243
244 //=========================================================================
245
246 'getVersionFunction': function () {
247 return this._getVersionFunction;
248 },
249
250 'previousVersion': function () {
251 return Clipperz.Async.callbacks("Record.Versions.previousVersion", [
252 MochiKit.Base.method(this, 'previousVersionReference'),
253 this.getVersionFunction()
254 ], {trace:false});
255 },
256
257 'previousVersionReference': function () {
258 return this.getValue('previousVersionReference');
259 },
260
261 'previousVersionKey': function () {
262 //TODO: this value i encrypted on its own. So it can not be saved in the main objectStore!!!
263 return this.getValue('previousVersionKey');
264 },
265
266 //-------------------------------------------------------------------------
267
268 'setPreviousVersionReferenceAndKey': function (aVersionObjectAndKey) {
269 // this._previousVersion = anotherVersion;
270 return Clipperz.Async.callbacks("Record.Version.setPreviousVersion", [
271 MochiKit.Base.method(this, 'setValue', 'previousVersionReference',aVersionObjectAndKey['reference']),
272 MochiKit.Base.method(this, 'setValue', 'previousVersionKey', aVersionObjectAndKey['key'])
273 ], {trace:false});
274 },
275
276 //=========================================================================
277
278 'revertChanges': function () {
279 this.setReference(this.transientState()['originalReference']);
280 Clipperz.PM.DataModel.Record.Version.superclass.revertChanges.apply(this, arguments);
281 },
282
283 //-------------------------------------------------------------------------
284
285 'prepareRemoteDataWithKey': function (aKey) {
286 var deferredResult;
287 var result;
288
289 result = {};
290
291 deferredResult = new Clipperz.Async.Deferred("Record.Version.prepareRemoteDataWithKey", {trace:false});
292 if (this.isBrandNew() == false) {
293 this.transientState()['originalReference'] = this.reference();
294
295 deferredResult.collectResults({
296 'key':MochiKit.Base.partial(MochiKit.Async.succeed, aKey),
297 'value': MochiKit.Base.method(this, 'getKey'),
298 'version': MochiKit.Base.partial(MochiKit.Async.succeed, Clipperz.PM.Crypto.encryptingFunctions.currentVersion)
299 });
300 deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncrypt);
301 deferredResult.addCallback(Clipperz.Async.setItem, result, 'previousVersionKey');
302 } else {
303 deferredResult.addCallback(Clipperz.Async.setItem, result, 'previousVersionKey', Clipperz.PM.Crypto.nullValue);
304 }
305 deferredResult.addCallback(MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.prepareRemoteDataWithKey, this, aKey));
306 deferredResult.addCallback(MochiKit.Base.update, result);
307 deferredResult.addMethod(this, 'setRemoteData');
308
309 deferredResult.callback();
310
311 return deferredResult;
312 },
313
314 //=========================================================================
315/*
316 'deleteAllCleanTextData': function () {
317 return Clipperz.PM.DataModel.Record.Version.superclass.deleteAllCleanTextData.apply(this, arguments);
318 },
319
320 'hasAnyCleanTextData': function () {
321 return Clipperz.PM.DataModel.Record.Version.superclass.hasAnyCleanTextData.apply(this, arguments);
322 },
323*/
324 //=========================================================================
325 __syntaxFix__: "syntax fix"
326});
327
328
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/Record.js b/frontend/delta/js/Clipperz/PM/DataModel/Record.js
new file mode 100644
index 0000000..379872a
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/Record.js
@@ -0,0 +1,891 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29Clipperz.PM.DataModel.Record = function(args) {
30 Clipperz.PM.DataModel.Record.superclass.constructor.apply(this, arguments);
31
32 this._updateDate = (args.updateDate ? Clipperz.PM.Date.parse(args.updateDate) : Clipperz.Base.exception.raise('MandatoryParameter'));
33
34 this._retrieveIndexDataFunction = args.retrieveIndexDataFunction|| Clipperz.Base.exception.raise('MandatoryParameter');
35 this._updateIndexDataFunction = args.updateIndexDataFunction || Clipperz.Base.exception.raise('MandatoryParameter');
36
37 this._retrieveDirectLoginIndexDataFunction = args.retrieveDirectLoginIndexDataFunction|| null;
38 this._setDirectLoginIndexDataFunction = args.setDirectLoginIndexDataFunction || null;
39 this._removeDirectLoginIndexDataFunction = args.removeDirectLoginIndexDataFunction|| null;
40
41 this._createNewDirectLoginFunction = args.createNewDirectLoginFunction || null;
42
43 this._directLogins = {};
44
45 this._versions = {};
46
47 this._currentRecordVersion = null;
48 if (this.isBrandNew()) {
49 var newVersion;
50
51 this.setNotes('');
52 newVersion = new Clipperz.PM.DataModel.Record.Version({
53 'retrieveKeyFunction':MochiKit.Base.method(this, 'getVersionKey'),
54 'getVersion': MochiKit.Base.method(this, 'getVersion')
55
56 });
57 this._versions[newVersion.reference()] = newVersion;
58 this._currentVersionReference = newVersion.reference();
59 // this.setLabel('');
60 }
61
62 return this;
63}
64
65
66Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.EncryptedRemoteObject, {
67
68 'toString': function() {
69 return "Record (" + this.reference() + ")";
70 },
71
72 //-------------------------------------------------------------------------
73
74 'reference': function () {
75 return this._reference;
76 },
77
78 //=========================================================================
79
80 'getIndexData': function () {
81 return this._retrieveIndexDataFunction(this.reference());
82 },
83
84 //.........................................................................
85
86 'getIndexDataForKey': function (aKey) {
87 return Clipperz.Async.callbacks("Record.getIndexDataForKey", [
88 MochiKit.Base.method(this, 'getIndexData'),
89 MochiKit.Base.itemgetter(aKey)
90 ], {trace:false});
91 },
92
93 //-------------------------------------------------------------------------
94
95 'setIndexDataForKey': function (aKey, aValue) {
96 // return this._updateIndexDataFunction(this.reference(), aKey, aValue);
97
98 var deferredResult;
99
100 deferredResult = new Clipperz.Async.Deferred("Record.setIndexDataForKey", {trace:false});
101 deferredResult.addMethod(this, 'getIndexDataForKey', aKey);
102 deferredResult.addCallback(MochiKit.Base.bind(function (aCurrentValue) {
103 var result;
104 var originalValue;
105
106 originalValue = this.transientState().getValue('originalValues.indexData.' + aKey);
107 if (originalValue == null) {
108 originalValue = this.transientState().setValue('originalValues.indexData.' + aKey, aCurrentValue);
109 }
110
111 if (aCurrentValue != aValue) {
112 if (originalValue != aValue) {
113 this.transientState().setValue('hasPendingChanges.indexData.' + aKey, true);
114 } else {
115 this.transientState().setValue('hasPendingChanges.indexData.' + aKey, false);
116 }
117
118 result = this._updateIndexDataFunction(this.reference(), aKey, aValue);
119 } else {
120 result = MochiKit.Async.succeed(aValue);
121 }
122
123 return result;
124 }, this));
125
126 deferredResult.callback();
127
128 return deferredResult;
129 },
130
131 //=========================================================================
132/*
133 'key': function () {
134 return this.getIndexDataForKey('key');
135 },
136*/
137 //=========================================================================
138
139 'label': function () {
140 return this.getIndexDataForKey('label');
141 },
142
143 //.........................................................................
144
145 'setLabel': function (aValue) {
146 return this.setIndexDataForKey('label', aValue);
147 },
148
149 //=========================================================================
150
151 'headerNotes': function () {
152 return this.getIndexDataForKey('notes');
153 },
154
155 //-------------------------------------------------------------------------
156
157 'notes': function () {
158 return Clipperz.Async.callbacks("Record.notes", [
159 MochiKit.Base.method(this, 'headerNotes'),
160 MochiKit.Base.bind(function (someHeaderNotes) {
161 var result;
162
163 if ((someHeaderNotes == null) || (typeof(someHeaderNotes) == 'undefined')) {
164 result = this.getValue('notes');
165 } else {
166 result = MochiKit.Async.succeed(someHeaderNotes);
167 }
168
169 return result;
170 }, this)
171 ], {trace:false});
172 },
173
174 //.........................................................................
175
176 'setNotes': function (aValue) {
177 return this.setValue('notes', aValue);
178 },
179
180 //=========================================================================
181
182 'updateDate': function () {
183 return MochiKit.Async.succeed(this._updateDate);
184 },
185
186 //=========================================================================
187
188 'favicon': function () {
189 var result;
190 var directLogins;
191
192 directLogins = MochiKit.Base.values(this.directLogins());
193 if (directLogins.length > 0) {
194 result = directLogins[0].favicon();
195 // } else if (/* is there an URL to use for searching a favicon */){
196 } else {
197 result = null; //MochiKit.Async.succeed(Clipperz.PM.Strings['defaultFaviconUrl']);
198 }
199
200 return result;
201 },
202
203 //-------------------------------------------------------------------------
204
205 'searchableContent': function () {
206 var deferredResult;
207
208 deferredResult = new Clipperz.Async.Deferred("Record.searchableContent", {trace:false});
209
210 deferredResult.collectResults({
211 'recordLabel': MochiKit.Base.method(this, 'label'),
212 'directLoginLabels': [
213 MochiKit.Base.method(this, 'directLoginReferences'),
214 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.itemgetter('label'))
215 ]
216 })
217 deferredResult.addCallback(function (someValues) {
218 return someValues['recordLabel'] + ' ' + someValues['directLoginLabels'].join(' ');
219 });
220 deferredResult.callback();
221
222 return deferredResult;
223 },
224
225 //-------------------------------------------------------------------------
226
227 'isMatching': function (aRegExp) {
228 return Clipperz.Async.callbacks("deferredFilterFunction", [
229 MochiKit.Base.method(this, 'searchableContent'),
230 MochiKit.Base.method(aRegExp, 'test'),
231 function (doesItMatch) {
232 var result;
233
234 if (doesItMatch) {
235 result = MochiKit.Async.succeed('match');
236 } else {
237 result = MochiKit.Async.fail('miss');
238 }
239
240 return result;
241 }
242 ], {trace:false});
243 },
244
245 //=========================================================================
246
247 'content': function () {
248 var deferredResult;
249 varresult;
250
251 result = {
252 'fields': [],
253 'directLogins': []
254 };
255
256 deferredResult = new Clipperz.Async.Deferred("Record.content", {trace:false});
257 deferredResult.addMethod(this, 'reference');
258 deferredResult.addCallback(function (aValue) { result['reference'] = aValue; });
259 deferredResult.addMethod(this, 'label');
260 deferredResult.addCallback(function (aValue) { result['title'] = aValue; });
261 deferredResult.addMethod(this, 'notes');
262 deferredResult.addCallback(function (aValue) { result['notes'] = aValue; });
263
264 deferredResult.addMethod(this, 'fields');
265 deferredResult.addCallback(MochiKit.Base.values);
266 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.methodcaller('content'));
267 deferredResult.addCallback(Clipperz.Async.collectAll);
268 deferredResult.addCallback(MochiKit.Base.map, function (aValue) { result['fields'].push(aValue); });
269
270 deferredResult.addMethod(this, 'directLogins');
271 deferredResult.addCallback(MochiKit.Base.values);
272 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.methodcaller('content'));
273 deferredResult.addCallback(Clipperz.Async.collectAll);
274 deferredResult.addCallback(MochiKit.Base.map, function (aValue) { result['directLogins'].push(aValue); });
275 deferredResult.addCallback(function () { return result; });
276
277 deferredResult.callback();
278
279 return deferredResult;
280 },
281
282 //=========================================================================
283
284 'directLogins': function () {
285 return this._directLogins;
286 },
287
288 'addDirectLogin': function (aDirectLogin) {
289 this._directLogins[aDirectLogin.reference()] = aDirectLogin;
290 },
291
292 'directLoginWithReference': function (aDirectLoginReference) {
293 return this._directLogins[aDirectLoginReference];
294 },
295
296 'createNewDirectLoginFunction': function () {
297 return this._createNewDirectLoginFunction;
298 },
299
300 'saveOriginalDirectLoginStatusToTransientState': function () {
301 if (this.transientState().getValue('directLogins') == null) {
302 // this.transientState().setValue('directLogins', this._directLogins)
303 MochiKit.Iter.forEach(MochiKit.Base.keys(this._directLogins), MochiKit.Base.bind(function(aKey) {
304 this.transientState().setValue('directLogins' + '.' + aKey, this._directLogins[aKey])
305 }, this))
306 }
307 },
308
309 'createNewDirectLogin': function () {
310 this.saveOriginalDirectLoginStatusToTransientState();
311
312 return this.createNewDirectLoginFunction()(this);
313 },
314
315 'removeDirectLogin': function(aDirectLogin) {
316 this.saveOriginalDirectLoginStatusToTransientState();
317
318 return Clipperz.Async.callbacks("Record.removeDirectLogin", [
319 MochiKit.Base.method(this, 'removeValue', 'directLogins' + '.' + aDirectLogin.reference()),
320 MochiKit.Base.bind(function () {
321 delete this._directLogins[aDirectLogin.reference()]
322 }, this)
323 ], {trace:false});
324
325 },
326
327 'directLoginReferences': function () {
328 var result;
329
330 result = Clipperz.Async.callbacks("Record.directLoginReferences", [
331 MochiKit.Base.method(this, 'directLogins'),
332 MochiKit.Base.values,
333 function (someDirectLogins) {
334 var result;
335 var i,c;
336
337 result = [];
338 c = someDirectLogins.length;
339 for (i=0; i<c; i++) {
340 result.push(Clipperz.Async.collectResults("Record.directLoginReferences - collectResults", {
341 '_rowObject': MochiKit.Async.succeed,
342 '_reference': MochiKit.Base.methodcaller('reference'),
343 'label': MochiKit.Base.methodcaller('label'),
344 'favicon': MochiKit.Base.methodcaller('favicon')
345 }, {trace:false})(someDirectLogins[i]));
346 };
347
348 return result;
349 },
350 Clipperz.Async.collectAll
351 ], {trace:false});
352
353 return result;
354 },
355
356 //=========================================================================
357
358 'unpackRemoteData': function (someData) {
359 var result;
360
361/*
362 this._currentRecordVersion = new Clipperz.PM.DataModel.Record.Version({
363 'reference': someData['currentVersion']['reference'],
364 'retrieveKeyFunction': MochiKit.Base.method(this, 'getCurrentRecordVersionKey'),
365 'remoteData': someData['currentVersion'],
366 });
367*/
368 var versionKey;
369
370 for (versionKey in someData['versions']) {
371 this._versions[versionKey] = new Clipperz.PM.DataModel.Record.Version({
372 'reference': versionKey,
373 'retrieveKeyFunction':MochiKit.Base.method(this, 'getVersionKey'),
374 'remoteData': someData['versions'][versionKey],
375 'getVersion': MochiKit.Base.method(this, 'getVersion')
376 })
377 }
378
379 // this._currentVersionReference = someData['currentVersion']['reference'];
380 this._currentVersionReference = someData['currentVersion'];
381
382 result = Clipperz.PM.DataModel.Record.superclass.unpackRemoteData.apply(this, arguments);
383
384 return result;
385 },
386
387 //-------------------------------------------------------------------------
388
389 'unpackData': function (someData) {
390 var result;
391
392 result = Clipperz.PM.DataModel.Record.superclass.unpackData.apply(this, arguments);
393
394 if (MochiKit.Base.isUndefinedOrNull(result['notes'])) {
395 result['notes'] = ''
396 }
397
398 return result;
399 },
400
401 //-------------------------------------------------------------------------
402
403 'prepareRemoteDataWithKey': function (aKey) {
404 var deferredResult;
405 varnewVersionKey;
406 var result;
407
408 newVersionKey = Clipperz.PM.Crypto.randomKey();
409 result = {};
410
411 deferredResult = new Clipperz.Async.Deferred("Record.prepareRemoteDataWithKey", {trace:false});
412 deferredResult.addCallbackList([
413 Clipperz.Async.collectResults("Record.prepareRemoteDataWithKey - collect results", {
414 'isBrandNew': MochiKit.Base.method(this, 'isBrandNew'),
415 'versionHasPendingChanges':[
416 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
417 // MochiKit.Base.methodcaller('hasPendingChanges')
418 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges')
419 ]
420 }),
421 Clipperz.Async.or,
422
423 Clipperz.Async.deferredIf("Current Version has pending changes", [
424 MochiKit.Base.method(this, 'createNewRecordVersion'),
425 MochiKit.Base.methodcaller('prepareRemoteDataWithKey', newVersionKey),
426 MochiKit.Base.partial(Clipperz.Async.setItem, result, 'currentRecordVersion'),
427 MochiKit.Base.method(this, 'setCurrentRecordVersionKey', newVersionKey)
428 ], []),
429
430 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.prepareRemoteDataWithKey, this, aKey),
431 MochiKit.Base.partial(Clipperz.Async.setItem, result, 'record'),
432
433 MochiKit.Base.partial(MochiKit.Async.succeed, result)
434 ]);
435
436 deferredResult.callback();
437
438 return deferredResult;
439 },
440
441 //=========================================================================
442
443 'fields': function () {
444 return this.invokeCurrentRecordVersionMethod('fields');
445 },
446
447 'addField': function (someParameters) {
448 return this.invokeCurrentRecordVersionMethod('addField', someParameters);
449 },
450
451 'removeField': function (someParameters) {
452 return this.invokeCurrentRecordVersionMethod('removeField', someParameters);
453 },
454
455 //'sortFieldReference': function (someSortedFieldReferences) {
456 // return this.invokeCurrentRecordVersionMethod('sortFieldReference', someSortedFieldReferences);
457 //},
458
459 'getFieldsValues': function () {
460 return this.invokeCurrentRecordVersionMethod('getFieldsValues');
461 },
462
463 'fieldWithLabel': function (aLabel) {
464 return Clipperz.Async.callbacks("Record.fieldWithLabel", [
465 MochiKit.Base.method(this, 'fields'),
466 MochiKit.Base.values,
467 MochiKit.Base.partial(Clipperz.Async.deferredFilter, function (aField) {
468 return Clipperz.Async.callbacks("Record.fieldWithLabel - check field label", [
469 MochiKit.Base.methodcaller('label'),
470 MochiKit.Base.partial(MochiKit.Base.operator.eq, aLabel)
471 ], {trace:false}, aField);
472 }),
473 function (someFilteredResults) {
474 var result;
475
476 switch (someFilteredResults.length) {
477 case 0:
478 result = null;
479 break;
480 case 1:
481 result = someFilteredResults[0];
482 break;
483 default:
484 WTF = TODO;
485 break;
486 }
487
488 return result;
489 }
490 ], {trace:false});
491 },
492
493 //=========================================================================
494
495 'getVersion': function (aVersionReference) {
496 return Clipperz.Async.callbacks("Record.getVersion", [
497 MochiKit.Base.method(this, 'getVersions'),
498 MochiKit.Base.itemgetter(aVersionReference)
499 ], {trace:false});
500 },
501
502 //-------------------------------------------------------------------------
503
504 'getVersionKey': function (aVersionReference) {
505 vardeferredResult;
506 var transientStateKey;
507
508 transientStateKey = 'versionKeys' + '.' + aVersionReference;
509 if (this.transientState().getValue(transientStateKey) != null) {
510 deferredResult = MochiKit.Async.succeed(this.transientState().getValue(transientStateKey));
511 } else {
512 deferredResult = Clipperz.Async.callbacks("Record.getVersionKey", [
513 MochiKit.Base.method(this, 'getVersions'),
514 MochiKit.Base.partial(MochiKit.Base.operator.eq, aVersionReference, this.currentVersionReference()),
515 Clipperz.Async.deferredIf("getVersionKey for current version", [
516 MochiKit.Base.method(this, 'getCurrentRecordVersionKey'),
517 MochiKit.Base.method(this.transientState(), 'setValue', transientStateKey)
518 ],[
519 MochiKit.Async.fail
520 ])
521 ], {trace:false});
522 }
523
524 return deferredResult;
525 },
526
527 //-------------------------------------------------------------------------
528
529 'versions': function () {
530 return this._versions;
531 },
532
533 'getVersions': function () {
534 return Clipperz.Async.callbacks("Record.versions", [
535 MochiKit.Base.method(this, 'getValue', 'fakeKey, just to trigger unpackRemoteData'),
536 MochiKit.Base.bind(function () { return this._versions; }, this)
537 ], {trace:false});
538 },
539
540 //-------------------------------------------------------------------------
541
542 'getCurrentRecordVersion': function () {
543 return Clipperz.Async.callbacks("Record.getCurrentRecordVersion", [
544 // MochiKit.Base.method(this, 'getValue', 'fakeKey, just to trigger unpackRemoteData'),
545 // MochiKit.Base.bind(function () { return this._currentRecordVersion; }, this)
546
547 MochiKit.Base.method(this, 'versions'),
548 MochiKit.Base.itemgetter(this.currentVersionReference()),
549 Clipperz.Async.deferredIf("The current version is available", [
550 MochiKit.Async.succeed
551 ], [
552 MochiKit.Base.method(this, 'getVersions'),
553 MochiKit.Base.bind(function (someVersions) { return someVersions[this.currentVersionReference()]}, this)
554 ])
555 ], {trace:false});
556 },
557
558 'setCurrentRecordVersion': function (aRecordVersion) {
559 this._currentVersionReference = aRecordVersion.reference();
560 },
561
562 //.........................................................................
563
564 'currentVersionReference': function () {
565 return this._currentVersionReference;
566 },
567
568 //-------------------------------------------------------------------------
569
570 'createNewRecordVersion': function () {
571 var deferredResult;
572
573 if (this.isBrandNew()) {
574 deferredResult = this.getCurrentRecordVersion();
575 } else {
576 var newVersion;
577
578 newVersion = new Clipperz.PM.DataModel.Record.Version({
579 // 'reference': versionKey,
580 'retrieveKeyFunction':MochiKit.Base.method(this, 'getVersionKey'),
581 // 'remoteData': {},
582 'getVersion': MochiKit.Base.method(this, 'getVersion')
583 })
584 this._versions[newVersion.reference()] = newVersion;
585
586 deferredResult = Clipperz.Async.callbacks("Record.createNewRecordVersion", [
587 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
588 // MochiKit.Base.methodcaller('values'),
589 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'values'),
590 MochiKit.Base.method(newVersion, 'setValues'),
591
592 Clipperz.Async.collectResults("Record.createNewRecordVersion [collect results]", {
593 'reference':MochiKit.Base.method(this, 'currentVersionReference'),
594 'key': MochiKit.Base.method(this, 'getCurrentRecordVersionKey')
595 }, {trace:false}),
596 MochiKit.Base.method(newVersion, 'setPreviousVersionReferenceAndKey'),
597
598 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
599 // MochiKit.Base.method(this, 'revertChanges'),
600 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'revertChanges'),
601
602 MochiKit.Base.method(this, 'setCurrentRecordVersion', newVersion),
603 MochiKit.Base.partial(MochiKit.Async.succeed, newVersion)
604 ], {trace:false});
605 }
606
607 return deferredResult;
608 },
609
610 //-------------------------------------------------------------------------
611
612 'getCurrentRecordVersionKey': function () {
613 return Clipperz.Async.callbacks("Record.getCurrentRecordVersionKey", [
614 MochiKit.Base.method(this, 'getValue', 'currentVersionKey'),
615 Clipperz.Async.deferredIf("currentVersionKey is NOT null", [
616 MochiKit.Async.succeed
617 ], [
618 MochiKit.Base.method(this, 'getKey')
619 ])
620 ], {trace:false});
621 },
622
623 'setCurrentRecordVersionKey': function (aValue) {
624 //TODO: triple check this method!
625 return Clipperz.Async.callbacks("Record.setCurrentRecordVersionKey", [
626 MochiKit.Base.method(this, 'setValue', 'currentVersionKey', aValue)
627 ], {trace:false});
628 },
629
630 //-------------------------------------------------------------------------
631
632 'invokeCurrentRecordVersionMethod': function (aMethodName, someValues) {
633 return Clipperz.Async.callbacks("Record.invokeCurrentRecordVersionMethod", [
634 MochiKit.Base.method(this, 'getCurrentRecordVersion'),
635 MochiKit.Base.methodcaller(aMethodName, someValues)
636 ], {trace:false});
637 },
638
639
640 'lazilyinvokeCurrentRecordVersionMethod': function (aMethodName, someValues, defaultResult) {
641 return Clipperz.Async.callbacks("Record.lazilyinvokeCurrentRecordVersionMethod", [
642 MochiKit.Base.method(this, 'currentVersionReference'),
643 Clipperz.Async.deferredIf("versions has been loaded", [
644 MochiKit.Base.method(this, 'getCurrentRecordVersion'),
645 MochiKit.Base.methodcaller(aMethodName, someValues),
646 ], [
647 MochiKit.Base.partial(MochiKit.Async.succeed, defaultResult),
648 ])
649 ], {trace:false});
650 },
651
652 //=========================================================================
653
654 'hasPendingChanges': function () {
655 var deferredResult;
656
657 if (this.hasInitiatedObjectDataStore()) {
658 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.hasPendingChanges", {trace:false});
659 deferredResult.collectResults({
660 'super': MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasPendingChanges, this),
661 'currentVersion': [
662 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
663 // MochiKit.Base.methodcaller('hasPendingChanges')
664 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges')
665 ],
666 'directLogins': [
667 MochiKit.Base.method(this, 'directLogins'),
668 MochiKit.Base.values,
669 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasPendingChanges')),
670 Clipperz.Async.collectAll,
671 Clipperz.Async.or
672 // function(someValues) {
673 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
674 // }
675 ]
676 });
677 deferredResult.addCallback(MochiKit.Base.values);
678 deferredResult.addCallback(MochiKit.Base.bind(function(someValues) {
679 var result;
680 result = MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
681
682 if ((result == false) && (this.isBrandNew() == false)) {
683 result = MochiKit.Iter.some(MochiKit.Base.values(this.transientState().getValue('hasPendingChanges.indexData')), MochiKit.Base.operator.identity);
684 }
685
686 return result;
687 }, this));
688
689 deferredResult.callback();
690 } else {
691 deferredResult = Clipperz.Async.callbacks("Recrod.hasPendingChanges [hasInitiatedObjectDataStore == false]", [
692 MochiKit.Base.method(this, 'directLogins'),
693 MochiKit.Base.values,
694 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasPendingChanges')),
695 Clipperz.Async.collectAll,
696 Clipperz.Async.or
697 // function(someValues) {
698 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
699 // }
700 ], {trace:false})
701 }
702
703 return deferredResult;
704 },
705
706 //-------------------------------------------------------------------------
707
708 'hasPendingChangesWhenBrandNew': function () {
709 var deferredResult;
710
711 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.hasPendingChangesWhenBrandNew", {trace:false});
712 deferredResult.collectResults({
713 'label': [
714 MochiKit.Base.method(this, 'label'),
715 MochiKit.Base.partial(MochiKit.Base.operator.ne, '')
716 ],
717 'notes': [
718 MochiKit.Base.method(this, 'notes'),
719 MochiKit.Base.partial(MochiKit.Base.operator.ne, '')
720 ]
721 });
722 // deferredResult.addCallback(MochiKit.Base.values);
723 // deferredResult.addCallback(function(someValues) {
724 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
725 // });
726 deferredResult.addCallback(Clipperz.Async.or);
727
728 deferredResult.callback();
729
730 return deferredResult;
731 },
732
733 //-------------------------------------------------------------------------
734
735 'isBrandNewWithNoPendingChanges': function () {
736 vardeferredResult;
737
738 if (this.isBrandNew() == false) {
739 deferredResult = MochiKit.Async.succeed(false);
740 } else {
741 deferredResult = Clipperz.Async.callbacks("Record.isBrandNewWithNoPendingChanges", [
742 MochiKit.Base.method(this, 'hasPendingChanges'),
743 MochiKit.Base.operator.lognot
744 ], {trace:false});
745 }
746
747 return deferredResult;
748 },
749
750 //=========================================================================
751
752 'revertChanges': function () {
753 var deferredResult;
754
755 if (this.isBrandNew() == false) {
756 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.revertChanges", {trace:false});
757 deferredResult.addMethod(this, 'hasPendingChanges');
758 deferredResult.addIf([
759 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
760 // MochiKit.Base.methodcaller('revertChanges'),
761 MochiKit.Base.method(this,'invokeCurrentRecordVersionMethod', 'revertChanges'),
762
763 MochiKit.Base.method(this, 'directLogins'),
764 MochiKit.Base.values,
765 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('revertChanges')),
766
767 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.revertChanges, this)
768 ], [
769 MochiKit.Async.succeed
770 ]);
771 deferredResult.callback();
772 } else {
773 // this.deleteAllCleanTextData();
774 deferredResult = MochiKit.Async.succeed();
775 }
776
777 return deferredResult;
778 },
779
780 //-------------------------------------------------------------------------
781
782 'resetTransientState': function (isCommitting) {
783 // if ((isCommitting == false) && (this.transientState().getValue('directLogins') != null)) {
784 // this._directLogins = this.transientState().getValue('directLogins');
785 // }
786
787 return Clipperz.Async.callbacks("Record.resetTransientState", [
788 //- MochiKit.Base.method(this, 'getCurrentRecordVersion'),
789 //- MochiKit.Base.methodcaller('resetTransientState'),
790 // MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'resetTransientState'),
791 MochiKit.Base.method(this, 'lazilyinvokeCurrentRecordVersionMethod', 'resetTransientState'),
792
793 MochiKit.Base.method(this, 'directLogins'),
794 MochiKit.Base.values,
795 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('resetTransientState')),
796
797 MochiKit.Base.bind(function () {
798 if ((isCommitting == false) && (this.transientState().getValue('directLogins') != null)) {
799 this._directLogins = this.transientState().getValue('directLogins');
800 }
801 }, this),
802
803 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.resetTransientState, this, isCommitting)
804 ], {trace:false})
805 },
806
807 //-------------------------------------------------------------------------
808
809 'commitTransientState': function () {
810 var deferredResult;
811
812 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.commitTransientState", {trace:false});
813 deferredResult.addMethod(this, 'hasPendingChanges');
814 deferredResult.addIf([
815 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.commitTransientState, this),
816 // MochiKit.Base.method(this, 'getCurrentRecordVersion'),
817 // MochiKit.Base.methodcaller('commitTransientState'),
818 MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'commitTransientState'),
819 MochiKit.Base.method(this, 'directLogins'),
820 MochiKit.Base.values,
821 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('commitTransientState'))
822 ], [
823 MochiKit.Async.succeed
824 ]);
825 deferredResult.callback();
826
827 return deferredResult;
828 },
829
830 //=========================================================================
831
832 'retrieveDirectLoginIndexDataFunction': function () {
833 return this._retrieveDirectLoginIndexDataFunction;
834 },
835
836 'setDirectLoginIndexDataFunction': function () {
837 return this._setDirectLoginIndexDataFunction;
838 },
839
840 'removeDirectLoginIndexDataFunction': function () {
841 return this._removeDirectLoginIndexDataFunction;
842 },
843
844 //=========================================================================
845
846 'deleteAllCleanTextData': function () {
847 // return Clipperz.PM.DataModel.Record.superclass.deleteAllCleanTextData.apply(this, arguments);
848
849 return Clipperz.Async.callbacks("Record.deleteAllCleanTextData", [
850 MochiKit.Base.method(this, 'versions'),
851 MochiKit.Base.values,
852 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('deleteAllCleanTextData')),
853
854 MochiKit.Base.method(this, 'directLogins'),
855 MochiKit.Base.values,
856 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('deleteAllCleanTextData')),
857
858 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.deleteAllCleanTextData, this)
859 ], {trace:false});
860 },
861
862 'hasAnyCleanTextData': function () {
863 // return Clipperz.PM.DataModel.Record.superclass.hasAnyCleanTextData.apply(this, arguments);
864
865 return Clipperz.Async.callbacks("Record.hasAnyCleanTextData", [
866 Clipperz.Async.collectResults("Record.hasAnyCleanTextData [collect results]", {
867 'versions':[
868 MochiKit.Base.method(this, 'versions'),
869 MochiKit.Base.values,
870 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasAnyCleanTextData')),
871 Clipperz.Async.collectAll
872 ],
873 'directLogins': [
874 MochiKit.Base.method(this, 'directLogins'),
875 MochiKit.Base.values,
876 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasAnyCleanTextData')),
877 Clipperz.Async.collectAll
878 ],
879 'super': [
880 MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasAnyCleanTextData, this)
881 ]
882 }, {trace:false}),
883 Clipperz.Async.or
884 ])
885 },
886
887 //=========================================================================
888 __syntaxFix__: "syntax fix"
889});
890
891
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Legacy.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Legacy.js
new file mode 100644
index 0000000..cda5a41
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Legacy.js
@@ -0,0 +1,182 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Header.Legacy depends on Clipperz.PM.DataModel.User!";
26}
27
28if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
29
30Clipperz.PM.DataModel.User.Header.Legacy = function(args) {
31 //args = args || {};
32 Clipperz.PM.DataModel.User.Header.Legacy.superclass.constructor.apply(this, arguments);
33
34 this._retrieveRecordDetailFunction = args.retrieveRecordDetailFunction|| Clipperz.Base.exception.raise('MandatoryParameter');
35 this._records = null;
36 //this._directLogins = null;
37
38 return this;
39}
40
41
42Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.Legacy, Clipperz.PM.DataModel.EncryptedRemoteObject, {
43
44 'toString': function() {
45 return "Clipperz.PM.DataModel.User.Header.Legacy";
46 },
47
48 //-------------------------------------------------------------------------
49
50 'retrieveRecordDetailFunction': function () {
51 return this._retrieveRecordDetailFunction;
52 },
53
54 //-------------------------------------------------------------------------
55
56 'getRecordKey': function (aRecordReference) {
57 var deferredResult;
58
59 deferredResult = new Clipperz.Async.Deferred("User.Header.Legacy.getRecordKey", {trace:false});
60 deferredResult.addMethod(this, 'getRecordIndexData');
61 deferredResult.addCallback(MochiKit.Base.itemgetter('key'))
62 deferredResult.callback();
63
64 return deferredResult;
65 },
66
67 //=========================================================================
68
69 'getRecordIndexData': function (aRecordReference) {
70 return this.getValue('records.' + aRecordReference);
71 },
72
73 'updateRecordIndexData': function (aRecordReference, aKey, aValue) {
74 return this.setValue('records.' + aRecordReference + "." + aKey, aValue);
75 },
76
77 //-------------------------------------------------------------------------
78
79 'getDirectLoginIndexData': function (aDirectLoginReference) {
80 return this.getValue('directLogins.' + aDirectLoginReference);
81 },
82
83 'setDirectLoginIndexData': function (aDirectLoginReference, aKey, aValue) {
84 return this.setValue('directLogins.' + aDirectLoginReference + '.' + aKey, aValue);
85 },
86
87 'removeDirectLoginIndexData': function (aDirectLoginReference) {
88 return this.removeValue('directLogins.' + aDirectLoginReference);
89 },
90
91 //=========================================================================
92
93 'records': function () {
94 vardeferredResult;
95 var deferredLock;
96
97 deferredLock = this.getDeferredLockForKey('records');
98
99 deferredResult = new Clipperz.Async.Deferred("User.Header.Legacy.records", {trace:false});
100 deferredResult.acquireLock(deferredLock);
101 deferredResult.addCallback(MochiKit.Base.bind(function () {
102 var innerDeferredResult;
103
104 if (this._records == null) {
105 innerDeferredResult = new Clipperz.Async.Deferred("User.Header.Legacy.records <inner deferred>", {trace:false});
106 innerDeferredResult.collectResults({
107 'header': [
108 // MochiKit.Base.method(this, 'getObjectDataStore'),
109 // MochiKit.Base.methodcaller('values')
110 MochiKit.Base.method(this, 'values')
111 ],
112 'recordsStats': [
113 MochiKit.Base.method(this, 'getRemoteData'),
114 MochiKit.Base.itemgetter('recordsStats')
115 ]
116 });
117 innerDeferredResult.addCallback(MochiKit.Base.bind(function (someObjectData) {
118 var reference;
119
120 this._records = {};
121 // this._directLogins = {};
122
123 for (reference in someObjectData['header']['records']) {
124 varrecord;
125
126 record = new Clipperz.PM.DataModel.Record({
127 'reference': reference,
128 'retrieveKeyFunction': MochiKit.Base.method(this, 'getRecordKey'),
129 'retrieveRemoteDataFunction':this.retrieveRecordDetailFunction(),
130 // 'encryptedDataKeypath': 'data',
131 // 'encryptedVersionKeypath': 'version',
132
133 'retrieveIndexDataFunction':MochiKit.Base.method(this, 'getRecordIndexData'),
134 'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
135 'updateDate': someObjectData['recordsStats'][reference]['updateDate'],
136
137 'retrieveDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'getDirectLoginIndexData'),
138 'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
139 'removeDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'removeDirectLoginIndexData')
140 });
141
142 this._records[reference] = record;
143 }
144
145 for (reference in someObjectData['header']['directLogins']) {
146 vardirectLogin;
147 var record;
148
149 record = this._records[someObjectData['header']['directLogins'][reference]['record']];
150 if (record != null) {
151 directLogin = new Clipperz.PM.DataModel.DirectLogin({
152 'reference': reference,
153 'record': record//,
154 // 'retrieveIndexDataFunction':MochiKit.Base.method(this, 'getDirectLoginIndexData'),
155 // 'setIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
156 // 'removeIndexDataFunction': MochiKit.Base.method(this, 'removeDirectLoginIndexData')
157 });
158 } else {
159Clipperz.log("WARNING: DIRECT LOGIN without a matching RECORD!!");
160 }
161 }
162
163 return this._records;
164 }, this));
165 innerDeferredResult.callback();
166 } else {
167 innerDeferredResult = MochiKit.Async.succeed(this._records);
168 }
169
170 return innerDeferredResult;
171 }, this));
172 deferredResult.releaseLock(deferredLock);
173 deferredResult.callback();
174
175 return deferredResult;
176 },
177
178 //=========================================================================
179 __syntaxFix__: "syntax fix"
180});
181
182
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js
new file mode 100644
index 0000000..e82da47
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js
@@ -0,0 +1,117 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Header.OneTimePasswords depends on Clipperz.PM.DataModel.User!";
26}
27if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
28
29//-----------------------------------------------------------------------------
30
31Clipperz.PM.DataModel.User.Header.OneTimePasswords = function(args) {
32 Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.constructor.apply(this, arguments);
33
34 this._oneTimePasswords = null;
35
36 return this;
37}
38
39//-----------------------------------------------------------------------------
40
41Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.OneTimePasswords, Clipperz.PM.DataModel.EncryptedRemoteObject, {
42
43 'toString': function() {
44 return "Clipperz.PM.DataModel.User.Header.OneTimePasswords";
45 },
46
47 //-------------------------------------------------------------------------
48/*
49 'packData': function (someData) { //++
50 var result;
51
52 result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.packData.apply(this, arguments);
53
54 return result;
55 },
56*/
57 //-------------------------------------------------------------------------
58/*
59 'packRemoteData': function (someData) {
60 var result;
61
62 result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.packRemoteData.apply(this, arguments);
63
64 return result;
65 },
66*/
67 //-------------------------------------------------------------------------
68/*
69 'prepareRemoteDataWithKey': function (aKey) {
70 var result;
71
72 result = Clipperz.PM.DataModel.User.Header.OneTimePasswords.superclass.prepareRemoteDataWithKey.apply(this, arguments);
73
74 return result;
75 },
76*/
77 //=========================================================================
78
79 'oneTimePasswords': function () {
80 vardeferredResult;
81
82 deferredResult = new Clipperz.Async.Deferred("User.Header.OneTimePasswords.oneTimePasswords", {trace:false});
83 if (this._oneTimePasswords == null) {
84 deferredResult.addMethod(this, 'values')
85 deferredResult.addCallback(MochiKit.Base.bind(function (someData) {
86 varotpKey;
87
88 this._oneTimePasswords = {};
89
90 for (otpKey in someData) {
91 var otp;
92 var otpParameters;
93
94 otpParameters = Clipperz.Base.deepClone(someData[otpKey]);
95 otpParameters['reference'] = otpKey;
96
97 otp = new Clipperz.PM.DataModel.OneTimePassword(otpParameters);
98 this._oneTimePasswords[otpKey] = otp;
99 }
100
101 return this._oneTimePasswords;
102
103 }, this));
104 deferredResult.callback();
105 } else {
106 deferredResult = MochiKit.Async.succeed(this._oneTimePasswords);
107 }
108
109 return deferredResult;
110 },
111
112 //=========================================================================
113 __syntaxFix__: "syntax fix"
114});
115
116//-----------------------------------------------------------------------------
117
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Preferences.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Preferences.js
new file mode 100644
index 0000000..f1f95e8
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.Preferences.js
@@ -0,0 +1,48 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Header.Preferences depends on Clipperz.PM.DataModel.User!";
26}
27
28if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
29
30Clipperz.PM.DataModel.User.Header.Preferences = function(args) {
31 Clipperz.PM.DataModel.User.Header.Preferences.superclass.constructor.apply(this, arguments);
32
33 return this;
34}
35
36
37Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.Preferences, Clipperz.PM.DataModel.EncryptedRemoteObject, {
38
39 'toString': function() {
40 return "Clipperz.PM.DataModel.User.Header.Preferences";
41 },
42
43 //-------------------------------------------------------------------------
44 //=========================================================================
45 __syntaxFix__: "syntax fix"
46});
47
48
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js
new file mode 100644
index 0000000..5681f70
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js
@@ -0,0 +1,685 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Header.RecordIndex depends on Clipperz.PM.DataModel.User!";
26}
27
28if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
29
30Clipperz.PM.DataModel.User.Header.RecordIndex = function(args) {
31 Clipperz.PM.DataModel.User.Header.RecordIndex.superclass.constructor.apply(this, arguments);
32
33 this._recordsData = new Clipperz.PM.DataModel.EncryptedRemoteObject({
34 'name':'recordsData',
35 'retrieveKeyFunction': args.retrieveKeyFunction,
36 'remoteData': {
37 'data': args.recordsData['data'],
38 'version': args.encryptedDataVersion,
39 'recordsStats': args.recordsStats
40 }//,
41 // 'encryptedDataKeypath': 'data',
42 // 'encryptedVersionKeypath': 'version'
43 });
44
45 this._directLoginsData = new Clipperz.PM.DataModel.EncryptedRemoteObject({
46 'name':'directLoginsData',
47 'retrieveKeyFunction': args.retrieveKeyFunction,
48 'remoteData': {
49 'data': args.directLoginsData['data'],
50 'version': args.encryptedDataVersion
51 }//,
52 // 'encryptedDataKeypath': 'data',
53 // 'encryptedVersionKeypath': 'version'
54 });
55
56 this._lock = new MochiKit.Async.DeferredLock();
57 this._transientState = null;
58
59 this._retrieveRecordDetailFunction = args.retrieveRecordDetailFunction|| Clipperz.Base.exception.raise('MandatoryParameter');
60 this._recordsIndex = args.recordsData['index'] || Clipperz.Base.exception.raise('MandatoryParameter');
61 this._directLoginsIndex = args.directLoginsData['index']|| Clipperz.Base.exception.raise('MandatoryParameter');
62
63 this._records = null;
64
65 return this;
66}
67
68
69Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.RecordIndex, Object, {
70
71 'toString': function() {
72 return "Clipperz.PM.DataModel.User.Header.RecordIndex";
73 },
74
75 //-------------------------------------------------------------------------
76
77 'retrieveRecordDetailFunction': function () {
78 return this._retrieveRecordDetailFunction;
79 },
80
81 //-------------------------------------------------------------------------
82
83 'recordsIndex': function () {
84 return this._recordsIndex;
85 },
86
87 'recordsData': function () {
88 return this._recordsData;
89 },
90
91 //-------------------------------------------------------------------------
92
93 'directLoginsIndex': function () {
94 return this._directLoginsIndex;
95 },
96
97 'directLoginsData': function () {
98 return this._directLoginsData;
99 },
100
101 //-------------------------------------------------------------------------
102
103 'lock': function () {
104 return this._lock;
105 },
106
107 //-------------------------------------------------------------------------
108
109 'transientState': function () {
110 if (this._transientState == null) {
111 this._transientState = new Clipperz.KeyValueObjectStore(/*{'name':'User.Header.RecordIndex.transientState [1]'}*/);
112 }
113
114 return this._transientState;
115 },
116
117 'resetTransientState': function (isCommitting) {
118 if (this._transientState != null) {
119 this._transientState.removeAllData();
120 }
121
122 this._transientState = null;
123 },
124
125 //-------------------------------------------------------------------------
126
127 'getRecordKey': function (aRecordReference) {
128 return Clipperz.Async.callbacks("User.Header.RecordIndex.getRecordKey", [
129 MochiKit.Base.method(this, 'getRecordIndexData', aRecordReference),
130 MochiKit.Base.itemgetter('key')
131 ], {trace:false});
132 },
133
134 'setRecordKey': function (aRecordReference, aValue) {
135 return this.updateRecordIndexData(aRecordReference, 'key', aValue);
136 },
137
138 //-------------------------------------------------------------------------
139
140 'getRecordIndexData': function (aRecordReference) {
141 return this.recordsData().getValue(this.recordsIndex()[aRecordReference]);
142 },
143
144 //.........................................................................
145
146 'updateRecordIndexData': function (aRecordReference, aKey, aValue) {
147 return this.recordsData().setValue(this.recordsIndex()[aRecordReference]+'.'+aKey, aValue);
148 },
149
150 //-------------------------------------------------------------------------
151
152 'getDirectLoginIndexData': function (aDirectLoginReference) {
153 return this.directLoginsData().getValue(this.directLoginsIndex()[aDirectLoginReference]);
154 },
155
156 'setDirectLoginIndexData': function (aDirectLoginReference, aKey, aValue) {
157//if (MochiKit.Base.isUndefinedOrNull(this.directLoginsIndex()[aDirectLoginReference])) {
158 //throw "PIPPO";
159//}
160 return this.directLoginsData().setValue(this.directLoginsIndex()[aDirectLoginReference] + '.' + aKey, aValue);
161 },
162
163 'addDirectLoginIndexData': function (aDirectLoginReference) {
164 return this.directLoginsData().setValue(this.directLoginsIndex()[aDirectLoginReference], {});
165 },
166
167 'removeDirectLoginIndexData': function (aDirectLoginReference) {
168 return this.directLoginsData().removeValue(this.directLoginsIndex()[aDirectLoginReference])
169 },
170
171 //-------------------------------------------------------------------------
172
173 'records': function () {
174 vardeferredResult;
175
176 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.records", {trace:false});
177 deferredResult.acquireLock(this.lock());
178 deferredResult.addCallback(MochiKit.Base.bind(function () {
179 var innerDeferredResult;
180
181 if (this._records == null) {
182 innerDeferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.records <inner deferred>", {trace:false});
183 innerDeferredResult.collectResults({
184 'records': [
185 // MochiKit.Base.method(this.recordsData(), 'getObjectDataStore'),
186 // MochiKit.Base.methodcaller('values')
187 MochiKit.Base.method(this.recordsData(), 'values')
188 ],
189 'recordsStats': [
190 MochiKit.Base.method(this.recordsData(), 'getRemoteData'),
191 MochiKit.Base.itemgetter('recordsStats')
192 ],
193 'directLogins': [
194 // MochiKit.Base.method(this.directLoginsData(), 'getObjectDataStore'),
195 // MochiKit.Base.methodcaller('values')
196 MochiKit.Base.method(this.directLoginsData(), 'values')
197 ]
198 })
199 innerDeferredResult.addCallback(MochiKit.Base.bind(function (someData) {
200 var indexReference;
201 var recordsInvertedIndex;
202 var directLoginsInvertedIndex;
203
204 recordsInvertedIndex = Clipperz.PM.DataModel.User.Header.RecordIndex.invertIndex(this.recordsIndex());
205 directLoginsInvertedIndex= Clipperz.PM.DataModel.User.Header.RecordIndex.invertIndex(this.directLoginsIndex());
206
207 this._records = {};
208
209 for (indexReference in someData['records']) {
210 varrecord;
211 var reference;
212 var updateDate;
213
214 reference = recordsInvertedIndex[indexReference];
215
216 if (typeof(someData['recordsStats'][reference]) != 'undefined') {
217 updateDate = someData['recordsStats'][reference]['updateDate'];
218
219 record = new Clipperz.PM.DataModel.Record({
220 'reference': reference,
221 'retrieveKeyFunction': MochiKit.Base.method(this, 'getRecordKey'),
222 'retrieveRemoteDataFunction':this.retrieveRecordDetailFunction(),
223
224 'retrieveIndexDataFunction':MochiKit.Base.method(this, 'getRecordIndexData'),
225 'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
226 'updateDate': updateDate,
227
228 'retrieveDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'getDirectLoginIndexData'),
229 'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
230 'removeDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'removeDirectLoginIndexData'),
231
232 'createNewDirectLoginFunction': MochiKit.Base.method(this, 'createNewDirectLogin')
233 });
234
235 this._records[reference] = record;
236 } else {
237Clipperz.log("SKIPPING record " + reference + " as there are no stas associated - " + Clipperz.Base.serializeJSON(someData['records'][reference]));
238 //# skip the record, as it seems it is not present in the DB
239 //updateDate = Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
240 }
241 }
242
243 for (indexReference in someData['directLogins']) {
244 // vardirectLogin;
245 var reference;
246 var record;
247
248 reference = directLoginsInvertedIndex[indexReference];
249 record = this._records[recordsInvertedIndex[someData['directLogins'][indexReference]['record']]];
250
251 if (record != null) {
252 // directLogin = new Clipperz.PM.DataModel.DirectLogin({
253 new Clipperz.PM.DataModel.DirectLogin({
254 'reference': reference,
255 'record': record
256 });
257 } else {
258 Clipperz.logWarning("WARNING: DIRECT LOGIN without a matching RECORD!!");
259 }
260 }
261
262 return this._records;
263 }, this));
264 innerDeferredResult.callback();
265 } else {
266 innerDeferredResult = MochiKit.Async.succeed(this._records);
267 }
268
269 return innerDeferredResult;
270 }, this));
271 deferredResult.releaseLock(this.lock());
272 deferredResult.callback();
273
274 return deferredResult;
275 },
276
277 //-------------------------------------------------------------------------
278
279 'updateRecordIndexForNewRecord': function (aNewRecord) {
280 var newRecordIndex;
281 var recordReference;
282
283 recordReference = aNewRecord.reference();
284 newRecordIndex = (MochiKit.Base.listMax(MochiKit.Base.map(MochiKit.Base.partial(MochiKit.Base.operator.mul, 1), MochiKit.Base.values(this.recordsIndex()))) + 1) + '';
285 this.recordsIndex()[recordReference] = newRecordIndex;
286
287 this.transientState().setValue('newlyCreatedRecordsIndex' + '.' + recordReference, newRecordIndex);
288 this.transientState().setValue('newlyCreatedRecordsReferences'+ '.' + recordReference, aNewRecord);
289 },
290
291 //.........................................................................
292
293 'createNewRecord': function () {
294 var deferredResult;
295 var newRecord;
296
297 newRecord = new Clipperz.PM.DataModel.Record({
298 'retrieveKeyFunction': MochiKit.Base.method(this, 'getRecordKey'),
299 'retrieveRemoteDataFunction':this.retrieveRecordDetailFunction(),
300
301 'retrieveIndexDataFunction':MochiKit.Base.method(this, 'getRecordIndexData'),
302 'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
303 'updateDate': Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
304
305 'retrieveDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'getDirectLoginIndexData'),
306 'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
307 'removeDirectLoginIndexDataFunction':MochiKit.Base.method(this, 'removeDirectLoginIndexData'),
308
309 'createNewDirectLoginFunction': MochiKit.Base.method(this, 'createNewDirectLogin')
310 });
311
312 this.transientState().setValue('newRecordsReferences' + '.' + newRecord.reference(), newRecord);
313 this.updateRecordIndexForNewRecord(newRecord);
314
315 deferredResult = Clipperz.Async.callbacks("User.Header.RecordIndex.createNewRecord", [
316 MochiKit.Base.method(this, 'records'),
317 MochiKit.Base.partial(Clipperz.Async.setItemOnObject, newRecord.reference(), newRecord),
318 MochiKit.Base.method(this, 'setRecordKey', newRecord.reference(), Clipperz.PM.Crypto.randomKey()),
319 MochiKit.Base.method(newRecord, 'setLabel', ''),
320 MochiKit.Base.partial(MochiKit.Async.succeed, newRecord)
321 ], {trace:false});
322
323
324 return deferredResult;
325 },
326
327 //-------------------------------------------------------------------------
328
329 'deleteRecord': function (aRecord) {
330 var deferredResult;
331 var recordReference;
332
333 recordReference = aRecord.reference();
334
335 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.deleteRecord", {trace:false});
336
337 deferredResult.addMethod(aRecord, 'directLogins');
338 deferredResult.addCallback(MochiKit.Base.values);
339 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'removeDirectLogin'));
340
341 deferredResult.addMethod(this.recordsData(), 'removeValue', this.recordsIndex()[recordReference]);
342 deferredResult.addCallback(MochiKit.Base.bind(function () {
343 this.transientState().setValue('deleteRecordsIndex' + '.' + recordReference, this.recordsIndex()[recordReference]);
344 delete this.recordsIndex()[recordReference];
345 }, this));
346
347 deferredResult.addMethod(this, 'records');
348 deferredResult.addCallback(MochiKit.Base.itemgetter(recordReference));
349 deferredResult.addMethod(this.transientState(), 'setValue', 'deleteRecordsReferences' + '.' + recordReference);
350
351 deferredResult.addMethod(this, 'records');
352 deferredResult.addCallback(MochiKit.Base.bind(function (someRecords) {
353 delete someRecords[recordReference];
354 }, this));
355 deferredResult.callback();
356
357 return deferredResult;
358 },
359
360 //=========================================================================
361
362 'removeDirectLogin': function (aDirectLogin) {
363 this.directLoginsData().removeValue(this.directLoginsIndex()[aDirectLogin.reference()]);
364 },
365
366 //-------------------------------------------------------------------------
367
368 'createNewDirectLogin': function (aRecord) {
369 var newDirectLogin;
370 varnewDirectLoginIndexValue;
371
372 newDirectLogin = new Clipperz.PM.DataModel.DirectLogin({record:aRecord});
373 newDirectLoginIndexValue = MochiKit.Base.listMax(MochiKit.Base.map(function (aValue) { return aValue * 1; }, MochiKit.Base.values(this.directLoginsIndex()))) + 1;
374
375 this.transientState().setValue('newDirectLoginReferences' + '.' + newDirectLogin.reference(), newDirectLogin);
376
377 this.directLoginsIndex()[newDirectLogin.reference()] = newDirectLoginIndexValue;
378 this.directLoginsData().setValue(this.directLoginsIndex()[newDirectLogin.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
379
380 return newDirectLogin;
381 },
382
383 //=========================================================================
384
385 'deleteAllCleanTextData': function () {
386 return Clipperz.Async.callbacks("User.Header.RecordIndex.deleteAllCleanTextData", [
387 // MochiKit.Base.method(this, 'records'),
388 // MochiKit.Base.values,
389 // MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('deleteAllCleanTextData')),
390
391 MochiKit.Base.method(this, 'recordsData'),
392 MochiKit.Base.methodcaller('deleteAllCleanTextData'),
393 MochiKit.Base.method(this, 'directLoginsData'),
394 MochiKit.Base.methodcaller('deleteAllCleanTextData')
395 ], {trace:false});
396 },
397
398 //-------------------------------------------------------------------------
399
400 'hasAnyCleanTextData': function () {
401 var deferredResult;
402
403 deferredResult = new Clipperz.Async.Deferred({trace:false});
404 deferredResult.collectResults({
405 'recordsData': [
406 MochiKit.Base.method(this, 'recordsData'),
407 MochiKit.Base.methodcaller('hasAnyCleanTextData')
408 ],
409 'directLoginsData':[
410 MochiKit.Base.method(this, 'directLoginsData'),
411 MochiKit.Base.methodcaller('hasAnyCleanTextData')
412 ],
413 // 'records': [
414 // MochiKit.Base.method(this, 'records'),
415 // MochiKit.Base.values,
416 // MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasAnyCleanTextData')),
417 // Clipperz.Async.collectAll
418 // ]
419 });
420
421 // deferredResult.addCallback(MochiKit.Base.values);
422 // deferredResult.addCallback(MochiKit.Base.flattenArguments);
423 // deferredResult.addCallback(function(someValues) {
424 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
425 // });
426 deferredResult.addCallback(Clipperz.Async.or);
427
428 deferredResult.callback();
429
430 return deferredResult;
431 },
432
433 //-------------------------------------------------------------------------
434
435 'hasPendingChanges': function () {
436 vardeferredResult;
437
438 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.hasPendingChanges", {trace:false});
439 deferredResult.collectResults({
440 'recordsData': [
441 MochiKit.Base.method(this, 'recordsData'),
442 MochiKit.Base.methodcaller('hasPendingChanges')
443 ],
444 'directLoginsData': [
445 MochiKit.Base.method(this, 'directLoginsData'),
446 MochiKit.Base.methodcaller('hasPendingChanges')
447 ]
448 });
449 deferredResult.addCallback(Clipperz.Async.or);
450 // deferredResult.addCallback(MochiKit.Base.values);
451 // deferredResult.addCallback(MochiKit.Base.flattenArguments);
452 // deferredResult.addCallback(function(someValues) {
453 // return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
454 // });
455 deferredResult.callback();
456
457 return deferredResult;
458 },
459
460 //-------------------------------------------------------------------------
461
462 'commitTransientState': function () {
463 var deferredResult;
464
465 deferredResut = Clipperz.Async.callbacks("User.Header.RecordIndex.commitTransientState", [
466 MochiKit.Base.method(this, 'recordsData'),
467 MochiKit.Base.methodcaller('commitTransientState'),
468
469 MochiKit.Base.method(this, 'directLoginsData'),
470 MochiKit.Base.methodcaller('commitTransientState'),
471
472 MochiKit.Base.method(this, 'resetTransientState', true)
473 ], {trace:false});
474
475 return deferredResult;
476 },
477
478 //-------------------------------------------------------------------------
479
480 'revertChanges': function () {
481 return Clipperz.Async.callbacks("User.Header.RecordIndex.revertChanges", [
482 MochiKit.Base.method(this, 'recordsData'),
483 MochiKit.Base.methodcaller('revertChanges'),
484
485 // MochiKit.Base.method(this, 'directLoginsData'),
486 // MochiKit.Base.methodcaller('revertChanges'),
487
488 MochiKit.Base.method(this, 'records'),
489 MochiKit.Base.bind(function (someRecords) {
490 varrecordReference;
491
492 for (recordReference in this.transientState().getValue('deleteRecordsReferences')) {
493 this.recordsIndex()[recordReference] = this.transientState().getValue('deleteRecordsIndex' + '.' + recordReference);
494 someRecords[recordReference] = this.transientState().getValue('deleteRecordsReferences' + '.' + recordReference);
495 }
496
497 for (recordReference in this.transientState().getValue('newRecordsReferences')) {
498 delete this.recordsIndex()[recordReference];
499 delete someRecords[recordReference];
500 }
501 }, this),
502
503 // MochiKit.Base.method(this, 'directLogins'),
504 MochiKit.Base.bind(function () {
505 vardirectLoginReference;
506
507 //this.transientState().setValue('newDirectLoginReferences' + '.' + newDirectLogin.reference(), newDirectLogin);
508//
509 //this.directLoginsIndex()[newDirectLogin.reference()] = newDirectLoginIndexValue;
510 //this.directLoginsData().setValue(this.directLoginsIndex()[newDirectLogin.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
511
512
513 // for (directLoginReference in this.transientState().getValue('deleteDirectLoginReferences')) {
514 // someDirectLogins[directLoginReference] = this.transientState().getValue('deleteDirectLoginReferences' + '.' + recordReference);
515 // }
516
517 for (directLoginReference in this.transientState().getValue('newDirectLoginReferences')) {
518 // this.directLoginsData().removeValue(this.directLoginsIndex()[directLoginReference]);
519 delete this.directLoginsIndex()[directLoginReference];
520 }
521 }, this),
522
523 MochiKit.Base.method(this, 'directLoginsData'),
524 MochiKit.Base.methodcaller('revertChanges'),
525
526 MochiKit.Base.method(this, 'resetTransientState', false)
527 ], {trace:false});
528 },
529
530 //-------------------------------------------------------------------------
531
532 'prepareRemoteDataWithKey': function (aKey) {
533 // "records": {
534 // "index": {
535 // "eeda70e0392261967bda71c3764da78989c45bbd2bb7be6b941b90f81d9b81b5": "0",
536 // "13a5e52976337ab210903cd04872588e1b21fb72bc183e91aa25c494b8138551": "1",
537 // ...
538 // "465a067a0bd2b470fa834de5397e38494de0c7707938262fae3427932e219744": "18",
539 // "4fd1dc2ca860b7fb47cef10a84edb3270da05510b0a30a6b0b083898712d4b9e": "19"
540 // },
541 // "data": "n+AzGEEQXaSRSY4d ... BDypotrXgPo94uHfoXvGFzwCn8w="
542 // },
543 // "directLogins": {
544 // "index": {
545 // "61e87fdc4f1d9112e3b30c1f6812d095dcdb24f014c83319091eb6c9899ec348":"0",
546 // "989593d4c48929f0c8f1581aa96969c622807e99619ed4732026e967530a68ad":"1",
547 // ...
548 // "cb9ae0bba1957075ccdbfd3b3481704d62087687a2ac7c411a4f07d444bde0f7":"17",
549 // "7e1d069b7fa57c03bd7bf48807520feb953157834503aaff8c9d493f37dea69d":"18"
550 // },
551 // "data":"5YG9KKU/OZ5guUgFlms6k1 ... ZG/5Fn0uN+LoAsNfHm+EE62x"
552 // },
553
554 var deferredResult;
555 var result;
556
557 result = {};
558
559 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.prepareRemoteDataWithKey", {trace:false});
560 deferredResult.collectResults({
561 'index':MochiKit.Base.partial(MochiKit.Async.succeed, this.recordsIndex()),
562 'data': [
563 MochiKit.Base.method(this.recordsData(), 'prepareRemoteDataWithKey', aKey),
564 MochiKit.Base.itemgetter('data')
565 ]
566 });
567 deferredResult.addCallback(Clipperz.Async.setItem, result, 'records');
568
569 deferredResult.collectResults({
570 'index':MochiKit.Base.partial(MochiKit.Async.succeed, this.directLoginsIndex()),
571 'data': [
572 MochiKit.Base.method(this.directLoginsData(), 'prepareRemoteDataWithKey', aKey),
573 MochiKit.Base.itemgetter('data')
574 ]
575 });
576 deferredResult.addCallback(Clipperz.Async.setItem, result, 'directLogins');
577
578 deferredResult.addCallback(MochiKit.Async.succeed, result);
579
580 deferredResult.callback();
581
582 return deferredResult;
583 },
584
585 //-------------------------------------------------------------------------
586
587 'updateRecordKeyAndPrepareRemoteData': function (aRecord) {
588 varnewRecordKey;
589 var deferredResult;
590
591 newRecordKey = Clipperz.PM.Crypto.randomKey();
592
593 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.updateRecordKeyAndPrepareRemoteData", {trace:false});
594 deferredResult.addCallback(MochiKit.Base.method(aRecord, 'prepareRemoteDataWithKey', newRecordKey));
595 deferredResult.addCallbackPass(MochiKit.Base.method(this, 'setRecordKey', aRecord.reference(), newRecordKey));
596 deferredResult.callback();
597
598 return deferredResult;
599 },
600
601 //.........................................................................
602
603 'removeNewRecordWithNoChanges': function (aRecord) {
604 var deferredResult;
605 var recordReference;
606
607 recordReference = aRecord.reference();
608
609 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.removeNewRecordWithNoChanges", {trace:false});
610
611 deferredResult.addMethod(this.recordsData(), 'removeValue', this.recordsIndex()[recordReference]);
612 deferredResult.addCallback(MochiKit.Base.bind(function () {
613 delete this.recordsIndex()[recordReference];
614 }, this));
615
616 deferredResult.addMethod(this, 'records');
617 deferredResult.addCallback(MochiKit.Base.bind(function (someRecords) {
618 delete someRecords[recordReference];
619 }, this));
620 deferredResult.callback();
621
622 return deferredResult;
623 },
624
625 //.........................................................................
626
627 'prepareRemoteDataForChangedRecords': function () {
628 vardeferredResult;
629 varresult;
630
631 result = {};
632
633 deferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.prepareRemoteDataForChangedRecords", {trace:false});
634
635 deferredResult.addMethod(this, 'records');
636 deferredResult.addCallback(MochiKit.Base.values);
637 deferredResult.addCallback(Clipperz.Async.deferredFilter, MochiKit.Base.methodcaller('isBrandNewWithNoPendingChanges'));
638 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'removeNewRecordWithNoChanges'));
639
640 deferredResult.addMethod(this, 'records');
641 deferredResult.addCallback(MochiKit.Base.values);
642 deferredResult.addCallback(Clipperz.Async.deferredFilter, MochiKit.Base.methodcaller('hasPendingChanges'));
643 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'updateRecordKeyAndPrepareRemoteData'));
644 deferredResult.addCallback(Clipperz.Async.collectAll);
645
646 deferredResult.addCallback(Clipperz.Async.deferredIf("updated records != null", [
647 MochiKit.Base.operator.identity
648 ], [
649 MochiKit.Base.partial(MochiKit.Async.succeed, [])
650 ]));
651 deferredResult.addCallback(Clipperz.Async.setItem, result, 'updated');
652
653 deferredResult.addMethod(this.transientState(), 'getValue', 'deleteRecordsReferences');
654 deferredResult.addCallback(MochiKit.Base.keys);
655 deferredResult.addCallback(Clipperz.Async.deferredIf("deleted records != null", [
656 MochiKit.Base.operator.identity
657 ], [
658 MochiKit.Base.partial(MochiKit.Async.succeed, [])
659 ]));
660 deferredResult.addCallback(Clipperz.Async.setItem, result, 'deleted');
661
662 deferredResult.addCallback(MochiKit.Async.succeed, result);
663 deferredResult.callback();
664
665 return deferredResult;
666 },
667
668 //-------------------------------------------------------------------------
669 __syntaxFix__: "syntax fix"
670});
671
672
673
674Clipperz.PM.DataModel.User.Header.RecordIndex.invertIndex = function (anIndex) {
675 var result;
676 var key;
677
678 result = {};
679
680 for (key in anIndex) {
681 result[anIndex[key]] = key;
682 }
683
684 return result;
685}; \ No newline at end of file
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Subscription.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Subscription.js
new file mode 100644
index 0000000..341e9f3
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Subscription.js
@@ -0,0 +1,53 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.DataModel.User.Subscription depends on Clipperz.PM.DataModel.User!";
26}
27
28Clipperz.PM.DataModel.User.Subscription = function(args) {
29 this._attributes = args;
30 return this;
31}
32
33
34Clipperz.Base.extend(Clipperz.PM.DataModel.User.Subscription, Object, {
35
36 'features': function () {
37 return this._attributes['features'];
38 },
39
40 'type': function () {
41 return this._attributes['type'];
42 },
43
44 'validity': function () {
45 return {
46 'from':this._attributes['fromDate'],
47 'to':this._attributes['toDate']
48 };
49 },
50
51 //=========================================================================
52 __syntaxFix__: "syntax fix"
53});
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.js b/frontend/delta/js/Clipperz/PM/DataModel/User.js
new file mode 100644
index 0000000..1d90800
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/User.js
@@ -0,0 +1,827 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
27
28
29//#############################################################################
30
31Clipperz.PM.DataModel.User = function (args) {
32 args = args || {};
33
34 Clipperz.PM.DataModel.User.superclass.constructor.apply(this, arguments);
35
36 this._username = args.username || null;
37 this._getPassphraseFunction = args.getPassphraseFunction || null;
38
39 this._data = null;
40
41 this._connection = null;
42 this._connectionVersion = 'current';
43
44 this._subscription = null;
45 this._serverData = null;
46 //this._serverLockValue = null;
47 this._transientState = null;
48
49 this._deferredLocks = {
50 'passphrase': new MochiKit.Async.DeferredLock(),
51 'serverData': new MochiKit.Async.DeferredLock(),
52 // 'recordsIndex': new MochiKit.Async.DeferredLock(),
53 // 'directLoginsIndex':new MochiKit.Async.DeferredLock()
54 // 'preferences': new MochiKit.Async.DeferredLock()
55 // 'oneTimePasswords': new MochiKit.Async.DeferredLock()
56 '__syntaxFix__': 'syntax fix'
57 };
58
59 return this;
60}
61
62Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
63
64 'toString': function () {
65 return "Clipperz.PM.DataModel.User - " + this.username();
66 },
67
68 //-------------------------------------------------------------------------
69
70 'username': function () {
71 return this._username;
72 },
73
74 'setUsername': function (aValue) {
75 this._username = aValue;
76 },
77
78 //-------------------------------------------------------------------------
79
80 //this.setSubscription(new Clipperz.PM.DataModel.User.Subscription(someServerData['subscription']));
81 'subscription': function () {
82 return this._subscription;
83 },
84
85 'setSubscription': function (aValue) {
86 this._subscription = aValue;
87 },
88
89 //-------------------------------------------------------------------------
90
91 'displayName': function() {
92 return "" + this.username() + "";
93 },
94
95 //-------------------------------------------------------------------------
96
97 'data': function () {
98 if (this._data == null) {
99 this._data = new Clipperz.KeyValueObjectStore(/*{'name':'User.data [1]'}*/);
100 };
101
102 return this._data;
103 },
104
105 //-------------------------------------------------------------------------
106/*
107 'serverLockValue': function () {
108 return this._serverLockValue;
109 },
110
111 'setServerLockValue': function (aValue) {
112 this._serverLockValue = aValue;
113 },
114*/
115 //-------------------------------------------------------------------------
116
117 'transientState': function () {
118 if (this._transientState == null) {
119 this._transientState = {}
120 }
121
122 return this._transientState;
123 },
124
125 'resetTransientState': function (isCommitting) {
126 this._transientState = null;
127 },
128
129 //-------------------------------------------------------------------------
130
131 'deferredLockForSection': function(aSectionName) {
132 return this._deferredLocks[aSectionName];
133 },
134
135 //-------------------------------------------------------------------------
136
137 'getPassphrase': function() {
138 var deferredResult;
139
140 deferredResult = new Clipperz.Async.Deferred("User.getPassphrase", {trace:false});
141 deferredResult.acquireLock(this.deferredLockForSection('passphrase'));
142 deferredResult.addMethod(this.data(), 'deferredGetOrSet', 'passphrase', this.getPassphraseFunction());
143 deferredResult.releaseLock(this.deferredLockForSection('passphrase'));
144 deferredResult.callback();
145
146 return deferredResult;
147 },
148
149 'getPassphraseFunction': function () {
150 return this._getPassphraseFunction;
151 },
152
153 //-------------------------------------------------------------------------
154
155 'getCredentials': function () {
156 return Clipperz.Async.collectResults("User; get username and passphrase", {
157 'username': MochiKit.Base.method(this, 'username'),
158 'password': MochiKit.Base.method(this, 'getPassphrase')
159 }, {trace:false})();
160 },
161
162 //-------------------------------------------------------------------------
163
164 'changePassphrase': function (aNewValue) {
165 return this.updateCredentials(this.username(), aNewValue);
166 },
167
168 //.........................................................................
169
170 'updateCredentials': function (aUsername, aPassphrase) {
171 vardeferredResult;
172
173 deferredResult = new Clipperz.Async.Deferred("User.updateCredentials", {trace:false});
174 // deferredResult.addMethod(this, 'getPassphrase');
175 // deferredResult.setValue('currentPassphrase');
176 deferredResult.addMethod(this.connection(), 'ping');
177 deferredResult.addMethod(this, 'setUsername', aUsername)
178 deferredResult.acquireLock(this.deferredLockForSection('passphrase'));
179 deferredResult.addMethod(this.data(), 'deferredGetOrSet', 'passphrase', aPassphrase);
180 deferredResult.releaseLock(this.deferredLockForSection('passphrase'));
181 // deferredResult.getValue('currentPassphrase');
182 deferredResult.addMethod(this, 'prepareRemoteDataWithKey', aPassphrase);
183 deferredResult.addMethod(this.connection(), 'updateCredentials', aUsername, aPassphrase);
184 deferredResult.callback();
185
186 return deferredResult;
187 },
188
189 //-------------------------------------------------------------------------
190
191 'initialSetupWithNoData': function () {
192 this._serverData = {
193 'version': '0.1',
194 'statistics': "",
195 'header': {
196 'data': null,
197 'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion,
198
199 'recordsIndex': new Clipperz.PM.DataModel.User.Header.RecordIndex({
200 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
201 'recordsData': {'data':null, 'index':{}},
202 'recordsStats': null,
203 'directLoginsData': {'data':null, 'index':{}},
204 'encryptedDataVersion': Clipperz.PM.Crypto.encryptingFunctions.currentVersion,
205 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail')
206 }),
207 'preferences': new Clipperz.PM.DataModel.User.Header.Preferences({
208 'name':'preferences',
209 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
210 }),
211 'oneTimePasswords': new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
212 'name':'preferences',
213 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
214 })
215 }
216 };
217
218 // this._serverLockValue = Clipperz.PM.Crypto.randomKey();
219 },
220
221 //.........................................................................
222
223 'registerAsNewAccount': function () {
224 var deferredResult;
225
226 deferredResult = new Clipperz.Async.Deferred("User.registerAsNewAccount", {trace:false});
227 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':3});
228 deferredResult.addMethod(this, 'initialSetupWithNoData')
229 deferredResult.addMethod(this, 'getPassphrase');
230 deferredResult.addMethod(this, 'prepareRemoteDataWithKey');
231 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
232 deferredResult.addMethod(this.connection(), 'register');
233 // deferredResult.addCallback(MochiKit.Base.itemgetter('lock'));
234 // deferredResult.addMethod(this, 'setServerLockValue');
235 // deferredResult.addCallbackPass(MochiKit.Signal.signal,Clipperz.Signal.NotificationCenter, 'userSuccessfullyRegistered');
236
237 // deferredResult.addErrback (MochiKit.Base.method(this, 'handleRegistrationFailure'));
238
239 deferredResult.callback();
240
241 return deferredResult;
242 },
243
244 //-------------------------------------------------------------------------
245
246 'login': function () {
247 var deferredResult;
248
249 deferredResult = new Clipperz.Async.Deferred("User.login", {trace:false});
250 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':3});
251 deferredResult.addMethod(this, 'getPassphrase');
252 deferredResult.addCallback(Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue);
253 deferredResult.addCallback(Clipperz.Async.deferredIf("Is the passphrase an OTP", [
254 // MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':1}),
255 MochiKit.Base.method(this, 'getCredentials'),
256 MochiKit.Base.method(this.connection(), 'redeemOneTimePassword'),
257 MochiKit.Base.method(this.data(), 'setValue', 'passphrase')
258 ], []));
259 deferredResult.addErrback(MochiKit.Base.method(this, 'getPassphrase'));
260 deferredResult.addMethod(this.connection(), 'login', false);
261 deferredResult.addMethod(this, 'setupConnectionInfo');
262 // deferredResult.addCallbackPass(MochiKit.Signal.signal,Clipperz.Signal.NotificationCenter, 'userSuccessfullyLoggedIn');
263 deferredResult.addErrback (MochiKit.Base.method(this, 'handleConnectionFallback'));
264
265 deferredResult.callback();
266
267 return deferredResult;
268 },
269
270 //.........................................................................
271
272 'handleConnectionFallback': function(aValue) {
273 var result;
274
275//console.log("USER - handleConnectionFallback", aValue, aValue['isPermanent']);
276 if (aValue instanceof MochiKit.Async.CancelledError) {
277 result = aValue;
278 } else if ((aValue['isPermanent'] === true) || (Clipperz.PM.Connection.communicationProtocol.fallbackVersions[this.connectionVersion()] == null)) {
279 result = Clipperz.Async.callbacks("User.handleConnectionFallback - failed", [
280 MochiKit.Base.method(this.data(), 'removeValue', 'passphrase'),
281 MochiKit.Base.method(this, 'setConnectionVersion', 'current'),
282 // MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userLoginFailed'),
283 // MochiKit.Base.partial(MochiKit.Async.fail, Clipperz.PM.DataModel.User.exception.LoginFailed)
284 MochiKit.Base.partial(MochiKit.Async.fail, aValue)
285 ], {trace:false});
286 } else {
287 this.setConnectionVersion(Clipperz.PM.Connection.communicationProtocol.fallbackVersions[this.connectionVersion()]);
288 result = new Clipperz.Async.Deferred("User.handleConnectionFallback - retry");
289 result.addMethod(this, 'login');
290 result.callback();
291 }
292
293 return result;
294 },
295
296 //-------------------------------------------------------------------------
297
298 'setupConnectionInfo': function (aValue) {
299 // this.setLoginInfo(aValue['loginInfo']);
300 this.setSubscription(new Clipperz.PM.DataModel.User.Subscription(aValue['subscription']));
301 },
302
303 //-------------------------------------------------------------------------
304
305 'lock': function () {
306 return Clipperz.Async.callbacks("User.lock", [
307 MochiKit.Base.method(this, 'deleteAllCleanTextData')
308 ], {trace:false});
309 },
310
311 //-------------------------------------------------------------------------
312
313 'logout': function () {
314 return Clipperz.Async.callbacks("User.logout", [
315 MochiKit.Base.method(this, 'deleteAllCleanTextData'),
316 MochiKit.Base.method(this.connection(), 'logout')
317 ], {trace:false});
318 },
319
320 //-------------------------------------------------------------------------
321
322 'headerFormatVersion': function(anHeader) {
323 var result;
324
325 if (anHeader.charAt(0) == '{') {
326 varheaderData;
327
328 headerData = Clipperz.Base.evalJSON(anHeader);
329 result = headerData['version'];
330 } else {
331 result = 'LEGACY';
332 }
333
334 return result;
335 },
336
337 //-------------------------------------------------------------------------
338
339 'unpackServerData': function (someServerData) {
340 var unpackedData;
341 var headerVersion;
342
343 varrecordsIndex;
344 var preferences;
345 var oneTimePasswords;
346
347 // this.setServerLockValue(someServerData['lock']);
348
349 headerVersion = this.headerFormatVersion(someServerData['header']);
350 switch (headerVersion) {
351 case 'LEGACY':
352 varlegacyHeader;
353
354 legacyHeader = new Clipperz.PM.DataModel.User.Header.Legacy({
355 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
356 'remoteData': {
357 'data': someServerData['header'],
358 'version': someServerData['version'],
359 'recordsStats': someServerData['recordsStats']
360 },
361 // 'encryptedDataKeypath': 'data',
362 // 'encryptedVersionKeypath': 'version',
363 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail')
364 });
365
366 recordsIndex = legacyHeader;
367 preferences = legacyHeader;
368 oneTimePasswords= legacyHeader;
369 break;
370 case '0.1':
371 varheaderData;
372
373 headerData = Clipperz.Base.evalJSON(someServerData['header']);
374
375 recordsIndex = new Clipperz.PM.DataModel.User.Header.RecordIndex({
376 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
377 'recordsData': headerData['records'],
378 'recordsStats': someServerData['recordsStats'],
379 'directLoginsData': headerData['directLogins'],
380 'encryptedDataVersion': someServerData['version'],
381 'retrieveRecordDetailFunction':MochiKit.Base.method(this, 'getRecordDetail')
382 });
383
384 //Still missing a test case that actually fais with the old version of the code, where the check for undefined was missing
385 if (typeof(headerData['preferences']) != 'undefined') {
386 preferences= new Clipperz.PM.DataModel.User.Header.Preferences({
387 'name':'preferences',
388 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
389 'remoteData': {
390 'data': headerData['preferences']['data'],
391 'version': someServerData['version']
392 }
393 });
394 } else {
395 preferences= new Clipperz.PM.DataModel.User.Header.Preferences({
396 'name':'preferences',
397 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
398 });
399 }
400
401 if (typeof(headerData['oneTimePasswords']) != 'undefined') {
402 oneTimePasswords = new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
403 'name':'preferences',
404 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
405 'remoteData': {
406 'data': headerData['oneTimePasswords']['data'],
407 'version': someServerData['version']
408 }
409 });
410 } else {
411 oneTimePasswords = new Clipperz.PM.DataModel.User.Header.OneTimePasswords({
412 'name':'preferences',
413 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
414 });
415 }
416
417 break;
418 }
419
420 unpackedData = {
421 'version': someServerData['version'],
422 'statistics': someServerData['statistics'],
423 'header': {
424 'data': someServerData['header'],
425 'version': headerVersion,
426
427 'recordsIndex': recordsIndex,
428 'preferences': preferences,
429 'oneTimePasswords': oneTimePasswords
430 }
431 };
432
433 this._serverData = unpackedData;
434
435 return this._serverData;
436 },
437
438 //-------------------------------------------------------------------------
439
440 'getServerData': function() {
441 var deferredResult;
442
443 deferredResult = new Clipperz.Async.Deferred("User.getServerData", {trace:false});
444 deferredResult.acquireLock(this.deferredLockForSection('serverData'));
445 deferredResult.addCallback(MochiKit.Base.bind(function(aResult) {
446 var innerDeferredResult;
447
448 innerDeferredResult = new Clipperz.Async.Deferred("User.getUserDetails.innerDeferred", {trace:false});
449 if (this._serverData == null) {
450 innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadingUserDetails');
451 innerDeferredResult.addMethod(this.connection(), 'message', 'getUserDetails');
452 innerDeferredResult.addMethod(this, 'unpackServerData');
453 innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadedUserDetails');
454 }
455
456 innerDeferredResult.addCallback(MochiKit.Base.bind(function () {
457 return this._serverData;
458 },this));
459 innerDeferredResult.callback();
460
461 return innerDeferredResult;
462 }, this));
463 deferredResult.releaseLock(this.deferredLockForSection('serverData'));
464 deferredResult.callback();
465
466 return deferredResult;
467 },
468
469 //-------------------------------------------------------------------------
470
471 'connectionVersion': function() {
472 return this._connectionVersion;
473 },
474
475 'setConnectionVersion': function(aValue) {
476 if (this._connectionVersion != aValue) {
477 this.resetConnection();
478 }
479 this._connectionVersion = aValue;
480 },
481
482 //-------------------------------------------------------------------------
483
484 'connection': function() {
485 if ((this._connection == null) && (this.connectionVersion() != null) ){
486 this._connection = new Clipperz.PM.Connection.communicationProtocol.versions[this.connectionVersion()]({
487 getCredentialsFunction: MochiKit.Base.method(this, 'getCredentials')
488 });
489 }
490
491 return this._connection;
492 },
493
494 'resetConnection': function(aValue) {
495 if (this._connection != null) {
496 this._connection.reset();
497 }
498
499 this._connection = null;
500 },
501
502 //=========================================================================
503
504 'getHeaderIndex': function (aKey) {
505 return Clipperz.Async.callbacks("User.getHeaderIndex", [
506 MochiKit.Base.method(this, 'getServerData'),
507 MochiKit.Base.itemgetter('header'),
508 MochiKit.Base.itemgetter(aKey)
509 ], {trace:false})
510 },
511
512 //=========================================================================
513
514 'getRecords': function () {
515 return Clipperz.Async.callbacks("User.getRecords", [
516 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
517 MochiKit.Base.methodcaller('records'),
518 MochiKit.Base.values
519 ], {trace:false});
520 },
521
522 'recordWithLabel': function (aLabel) {
523 return Clipperz.Async.callbacks("User.recordWithLabel", [
524 MochiKit.Base.method(this, 'getRecords'),
525 MochiKit.Base.partial(Clipperz.Async.deferredFilter, function (aRecord) {
526 return Clipperz.Async.callbacks("User.recordWithLabel - check record label", [
527 MochiKit.Base.methodcaller('label'),
528 MochiKit.Base.partial(MochiKit.Base.operator.eq, aLabel)
529 ], {trace:false}, aRecord);
530 }),
531 function (someFilteredResults) {
532 var result;
533
534 switch (someFilteredResults.length) {
535 case 0:
536 result = null;
537 break;
538 case 1:
539 result = someFilteredResults[0];
540 break;
541 default:
542 WTF = TODO;
543 break;
544 }
545
546 return result;
547 }
548 ], {trace:false});
549 },
550
551 //-------------------------------------------------------------------------
552
553 'getRecord': function (aRecordReference) {
554 return Clipperz.Async.callbacks("User.getRecord", [
555 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
556 MochiKit.Base.methodcaller('records'),
557 MochiKit.Base.itemgetter(aRecordReference),
558
559 Clipperz.Async.deferredIf("record != null", [
560 MochiKit.Base.operator.identity
561 ], [
562 function () { throw "Record does not exists"}
563 ])
564 ], {trace:false});
565 },
566
567 //-------------------------------------------------------------------------
568
569 'getRecordDetail': function (aRecordReference) {
570 return this.connection().message('getRecordDetail', {reference: aRecordReference});
571 },
572
573 //-------------------------------------------------------------------------
574
575 'deleteRecord': function (aRecord) {
576 return Clipperz.Async.callbacks("User.deleteRecord", [
577 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
578 MochiKit.Base.methodcaller('deleteRecord', aRecord)
579 ], {trace:false});
580 },
581
582 //-------------------------------------------------------------------------
583
584 'createNewRecord': function () {
585 return Clipperz.Async.callbacks("User.createNewRecord", [
586 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
587 MochiKit.Base.methodcaller('createNewRecord')
588 ], {trace:false});
589 },
590
591 //=========================================================================
592
593 'getDirectLogins': function() {
594 var deferredResult;
595
596 deferredResult = new Clipperz.Async.Deferred("User.getDirectLogins", {trace:false});
597 deferredResult.addMethod(this, 'getRecords');
598 deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.compose(MochiKit.Base.values, MochiKit.Base.methodcaller('directLogins')));
599 deferredResult.addCallback(MochiKit.Base.flattenArray);
600 deferredResult.callback();
601
602 return deferredResult;
603 },
604
605 //=========================================================================
606
607 'getOneTimePasswords': function () {
608 return Clipperz.Async.callbacks("User.getOneTimePasswords", [
609 MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
610 MochiKit.Base.methodcaller('oneTimePasswords'),
611 MochiKit.Base.values
612 ], {trace:false});
613 },
614
615 //=========================================================================
616
617 'invokeMethodNamedOnHeader': function (aMethodName, aValue) {
618 return Clipperz.Async.collectResults("User.invokeMethodNamedOnHeader [" + aMethodName + "]", {
619 'recordIndex': [
620 MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
621 MochiKit.Base.methodcaller(aMethodName, aValue)
622 ],
623 'preferences': [
624 MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'),
625 MochiKit.Base.methodcaller(aMethodName, aValue)
626 ],
627 'oneTimePasswords': [
628 MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
629 MochiKit.Base.methodcaller(aMethodName, aValue)
630 ]//,
631 // 'statistics': [
632 // MochiKit.Base.method(this, 'getStatistics'),
633 // MochiKit.Base.methodcaller(aMethodName, aValue)
634 // ]
635 }, {trace:false})();
636 },
637
638 //-------------------------------------------------------------------------
639
640 'invokeMethodNamedOnRecords': function (aMethodName, aValue) {
641 return Clipperz.Async.callbacks("User.invokeMethodNamedOnRecords[" + aMethodName + "]", [
642 MochiKit.Base.method(this, 'getRecords'),
643 MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller(aMethodName, aValue)),
644 Clipperz.Async.collectAll
645 ], {trace:false});
646 },
647
648 //=========================================================================
649
650 'hasPendingChanges': function () {
651 vardeferredResult;
652
653 deferredResult = new Clipperz.Async.Deferred("User.hasPendingChanges", {trace:false});
654 deferredResult.collectResults({
655 'header': [
656 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'hasPendingChanges'),
657 MochiKit.Base.values
658 ],
659 'records': MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'hasPendingChanges')
660 });
661 deferredResult.addCallback(Clipperz.Async.or);
662 deferredResult.callback();
663 // recordsIndex = legacyHeader;
664 // preferences = legacyHeader;
665 // oneTimePasswords= legacyHeader;
666
667 return deferredResult;
668 },
669
670 //=========================================================================
671
672 'commitTransientState': function () {
673 return Clipperz.Async.callbacks("User.commitTransientState", [
674 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'commitTransientState'),
675 MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'commitTransientState'),
676
677 MochiKit.Base.method(this, 'transientState'),
678 // MochiKit.Base.itemgetter('lock'),
679 // MochiKit.Base.method(this, 'setServerLockValue'),
680 MochiKit.Base.method(this, 'resetTransientState', true)
681 ], {trace:false});
682 },
683
684 //-------------------------------------------------------------------------
685
686 'revertChanges': function () {
687 return Clipperz.Async.callbacks("User.revertChanges", [
688 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'revertChanges'),
689 MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'revertChanges'),
690 MochiKit.Base.method(this, 'resetTransientState', false)
691 ], {trace:false});
692 },
693
694 //=========================================================================
695
696 'deleteAllCleanTextData': function () {
697 return Clipperz.Async.callbacks("User.deleteAllCleanTextData", [
698 MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'deleteAllCleanTextData'),
699 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'deleteAllCleanTextData'),
700
701 MochiKit.Base.method(this.data(), 'removeAllData'),
702 MochiKit.Base.method(this, 'resetTransientState', false)
703 ], {trace:false});
704 },
705
706 //-------------------------------------------------------------------------
707
708 'hasAnyCleanTextData': function () {
709 vardeferredResult;
710
711 deferredResult = new Clipperz.Async.Deferred("User.hasAnyCleanTextData", {trace:false});
712 deferredResult.collectResults({
713 'header':[
714 MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'hasAnyCleanTextData'),
715 MochiKit.Base.values
716 ],
717 'records':MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'hasAnyCleanTextData'),
718 'data': MochiKit.Base.bind(function () {
719 return MochiKit.Async.succeed(! this.data().isEmpty());
720 }, this),
721 'transientState':MochiKit.Base.bind(function () {
722 return MochiKit.Async.succeed(MochiKit.Base.keys(this.transientState()).length != 0);
723 }, this)
724 });
725 deferredResult.addCallback(Clipperz.Async.or);
726 deferredResult.callback();
727
728 return deferredResult;
729 },
730
731 //=========================================================================
732
733 'prepareRemoteDataWithKey': function (aKey /*, aCurrentKey*/) {
734 var deferredResult;
735 varresult;
736
737 result = {};
738 deferredResult = new Clipperz.Async.Deferred("User.prepareRemoteDataWithKey", {trace:false});
739 deferredResult.addMethod(this, 'invokeMethodNamedOnHeader', 'prepareRemoteDataWithKey', aKey /*, aCurrentKey*/);
740 deferredResult.addCallback(MochiKit.Base.bind(function (aResult, someHeaderPackedData) {
741 var header;
742
743 header = {};
744 header['records'] = someHeaderPackedData['recordIndex']['records'];
745 header['directLogins'] = someHeaderPackedData['recordIndex']['directLogins'];
746 header['preferences'] = {'data': someHeaderPackedData['preferences']['data']};
747 header['oneTimePasswords']= {'data': someHeaderPackedData['oneTimePasswords']['data']};
748 header['version'] = '0.1';
749
750 aResult['header'] = Clipperz.Base.serializeJSON(header);
751 aResult['statistics'] = this._serverData['statistics']; //"someHeaderPackedData['statistics']['data']";
752
753 return aResult;
754 }, this), result);
755 deferredResult.addCallback(Clipperz.Async.setItem, result, 'version', Clipperz.PM.Crypto.encryptingFunctions.currentVersion);
756 // deferredResult.addCallback(Clipperz.Async.setItem, result, 'lock', this.serverLockValue());
757 deferredResult.callback();
758
759 return deferredResult;
760 },
761
762 //=========================================================================
763
764 'saveChanges': function () {
765 vardeferredResult;
766 var messageParameters;
767
768 messageParameters = {};
769
770 deferredResult = new Clipperz.Async.Deferred("User.saveChangaes", {trace:false});
771
772 deferredResult.addMethod(this, 'getHeaderIndex', 'recordsIndex');
773 deferredResult.addCallback(MochiKit.Base.methodcaller('prepareRemoteDataForChangedRecords'));
774 deferredResult.addCallback(Clipperz.Async.setItem, messageParameters, 'records');
775 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
776
777 deferredResult.addMethod(this, 'getPassphrase');
778 deferredResult.addMethod(this, 'prepareRemoteDataWithKey');
779 deferredResult.addCallback(Clipperz.Async.setItem, messageParameters, 'user');
780 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
781
782 deferredResult.addCallback(MochiKit.Async.succeed, messageParameters);
783 deferredResult.addMethod(this.connection(), 'message', 'saveChanges');
784 deferredResult.addCallback(MochiKit.Base.update, this.transientState())
785 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
786
787 deferredResult.addMethod(this, 'commitTransientState');
788 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress');
789 // deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userDataSuccessfullySaved');
790
791 deferredResult.addErrbackPass(MochiKit.Base.method(this, 'revertChanges'));
792 // deferredResult.addErrbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'failureWhileSavingUserData');
793
794 deferredResult.callback();
795
796 return deferredResult;
797 },
798
799 //=========================================================================
800 __syntaxFix__: "syntax fix"
801});
802
803//-----------------------------------------------------------------------------
804
805Clipperz.PM.DataModel.User.registerNewAccount = function (anUsername, aPassphraseFunction) {
806 vardeferredResult;
807 var user;
808
809 user = new Clipperz.PM.DataModel.User({'username':anUsername, 'getPassphraseFunction':aPassphraseFunction});
810
811 deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.User.registerNewAccount", {trace:false});
812 deferredResult.addMethod(user, 'registerAsNewAccount');
813 deferredResult.addMethod(user, 'login');
814 deferredResult.addCallback(MochiKit.Async.succeed, user);
815 deferredResult.callback();
816
817 return deferredResult;
818}
819
820//-----------------------------------------------------------------------------
821
822Clipperz.PM.DataModel.User.exception = {
823 LoginFailed: new MochiKit.Base.NamedError("Clipperz.PM.DataModel.User.exception.LoginFailed"),
824 CredentialUpgradeFailed:new MochiKit.Base.NamedError("Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed")
825};
826
827//-----------------------------------------------------------------------------
diff --git a/frontend/delta/js/Clipperz/PM/Date.js b/frontend/delta/js/Clipperz/PM/Date.js
new file mode 100644
index 0000000..a62857e
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Date.js
@@ -0,0 +1,196 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.Date) == 'undefined') { Clipperz.PM.Date = {}; }
27
28Clipperz.PM.Date.VERSION = "0.1";
29Clipperz.PM.Date.NAME = "Clipperz.PM.Date";
30
31MochiKit.Base.update(Clipperz.PM.Date, {
32
33 '__repr__': function () {
34 return "[" + this.NAME + " " + this.VERSION + "]";
35 },
36
37 //-------------------------------------------------------------------------
38
39 'toString': function () {
40 return this.__repr__();
41 },
42
43 //-------------------------------------------------------------------------
44
45 'locale': function() {
46 return {
47 'amDesignation':Clipperz.PM.Strings.getValue('calendarStrings.amDesignation'),
48 'pmDesignation':Clipperz.PM.Strings.getValue('calendarStrings.pmDesignation'),
49 'days': Clipperz.PM.Strings.getValue('calendarStrings.days'),
50 'shortDays': Clipperz.PM.Strings.getValue('calendarStrings.shortDays'),
51 'shortMonths': Clipperz.PM.Strings.getValue('calendarStrings.shortMonths'),
52 'months': Clipperz.PM.Strings.getValue('calendarStrings.months')
53 }
54 },
55
56 //=========================================================================
57/*
58 'formatDateWithPHPLikeTemplate': function(aDate, aTemplate) {
59 return Clipperz.Date.formatDateWithPHPLikeTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
60 },
61
62 'parseDateWithPHPLikeTemplate': function(aDate, aTemplate) {
63 return Clipperz.Date.parseDateWithPHPTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
64 },
65
66 //=========================================================================
67
68 'formatDateWithJavaLikeTemplate': function(aDate, aTemplate) {
69 return Clipperz.Date.formatDateWithJavaLikeTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
70 },
71
72 'parseDateWithJavaLikeTemplate': function(aDate, aTemplate) {
73 return Clipperz.Date.parseDateWithJavaLikeTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
74 },
75*/
76 //=========================================================================
77
78 'formatWithTemplate': function (aTemplate, aDate) {
79 return Clipperz.PM.Date.formatDateWithTemplate(aDate, aTemplate);
80 },
81
82 'formatDateWithTemplate': function(aDate, aTemplate) {
83 var result;
84
85 if (aDate == null) {
86 result = ""
87 } else {
88 result = Clipperz.Date.formatDateWithPHPLikeTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
89 };
90
91 return result;
92 },
93
94 'parseDateWithTemplate': function(aValue, aTemplate) {
95 return Clipperz.Date.parseDateWithPHPTemplateAndLocale(aValue, aTemplate, Clipperz.PM.Date.locale());
96 },
97
98 //=========================================================================
99
100 'formatDateWithUTCFormat': function(aDate) {
101 return Clipperz.Date.formatDateWithUTCFormatAndLocale(aDate, Clipperz.PM.Date.locale());
102 },
103
104 'parseDateWithUTCFormat': function(aValue) {
105 var result;
106
107 if (aValue == null) {
108 result = null;
109 } else {
110 result = Clipperz.Date.parseDateWithUTCFormatAndLocale(aValue, Clipperz.PM.Date.locale());
111 }
112
113 return result;
114 },
115
116 //=========================================================================
117
118 'getElapsedTimeDescription': function(aDate) {
119 var result;
120
121 result = ""
122
123 if (aDate != null) {
124 var now;
125 var elapsedTime;
126
127 var millisencondsInAMinute;
128 var millisencondsInAnHour;
129 var millisencondsInADay;
130 var millisencondsInAWeek;
131 var millisencondsInAMonth;
132
133 now = new Date();
134 elapsedTime = now.getTime() - aDate.getTime();
135
136 millisencondsInAMinute = 60 * 1000;
137 millisencondsInAnHour = millisencondsInAMinute * 60;
138 millisencondsInADay = millisencondsInAnHour * 24;
139 millisencondsInAWeek = millisencondsInADay * 7;
140 millisencondsInAMonth = millisencondsInAWeek * 5;
141
142 if ((elapsedTime / millisencondsInAMonth) > 1) {
143 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.MORE_THAN_A_MONTH_AGO');
144 } else if ((elapsedTime / millisencondsInAWeek) > 1) {
145 var elapsedWeeks;
146
147 elapsedWeeks = Math.floor((elapsedTime / millisencondsInAWeek));
148 if (elapsedWeeks == 1) {
149 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.MORE_THAN_A_WEEK_AGO');
150 } else {
151 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.MORE_THAN_*_WEEKS_AGO').replace(/__elapsed__/, elapsedWeeks);
152 }
153 } else if ((elapsedTime / millisencondsInADay) > 1) {
154 var elapsedDays;
155
156 elapsedDays = Math.floor((elapsedTime / millisencondsInADay));
157 if (elapsedDays == 1) {
158 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.YESTERDAY');
159 } else {
160 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.*_DAYS_AGO').replace(/__elapsed__/, elapsedDays);
161 }
162 } else if ((elapsedTime / millisencondsInAnHour) > 1) {
163 var elapsedHours;
164
165 elapsedHours = Math.floor((elapsedTime / millisencondsInAnHour));
166 if (elapsedHours == 1) {
167 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.ABOUT_AN_HOUR_AGO');
168 } else {
169 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.*_HOURS_AGO').replace(/__elapsed__/, elapsedHours);
170 }
171 } else {
172 var elapsed10Minutes;
173
174 elapsed10Minutes = (Math.floor((elapsedTime / millisencondsInAMinute) / 10)) * 10;
175 if (elapsed10Minutes == 0) {
176 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.JUST_A_FEW_MINUTES_AGO');
177 } else {
178 result = Clipperz.PM.Strings.getValue('elapsedTimeDescriptions.ABOUT_*_MINUTES_AGO').replace(/__elapsed__/, elapsed10Minutes+"");
179 }
180 }
181 }
182
183 return result;
184 },
185
186 //-------------------------------------------------------------------------
187
188 'parse': function (aValue) {
189 return Clipperz.PM.Date.parseDateWithUTCFormat(aValue);
190 },
191
192 //-------------------------------------------------------------------------
193 __syntaxFix__: "syntax fix"
194
195});
196
diff --git a/frontend/delta/js/Clipperz/PM/PIN.js b/frontend/delta/js/Clipperz/PM/PIN.js
new file mode 100644
index 0000000..a32889a
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/PIN.js
@@ -0,0 +1,132 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.PIN) == 'undefined') { Clipperz.PM.PIN = {}; }
27
28MochiKit.Base.update(Clipperz.PM.PIN, {
29
30 //-------------------------------------------------------------------------
31
32 '__repr__': function () {
33 return "[" + this.NAME + " " + this.VERSION + "]";
34 },
35
36 //-------------------------------------------------------------------------
37
38 'toString': function () {
39 return this.__repr__();
40 },
41
42 'CREDENTIALS': 'CLIPPERZ.CREDENTIALS',
43 'FAILURE_COUNT': 'CLIPPERZ.FAILED_LOGIN_COUNT',
44 'ALLOWED_RETRY': 3,
45
46 //-------------------------------------------------------------------------
47
48 'isSet': function () {
49 return (this.storedCredentials() != null);
50 },
51
52 'storedCredentials': function () {
53 return localStorage[this.CREDENTIALS];
54 },
55
56 //-------------------------------------------------------------------------
57
58 'recordFailedAttempt': function () {
59 varfailureCount;
60 varresult;
61
62 failureCount = localStorage[this.FAILURE_COUNT];
63
64 if (failureCount == null) {
65 failureCount = 0
66 }
67
68 failureCount ++;
69
70 if (failureCount < this.ALLOWED_RETRY) {
71 localStorage[this.FAILURE_COUNT] = failureCount;
72 result = failureCount;
73 } else {
74 this.removeLocalCredentials();
75 result = -1;
76 }
77
78 return result;
79 },
80
81 'resetFailedAttemptCount': function () {
82 localStorage.removeItem(this.FAILURE_COUNT);
83 },
84
85 'failureCount': function () {
86 return localStorage[this.FAILURE_COUNT];
87 },
88
89 //-------------------------------------------------------------------------
90
91 'deriveKeyFromPin': function (aPIN) {
92 return Clipperz.Crypto.SHA.sha256(new Clipperz.ByteArray(aPIN));
93 },
94
95 'credentialsWithPIN': function (aPIN) {
96 varbyteArrayValue;
97 var decryptedValue;
98 varresult;
99
100 byteArrayValue = (new Clipperz.ByteArray()).appendBase64String(localStorage[this.CREDENTIALS]);
101 decryptedValue = Clipperz.Crypto.AES.decrypt(this.deriveKeyFromPin(aPIN), byteArrayValue).asString();
102 try {
103 result = Clipperz.Base.evalJSON(decryptedValue);
104 } catch (error) {
105 result = {'username':'fakeusername', 'passphrase':'fakepassphrase'};
106 }
107
108 return result;
109 },
110
111 'setCredentialsWithPIN': function (aPIN, someCredentials) {
112 varencodedValue;
113 varbyteArrayValue;
114 var encryptedValue;
115
116 encodedValue = Clipperz.Base.serializeJSON(someCredentials);
117 byteArrayValue = new Clipperz.ByteArray(encodedValue);
118 encryptedValue = Clipperz.Crypto.AES.encrypt(this.deriveKeyFromPin(aPIN), byteArrayValue).toBase64String();
119
120 localStorage[this.CREDENTIALS] = encryptedValue;
121 },
122
123 'removeLocalCredentials': function () {
124 localStorage.removeItem(this.CREDENTIALS);
125 localStorage.removeItem(this.FAILURE_COUNT);
126 },
127
128 //-------------------------------------------------------------------------
129 __syntaxFix__: "syntax fix"
130
131});
132
diff --git a/frontend/delta/js/Clipperz/PM/Proxy.js b/frontend/delta/js/Clipperz/PM/Proxy.js
new file mode 100644
index 0000000..2ac684a
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Proxy.js
@@ -0,0 +1,186 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26
27//=============================================================================
28
29Clipperz.PM.Proxy = function(args) {
30 args = args || {};
31
32 this._shouldPayTolls = args.shouldPayTolls || false;
33
34 this._tolls = {
35 'CONNECT':[],
36 'REGISTER':[],
37 'MESSAGE':[]
38 };
39
40 if (args.isDefault === true) {
41 Clipperz.PM.Proxy.defaultProxy = this;
42 }
43
44 return this;
45}
46
47Clipperz.PM.Proxy.prototype = MochiKit.Base.update(null, {
48
49 'toString': function() {
50 return "Clipperz.PM.Proxy";
51 },
52
53 //=========================================================================
54
55 'shouldPayTolls': function() {
56 return this._shouldPayTolls;
57 },
58
59 //-------------------------------------------------------------------------
60
61 'tolls': function() {
62 return this._tolls;
63 },
64
65 //-------------------------------------------------------------------------
66
67 'payToll': function(aRequestType, someParameters) {
68 vardeferredResult;
69
70 if (this.shouldPayTolls()) {
71 deferredResult = new Clipperz.Async.Deferred("Proxy.payToll", {trace:false});
72
73 if (this.tolls()[aRequestType].length == 0) {
74 deferredResult.addMethod(this, 'sendMessage', 'knock', {requestType:aRequestType});
75 deferredResult.addMethod(this, 'setTollCallback');
76 }
77 deferredResult.addMethod(this.tolls()[aRequestType], 'pop');
78 deferredResult.addCallback(MochiKit.Base.methodcaller('deferredPay'));
79 deferredResult.addCallback(function(aToll) {
80 var result;
81
82 result = {
83 parameters: someParameters,
84 toll: aToll
85 }
86
87 return result;
88 });
89
90 deferredResult.callback();
91 } else {
92 deferredResult = MochiKit.Async.succeed({parameters:someParameters});
93 }
94
95 return deferredResult;
96 },
97
98 //-------------------------------------------------------------------------
99
100 'addToll': function(aToll) {
101 this.tolls()[aToll.requestType()].push(aToll);
102 },
103
104 //=========================================================================
105
106 'setTollCallback': function(someParameters) {
107 if (typeof(someParameters['toll']) != 'undefined') {
108 this.addToll(new Clipperz.PM.Toll(someParameters['toll']));
109 }
110
111 return someParameters['result'];
112 },
113
114 //=========================================================================
115
116 'registration': function (someParameters) {
117 return this.processMessage('registration', someParameters, 'REGISTER');
118 },
119
120 'handshake': function (someParameters) {
121 return this.processMessage('handshake', someParameters, 'CONNECT');
122 },
123
124 'message': function (someParameters) {
125 return this.processMessage('message', someParameters, 'MESSAGE');
126 },
127
128 'logout': function (someParameters) {
129 return this.processMessage('logout', someParameters, 'MESSAGE');
130 },
131
132 //=========================================================================
133
134 'processMessage': function (aFunctionName, someParameters, aRequestType) {
135 vardeferredResult;
136
137 deferredResult = new Clipperz.Async.Deferred("Proxy.processMessage", {trace:false});
138 deferredResult.addMethod(this, 'payToll', aRequestType);
139 deferredResult.addMethod(this, 'sendMessage', aFunctionName);
140 deferredResult.addMethod(this, 'setTollCallback');
141 deferredResult.callback(someParameters);
142
143 return deferredResult;
144 },
145
146 //=========================================================================
147
148 '_sendMessage': function (aFunctionName, aVersion, someParameters) {
149 throw Clipperz.Base.exception.AbstractMethod;
150 },
151
152 'sendMessage': function (aFunctionName, someParameters) {
153 var deferredResult;
154
155 //TODO: read actual application version for a property set at build time
156 deferredResult = new Clipperz.Async.Deferred("Proxy.sendMessage", {trace:false});
157 deferredResult.addMethod(this, '_sendMessage', aFunctionName, 'fake-app-version');
158 deferredResult.addErrback(MochiKit.Base.method(this, 'handleError'));
159 deferredResult.callback(someParameters);
160
161 return deferredResult;
162 },
163
164 //-------------------------------------------------------------------------
165
166 'handleError': function (anError) {
167 if (anError['message'] == 'Wrong application version') {
168 anError['isPermanent'] = true;
169 }
170 return anError;
171 },
172
173 //=========================================================================
174
175 'isReadOnly': function () {
176 return false;
177 },
178
179 'canRegisterNewUsers': function () {
180 return true;
181 },
182
183 //=========================================================================
184 __syntaxFix__: "syntax fix"
185
186});
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
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26
27//=============================================================================
28
29Clipperz.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
37Clipperz.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
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.Proxy.Offline) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.Proxy.Offline.DataStore depends on Clipperz.PM.Proxy.Offline!";
26}
27
28//=============================================================================
29
30Clipperz.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
43Clipperz.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
791Clipperz.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
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.Proxy.Offline.DataStore) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.Proxy.Offline.LocalStorageDataStore depends on Clipperz.PM.Proxy.Offline.DataStore!";
26}
27
28//=============================================================================
29
30Clipperz.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
45Clipperz.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
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24try { if (typeof(Clipperz.PM.Proxy.Offline.DataStore) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.Proxy.Offline.MemoryDataStore depends on Clipperz.PM.Proxy.Offline.DataStore!";
26}
27
28//=============================================================================
29
30Clipperz.PM.Proxy.Offline.MemoryDataStore = function(args) {
31 args = args || {};
32
33 this._data = args.data || (typeof(_clipperz_dump_data_) != 'undefined' ? _clipperz_dump_data_ : null);
34 this._isReadOnly = (typeof(args.readOnly) == 'undefined' ? true : args.readOnly);
35 this._shouldPayTolls = args.shouldPayTolls || false;
36
37 this._tolls = {};
38 this._currentStaticConnection = null;
39
40 return this;
41}
42
43Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.MemoryDataStore, Clipperz.PM.Proxy.Offline.DataStore, {
44
45 //=========================================================================
46
47 'resetData': function() {
48 this._data = {
49 'users': {
50 'catchAllUser': {
51 __masterkey_test_value__: 'masterkey',
52 s: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00',
53 v: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00'
54 }
55 }
56 };
57 },
58
59 //-------------------------------------------------------------------------
60
61 'setupWithEncryptedData': function(someData) {
62 this._data = Clipperz.Base.deepClone(someData);
63 },
64
65 //-------------------------------------------------------------------------
66
67 'setupWithData': function(someData) {
68 var deferredResult;
69 var resultData;
70 var i, c;
71
72//Clipperz.log(">>> Proxy.Test.setupWithData");
73 resultData = this._data;
74
75 deferredResult = new Clipperz.Async.Deferred("Proxy.Test.seupWithData", {trace:false});
76 c = someData['users'].length;
77
78 for (i=0; i<c; i++) {
79 varnewConnection;
80 varrecordConfiguration;
81
82 deferredResult.addMethod(this, 'userSerializedEncryptedData', someData['users'][i]);
83 deferredResult.addCallback(MochiKit.Base.bind(function(aUserSerializationContext) {
84 resultData['users'][aUserSerializationContext['credentials']['C']] = {
85 's': aUserSerializationContext['credentials']['s'],
86 'v': aUserSerializationContext['credentials']['v'],
87 'version': aUserSerializationContext['data']['connectionVersion'],
88 'userDetails': aUserSerializationContext['encryptedData']['user']['header'],
89 'userDetailsVersion':aUserSerializationContext['encryptedData']['user']['version'],
90 'statistics': aUserSerializationContext['encryptedData']['user']['statistics'],
91 'lock': aUserSerializationContext['encryptedData']['user']['lock'],
92 'records': this.rearrangeRecordsData(aUserSerializationContext['encryptedData']['records'])
93 }
94 }, this));
95 }
96
97 deferredResult.addCallback(MochiKit.Base.bind(function() {
98 this._data = resultData;
99 }, this));
100
101 deferredResult.callback();
102//Clipperz.log("<<< Proxy.Test.setupWithData");
103
104 return deferredResult;
105 },
106
107 //=========================================================================
108
109 'getTollForRequestType': function (aRequestType) {
110 varresult;
111 vartargetValue;
112 var cost;
113
114 targetValue = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
115 switch (aRequestType) {
116 case 'REGISTER':
117 cost = 5;
118 break;
119 case 'CONNECT':
120 cost = 5;
121 break;
122 case 'MESSAGE':
123 cost = 2;
124 break;
125 }
126
127 result = {
128 requestType: aRequestType,
129 targetValue: targetValue,
130 cost: cost
131 }
132
133 if (this.shouldPayTolls()) {
134 this.tolls()[targetValue] = result;
135 }
136
137 return result;
138 },
139
140 //-------------------------------------------------------------------------
141
142 'checkToll': function (aFunctionName, someParameters) {
143 if (this.shouldPayTolls()) {
144 var localToll;
145 vartollParameters;
146
147 tollParameters = someParameters['toll'];
148 localToll = this.tolls()[tollParameters['targetValue']];
149
150 if (localToll != null) {
151 if (! Clipperz.PM.Toll.validate(tollParameters['targetValue'], tollParameters['toll'], localToll['cost'])) {
152 throw "Toll value too low.";
153 };
154 } else {
155 throw "Missing toll";
156 }
157 }
158 },
159
160 //=========================================================================
161
162 'currentStaticConnection': function () {
163 if (this._currentStaticConnection == null) {
164 this._currentStaticConnection = {};
165 }
166
167 return this._currentStaticConnection;
168 },
169
170 //-------------------------------------------------------------------------
171
172 'getConnectionForRequest': function (aFunctionName, someParameters) {
173 varresult;
174
175 if (this.shouldPayTolls()) {
176 if ((typeof(someParameters['toll']) != 'undefined') && (typeof(someParameters['toll']['targetValue']) != 'undefined')) {
177 result = this.tolls()[someParameters['toll']['targetValue']]['connection'];
178 if (typeof(result) == 'undefined') {
179 result = {};
180 }
181 } else {
182 result = {};
183 }
184 } else {
185 result = this.currentStaticConnection();
186 }
187
188 return result;
189 },
190
191 //-------------------------------------------------------------------------
192
193 'storeConnectionForRequestWithConnectionAndResponse': function (aFunctionName, someParameters, aConnection, aResponse) {
194 if (this.shouldPayTolls()) {
195 if ((typeof(aResponse['toll']) != 'undefined')
196 &&(typeof(aResponse['toll']['targetValue']) != 'undefined')
197 &&(typeof(this.tolls()[aResponse['toll']['targetValue']]) != 'undefined')
198 ) {
199 this.tolls()[aResponse['toll']['targetValue']]['connection'] = aConnection;
200 }
201 }
202 },
203
204 //=========================================================================
205
206 'processMessage': function (aFunctionName, someParameters) {
207 var result;
208 varconnection;
209
210 connection = this.getConnectionForRequest(aFunctionName, someParameters);
211
212 switch(aFunctionName) {
213 case 'knock':
214 result = this._knock(connection, someParameters);
215 break;
216 case 'registration':
217 this.checkToll(aFunctionName, someParameters);
218 result = this._registration(connection, someParameters.parameters);
219 break;
220 case 'handshake':
221 this.checkToll(aFunctionName, someParameters);
222 result = this._handshake(connection, someParameters.parameters);
223 break;
224 case 'message':
225 this.checkToll(aFunctionName, someParameters);
226 result = this._message(connection, someParameters.parameters);
227 break;
228 case 'logout':
229 this._currentStaticConnection = null;
230 result = this._logout(connection, someParameters.parameters);
231 break;
232 }
233
234 this.storeConnectionForRequestWithConnectionAndResponse(aFunctionName, someParameters, connection, result);
235
236 return MochiKit.Async.succeed(result);
237 },
238
239 //=========================================================================
240
241 '_knock': function(aConnection, someParameters) {
242 var result;
243
244 result = {
245 toll: this.getTollForRequestType(someParameters['requestType'])
246 }
247
248 return result;
249 },
250
251 //-------------------------------------------------------------------------
252
253 '_registration': function(aConnection, someParameters) {
254 if (this.isReadOnly() == false) {
255 if (typeof(this.data()['users'][someParameters['credentials']['C']]) == 'undefined') {
256 this.data()['users'][someParameters['credentials']['C']] = {
257 's': someParameters['credentials']['s'],
258 'v': someParameters['credentials']['v'],
259 'version':someParameters['credentials']['version'],
260 // 'lock': Clipperz.Crypto.Base.generateRandomSeed(),
261 'userDetails': someParameters['user']['header'],
262 'statistics': someParameters['user']['statistics'],
263 'userDetailsVersion':someParameters['user']['version'],
264 'records':{}
265 }
266 } else {
267 throw "user already exists";
268 }
269 } else {
270 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
271 }
272
273 result = {
274 result: {
275 'lock': this.data()['users'][someParameters['credentials']['C']]['lock'],
276 'result':'done'
277 },
278 toll: this.getTollForRequestType('CONNECT')
279 }
280
281 return result;
282 },
283
284 //-------------------------------------------------------------------------
285
286 '_handshake': function(aConnection, someParameters) {
287 var result;
288 varnextTollRequestType;
289
290 result = {};
291 if (someParameters.message == "connect") {
292 var userData;
293 var randomBytes;
294 var v;
295
296 userData = this.data()['users'][someParameters.parameters.C];
297
298 if ((typeof(userData) != 'undefined') && (userData['version'] == someParameters.version)) {
299 aConnection['userData'] = userData;
300 aConnection['C'] = someParameters.parameters.C;
301 } else {
302 aConnection['userData'] = this.data()['users']['catchAllUser'];
303 }
304
305 randomBytes = Clipperz.Crypto.Base.generateRandomSeed();
306 aConnection['b'] = new Clipperz.Crypto.BigInt(randomBytes, 16);
307 v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
308 aConnection['B'] = v.add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()));
309
310 aConnection['A'] = someParameters.parameters.A;
311
312 result['s'] = aConnection['userData']['s'];
313 result['B'] = aConnection['B'].asString(16);
314
315 nextTollRequestType = 'CONNECT';
316 } else if (someParameters.message == "credentialCheck") {
317 var v, u, S, A, K, M1;
318
319 v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
320 u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aConnection['B'].asString(10))).toHexString(), 16);
321 A = new Clipperz.Crypto.BigInt(aConnection['A'], 16);
322 S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(aConnection['b'], Clipperz.Crypto.SRP.n());
323
324 K = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(S.asString(10))).toHexString().slice(2);
325
326 M1 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + aConnection['B'].asString(10) + K)).toHexString().slice(2);
327 if (someParameters.parameters.M1 == M1) {
328 var M2;
329
330 M2 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + someParameters.parameters.M1 + K)).toHexString().slice(2);
331 result['M2'] = M2;
332 } else {
333 throw new Error("Client checksum verification failed! Expected <" + M1 + ">, received <" + someParameters.parameters.M1 + ">.", "Error");
334 }
335
336 nextTollRequestType = 'MESSAGE';
337 } else if (someParameters.message == "oneTimePassword") {
338 var otpData;
339
340 otpData = this.data()['onetimePasswords'][someParameters.parameters.oneTimePasswordKey];
341
342 try {
343 if (typeof(otpData) != 'undefined') {
344 if (otpData['status'] == 'ACTIVE') {
345 if (otpData['key_checksum'] == someParameters.parameters.oneTimePasswordKeyChecksum) {
346 result = {
347 'data': otpData['data'],
348 'version':otpData['version']
349 }
350
351 otpData['status'] = 'REQUESTED';
352 } else {
353 otpData['status'] = 'DISABLED';
354 throw "The requested One Time Password has been disabled, due to a wrong keyChecksum";
355 }
356 } else {
357 throw "The requested One Time Password was not active";
358 }
359 } else {
360 throw "The requested One Time Password has not been found"
361 }
362 } catch (exception) {
363 result = {
364 'data': Clipperz.PM.Crypto.randomKey(),
365 'version':Clipperz.PM.Connection.communicationProtocol.currentVersion
366 }
367 }
368 nextTollRequestType = 'CONNECT';
369 } else {
370 Clipperz.logError("Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters.message);
371 }
372
373 result = {
374 result: result,
375 toll: this.getTollForRequestType(nextTollRequestType)
376 }
377
378 return result;
379 },
380
381 //-------------------------------------------------------------------------
382
383 '_message': function(aConnection, someParameters) {
384 var result;
385
386 result = {};
387
388 //=====================================================================
389 //
390 // R E A D - O N L Y M e t h o d s
391 //
392 //=====================================================================
393 if (someParameters.message == 'getUserDetails') {
394 var recordsStats;
395 var recordReference;
396
397 recordsStats = {};
398 for (recordReference in aConnection['userData']['records']) {
399 recordsStats[recordReference] = {
400 'updateDate': aConnection['userData']['records'][recordReference]['updateDate']
401 }
402 }
403
404 result['header'] = this.userDetails(aConnection);
405 result['statistics'] = this.statistics(aConnection);
406 result['maxNumberOfRecords'] = aConnection['userData']['maxNumberOfRecords'];
407 result['version'] = aConnection['userData']['userDetailsVersion'];
408 result['recordsStats'] = recordsStats;
409
410 if (this.isReadOnly() == false) {
411 varlock;
412
413 if (typeof(aConnection['userData']['lock']) == 'undefined') {
414 aConnection['userData']['lock'] = "<<LOCK>>";
415 }
416
417 result['lock'] = aConnection['userData']['lock'];
418 }
419
420 //=====================================================================
421 } else if (someParameters.message == 'getRecordDetail') {
422/*
423 varrecordData;
424 var currentVersionData;
425
426 recordData = this.userData()['records'][someParameters['parameters']['reference']];
427 result['reference'] = someParameters['parameters']['reference'];
428 result['data'] = recordData['data'];
429 result['version'] = recordData['version'];
430 result['creationData'] = recordData['creationDate'];
431 result['updateDate'] = recordData['updateDate'];
432 result['accessDate'] = recordData['accessDate'];
433
434 currentVersionData = recordData['versions'][recordData['currentVersion']];
435
436 result['currentVersion'] = {};
437 result['currentVersion']['reference'] = recordData['currentVersion'];
438 result['currentVersion']['version'] = currentVersionData['version'];
439 result['currentVersion']['header'] = currentVersionData['header'];
440 result['currentVersion']['data'] = currentVersionData['data'];
441 result['currentVersion']['creationData'] = currentVersionData['creationDate'];
442 result['currentVersion']['updateDate'] = currentVersionData['updateDate'];
443 result['currentVersion']['accessDate'] = currentVersionData['accessDate'];
444 if (typeof(currentVersionData['previousVersion']) != 'undefined') {
445 result['currentVersion']['previousVersionKey'] = currentVersionData['previousVersionKey'];
446 result['currentVersion']['previousVersion'] = currentVersionData['previousVersion'];
447 }
448*/
449 MochiKit.Base.update(result, aConnection['userData']['records'][someParameters['parameters']['reference']]);
450 result['reference'] = someParameters['parameters']['reference'];
451
452 //=====================================================================
453 //
454 // R E A D - W R I T E M e t h o d s
455 //
456 //=====================================================================
457 } else if (someParameters.message == 'upgradeUserCredentials') {
458 if (this.isReadOnly() == false) {
459 var parameters;
460 var credentials;
461
462 parameters = someParameters['parameters'];
463 credentials = parameters['credentials'];
464
465 if ((credentials['C'] == null)
466 ||(credentials['s'] == null)
467 ||(credentials['v'] == null)
468 ||(credentials['version'] != Clipperz.PM.Connection.communicationProtocol.currentVersion)
469 ) {
470 result = Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed;
471 } else {
472 varoldCValue;
473 oldCValue = aConnection['C'];
474
475 this.data()['users'][credentials['C']] = aConnection['userData'];
476 aConnection['C'] = credentials['C'];
477
478 aConnection['userData']['s'] = credentials['s'];
479 aConnection['userData']['v'] = credentials['v'];
480 aConnection['userData']['version'] = credentials['version'];
481
482 aConnection['userData']['userDetails'] = parameters['user']['header'];
483 aConnection['userData']['userDetailsVersion'] = parameters['user']['version'];
484 aConnection['userData']['statistics'] = parameters['user']['statistics'];
485
486 aConnection['userData']['lock'] = parameters['user']['lock'];
487
488 delete this.data()['users'][oldCValue];
489
490 result = {result:"done", parameters:parameters};
491 }
492 } else {
493 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
494 }
495
496 //=====================================================================
497
498 } else if (someParameters.message == 'saveChanges') {
499 if (this.isReadOnly() == false) {
500 var i, c;
501
502 if (aConnection['userData']['lock']!= someParameters['parameters']['user']['lock']) {
503 throw "the lock attribute is not processed correctly"
504 }
505
506 aConnection['userData']['userDetails'] = someParameters['parameters']['user']['header'];
507 aConnection['userData']['statistics'] = someParameters['parameters']['user']['statistics'];
508 aConnection['userData']['userDetailsVersion']= someParameters['parameters']['user']['version'];
509
510 c = someParameters['parameters']['records']['updated'].length;
511 for (i=0; i<c; i++) {
512 var currentRecord;
513 var currentRecordData;
514
515 currentRecordData = someParameters['parameters']['records']['updated'][i];
516 currentRecord = aConnection['userData']['records'][currentRecordData['record']['reference']];
517
518 if (
519 (typeof(aConnection['userData']['records'][currentRecordData['record']['reference']]) == 'undefined')
520 &&
521 (typeof(currentRecordData['currentRecordVersion']) == 'undefined')
522 ) {
523 throw "Record added without a recordVersion";
524 }
525
526 if (currentRecord == null) {
527 currentRecord = {};
528 currentRecord['versions'] = {};
529 currentRecord['creationDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
530 currentRecord['accessDate'] = Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
531
532 aConnection['userData']['records'][currentRecordData['record']['reference']] = currentRecord;
533 }
534
535 currentRecord['data'] = currentRecordData['record']['data'];
536 currentRecord['version']= currentRecordData['record']['version'];
537 currentRecord['updateDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
538
539 if (typeof(currentRecordData['currentRecordVersion']) != 'undefined') {
540 currentRecord['currentVersion'] = currentRecordData['currentRecordVersion']['reference'];
541 currentRecord['versions'][currentRecordData['currentRecordVersion']['reference']] = {
542 'data': currentRecordData['currentRecordVersion']['data'],
543 'version': currentRecordData['currentRecordVersion']['version'],
544 'previousVersion': currentRecordData['currentRecordVersion']['previousVersion'],
545 'previousVersionKey':currentRecordData['currentRecordVersion']['previousVersionKey'],
546 'creationDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
547 'updateDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
548 'accessDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date())
549 }
550 }
551 }
552
553 c = someParameters['parameters']['records']['deleted'].length;
554 for (i=0; i<c; i++) {
555 var currentRecordReference;
556
557 currentRecordReference = someParameters['parameters']['records']['deleted'][i];
558 delete aConnection['userData']['records'][currentRecordReference];
559 }
560
561 aConnection['userData']['lock'] = Clipperz.PM.Crypto.randomKey();
562 result['lock'] = aConnection['userData']['lock'];
563 result['result'] = 'done';
564 } else {
565 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
566 }
567
568 //=====================================================================
569 //
570 // U N H A N D L E D M e t h o d
571 //
572 //=====================================================================
573 } else {
574 Clipperz.logError("Clipperz.PM.Proxy.Test.message - unhandled message: " + someParameters.message);
575 }
576
577 result = {
578 result: result,
579 toll: this.getTollForRequestType('MESSAGE')
580 }
581
582 // return MochiKit.Async.succeed(result);
583 return result;
584 },
585
586 //-------------------------------------------------------------------------
587
588 '_logout': function(someParameters) {
589 // return MochiKit.Async.succeed({result: 'done'});
590 return {result: 'done'};
591 },
592
593 //=========================================================================
594 //#########################################################################
595
596 'isTestData': function(aConnection) {
597 return (typeof(aConnection['userData']['__masterkey_test_value__']) != 'undefined');
598 },
599
600 'userDetails': function(aConnection) {
601 var result;
602
603 if (this.isTestData(aConnection)) {
604 var serializedHeader;
605 var version;
606
607//Clipperz.logDebug("### test data");
608 version = aConnection['userData']['userDetailsVersion'];
609 serializedHeader = Clipperz.Base.serializeJSON(aConnection['userData']['userDetails']);
610 result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(aConnection['userData']['__masterkey_test_value__'], serializedHeader);
611 } else {
612//Clipperz.logDebug("### NOT test data");
613 result = aConnection['userData']['userDetails'];
614 }
615
616 return result;
617 },
618
619 'statistics': function(aConnection) {
620 var result;
621
622 if (aConnection['userData']['statistics'] != null) {
623 if (this.isTestData(aConnection)) {
624 var serializedStatistics;
625 var version;
626
627 version = aConnection['userData']['userDetailsVersion'];
628 serializedStatistics = Clipperz.Base.serializeJSON(aConnection['userData']['statistics']);
629 result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(aConnection['userData']['__masterkey_test_value__'], serializedStatistics);
630 } else {
631 result = aConnection['userData']['statistics'];
632 }
633 } else {
634 result = null;
635 }
636
637 return result;
638 },
639
640 //=========================================================================
641 __syntaxFix__: "syntax fix"
642});
643
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
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26
27//=============================================================================
28
29Clipperz.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
39Clipperz.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
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.Proxy) == 'undefined') { Clipperz.PM.Proxy = {}; }
27
28//=============================================================================
29
30Clipperz.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
44Clipperz.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;
143Clipperz.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
diff --git a/frontend/delta/js/Clipperz/PM/Strings.js b/frontend/delta/js/Clipperz/PM/Strings.js
new file mode 100644
index 0000000..7e855ff
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Strings.js
@@ -0,0 +1,285 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.Strings) == 'undefined') { Clipperz.PM.Strings = {}; }
27if (typeof(Clipperz.PM.Strings.Languages) == 'undefined') { Clipperz.PM.Strings.Languages = {}; }
28
29//-----------------------------------------------------------------------------
30/*
31Clipperz.PM.Strings.standardStrings = {
32 'loginPanelSwitchLanguageSelectOptions':[
33/ *
34 {tag:'option', html:"Arabic (Oman) (العربية)", value:'ar-OM', disabled:true},
35 {tag:'option', html:"Arabic (Syria) (العربية)", value:'ar-SY', disabled:true},
36 {tag:'option', html:"Bahasa Indonesia", value:'id-ID', disabled:true},
37 {tag:'option', html:"Bulgarian (Български)", value:'bg-BG', disabled:true},
38 {tag:'option', html:"Català", value:'ca-ES', disabled:true},
39 {tag:'option', html:"Chinese (Simplified) (简体中文)", value:'zh-CN', disabled:true},
40 {tag:'option', html:"Chinese (Traditional) (正體中文)", value:'zh-TW', disabled:true},
41 {tag:'option', html:"Czech (Česky)", value:'cs-CZ', disabled:true},
42 {tag:'option', html:"Dansk", value:'da-DK', disabled:true},
43 {tag:'option', html:"Deutsch", value:'de-DE'/ *, disabled:true* /},
44 {tag:'option', html:"English (American)", value:'en-US'/ *, disabled:true* /},
45 {tag:'option', html:"English (British)", value:'en-GB'/ *, disabled:true* /},
46 {tag:'option', html:"English (Canadian)", value:'en-CA'/ *, disabled:true* /},
47 {tag:'option', html:"Español", value:'es-ES', disabled:true},
48 {tag:'option', html:"Eesti", value:'et-EE', disabled:true},
49 {tag:'option', html:"Français", value:'fr-FR', disabled:true},
50 {tag:'option', html:"Galego", value:'gl-ES', disabled:true},
51 {tag:'option', html:"Greek (Ελληνικά)", value:'el-GR', disabled:true},
52 {tag:'option', html:"Íslenska", value:'is-IS', disabled:true},
53 {tag:'option', html:"Italiano", value:'it-IT'/ *, disabled:true* /},
54 {tag:'option', html:"Japanese (日本語)", value:'ja-JP', disabled:true},
55 {tag:'option', html:"Korean (한국어)", value:'ko-KR', disabled:true},
56 {tag:'option', html:"Latviešu", value:'lv-LV', disabled:true},
57 {tag:'option', html:"Lietuvių", value:'lt-LT', disabled:true},
58 {tag:'option', html:"Macedonian (Македонски)", value:'mk-MK', disabled:true},
59 {tag:'option', html:"Magyar", value:'hu-HU', disabled:true},
60 {tag:'option', html:"Nederlands", value:'nl-NL', disabled:true},
61 {tag:'option', html:"Norsk bokmål", value:'nb-NO', disabled:true},
62 {tag:'option', html:"Norsk nynorsk", value:'nn-NO', disabled:true},
63 {tag:'option', html:"Persian (Western) (فارسى)", value:'fa-IR', disabled:true},
64 {tag:'option', html:"Polski", value:'pl-PL', disabled:true},
65 {tag:'option', html:"Português", value:'pt-PT'/ *, disabled:true* /},
66 {tag:'option', html:"Português Brasileiro", value:'pt-BR'/ *, disabled:true* /},
67 {tag:'option', html:"Românä", value:'ro-RO', disabled:true},
68 {tag:'option', html:"Russian (Русский)", value:'ru-RU', disabled:true},
69 {tag:'option', html:"Slovak (Slovenčina)", value:'sk-SK', disabled:true},
70 {tag:'option', html:"Slovenian (Slovenščina)", value:'sl-SI', disabled:true},
71 {tag:'option', html:"Suomi", value:'fi-FI', disabled:true},
72 {tag:'option', html:"Svenska", value:'sv-SE', disabled:true},
73 {tag:'option', html:"Thai (ไทย)", value:'th-TH', disabled:true},
74 {tag:'option', html:"Türkçe", value:'tr-TR', disabled:true},
75 {tag:'option', html:"Ukrainian (Українська)", value:'uk-UA', disabled:true}
76* /
77 {tag:'option', html:"Arabic (العربية)", value:"ar", disabled:true, cls:'disabledOption'},
78 // {tag:'option', html:"Chinese (中文)", value:"zh", disabled:true},
79 {tag:'option', html:"Chinese (Simplified) (简体中文)", value:'zh-CN'},
80 {tag:'option', html:"Dutch (Nederlands)", value:"nl-NL", disabled:true, cls:'disabledOption'},
81 {tag:'option', html:"English", value:"en-US"},
82 {tag:'option', html:"French (Français)", value:"fr-FR"},
83 {tag:'option', html:"German (Deutsch)", value:"de-DE", disabled:true, cls:'disabledOption'},
84 {tag:'option', html:"Greek (Ελληνικά)", value:"el-GR", disabled:true, cls:'disabledOption'},
85 {tag:'option', html:"Hebrew (עברית)", value:"he-IL", disabled:true, cls:'disabledOption'},
86 {tag:'option', html:"Italian (Italiano)", value:"it-IT"},
87 {tag:'option', html:"Japanese (日本語)", value:"ja-JP"},
88 {tag:'option', html:"Korean (한국어)", value:"ko-KR", disabled:true, cls:'disabledOption'},
89 {tag:'option', html:"Norwegian (Norsk)", value:"no", disabled:true, cls:'disabledOption'},
90 {tag:'option', html:"Persian (فارسی)", value:"fa-IR", disabled:true, cls:'disabledOption'},
91 {tag:'option', html:"Polish (Polski)", value:"pl-PL", disabled:true, cls:'disabledOption'},
92 {tag:'option', html:"Portuguese (Português)", value:"pt-BR"},
93 {tag:'option', html:"Russian (Русский)", value:"ru-RU", disabled:true, cls:'disabledOption'},
94 {tag:'option', html:"Spanish (Español)", value:"es-ES"},
95 {tag:'option', html:"Swedish (Svenska)", value:"sv-SE", disabled:true, cls:'disabledOption'},
96 {tag:'option', html:"Turkish (Türkçe)", value:"tr-TR", disabled:true, cls:'disabledOption'},
97 {tag:'option', html:"Vietnamese (Tiếng Việt)", value:"vi-VN", disabled:true, cls:'disabledOption'}
98 ]
99}
100*/
101
102Clipperz.PM.Strings.GeneralSettings = {
103 'defaults': {
104 // 'loginFormAarghThatsBadUrl':"http://www.clipperz.com/support/faq/account_faq",
105 // 'loginFormVerifyTheCodeUrl':"http://www.clipperz.com/learn_more/reviewing_the_code",
106
107 // 'donateHeaderLinkUrl': "http://www.clipperz.com/donations",
108 // 'creditsHeaderLinkUrl': "http://www.clipperz.com/credits",
109 // 'feedbackHeaderLinkUrl': "http://www.clipperz.com/contact",
110 // 'helpHeaderLinkUrl': "http://www.clipperz.com/support/user_guide",
111 // 'forumHeaderLinkUrl': "http://www.clipperz.com/forum",
112
113 // 'httpAuthBookmarkletConfiguration':{tag:'textarea', id:'httpAuthDefaultConfiguration', html:"" +
114 // "{ \"page\":{\"title\":\"HTTP authentication\"}," + "\n" +
115 // " \"form\":{\"attributes\": {" + "\n" +
116 // " \"action\":\"\"," + "\n" +
117 // " \"type\":\"http_auth\"" + "\n" +
118 // " }, \"inputs\": [" + "\n" +
119 // " {\"type\":\"text\",\"name\":\"url\",\"value\":\"\"}," + "\n" +
120 // " {\"type\":\"text\",\"name\":\"username\",\"value\":\"\"}," + "\n" +
121 // " {\"type\":\"password\",\"name\":\"password\",\"value\":\"\"}" + "\n" +
122 // " ]}, \"version\":\"0.2.3\"}"
123 // },
124
125 'directLoginJumpPageUrl':"",
126 'defaultFaviconUrl': "data:application/octet-stream;charset=utf-8;base64,AAABAAEAFxcAAAEAGAD8BgAAFgAAACgAAAAXAAAALgAAAAEAGAAAAAAAAAAAABIXAAASFwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////9zAC////////////////////////////////////////////////////////////////////////////////////////////9pAG////////////////////////////////////////////////////////////////////////////////////////////9rAC////////////////////////////////////////////////////////////////////////////////////////////9yAHP////////////////////////IyMizs7O6urrq6ur////////////Ozs6zs7Ozs7Pq6ur///////////////////////8AAAD////////////////////V1dWXl5eXl5eXl5elpaX4+Pj////Ozs6Xl5eXl5eXl5eenp7///////////////////////8AAAD////////////////////Ozs6Xl5eXl5eXl5eXl5fBwcHq6uqenp6Xl5eXl5eXl5eXl5f///////////////////////8AAAD////////////////////j4+OXl5eXl5eXl5eXl5eXl5elpaWXl5eXl5eXl5eXl5ezs7P///////////////////////8AAAD////////////////////////IyMiXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eenp7x8fH////////////////////////////////////////////////////4+PilpaWXl5eXl5eXl5eXl5eXl5eXl5eXl5fOzs7////////////////////////////////////////////////////////q6uq6urqXl5eXl5eXl5eXl5eXl5eXl5eenp7V1dX4+Pj///////////////////////8AAAD////////////4+PjOzs6lpaWXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5e6urrj4+P///////////////8AAAD////////////BwcGXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5fx8fH///////////8AAAD///////////+zs7OXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5fj4+P///////////8AAAD////////////IyMiXl5eXl5eXl5eXl5e6urqXl5eXl5eXl5eXl5esrKylpaWXl5eXl5eXl5eenp7x8fH///////////8AAAD////////////////Ozs7Ozs7V1dX4+Pj///+Xl5eXl5eXl5eXl5fOzs7////q6urOzs7Ozs7q6ur///////////////8AAAD///////////////////////////////////+Xl5eXl5eXl5eXl5fOzs7///////////////////////////////////8AAAD///////////////////////////////////+Xl5eXl5eXl5eXl5fOzs7///////////////////////////////////8AAAD///////////////////////////////////+Xl5eXl5eXl5eXl5fOzs7///////////////////////////////////8AAAD////////////////////////////////////IyMiXl5eXl5eenp7x8fH///////////////////////////////////8AAAD////////////////////////////////////////j4+Pj4+Px8fH///////////////////////////////////////8AAAD///////////////////////////////////////////////////////////////////////////////////////////8AAAD///////////////////////////////////////////////////////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo=",
127 'defaultFaviconUrl_IE': "https://www.clipperz.com/images/icons/misc/favicon.ico",
128
129 // 'icons_baseUrl':"https://www.clipperz.com/images/icons",
130
131 // 'passwordGeneratorLowercaseCharset':"abcdefghijklmnopqrstuvwxyz",
132 // 'passwordGeneratorUppercaseCharset':"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
133 // 'passwordGeneratorNumberCharset': "0123456789",
134 // 'passwordGeneratorSymbolCharset': "!@#$%^&*+?[]{}/|\\<>,.;:~=-_",
135
136 // 'passwordGenerator': {
137 // 'lowercaseCharset':"abcdefghijklmnopqrstuvwxyz",
138 // 'uppercaseCharset':"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
139 // 'numberCharset':"0123456789",
140 // 'symbolCharset':"!@#$%^&*+?[]{}/|\\<>,.;:~=-_",
141 // },
142
143 '_': ""
144 }
145}
146
147Clipperz.PM.Strings.defaultLanguages = {
148 'default':"en-us",
149
150 // 'de':"de-de",
151 // 'el':"el-gr",
152 // 'he':"he-il",
153 // 'ru':"ru-ru",
154
155 'fr':"fr-fr",
156 'es':"es-es",
157 'zh':"zh-cn",
158 'ja':"ja-jp",
159 'pt':"pt-br",
160 'it':"it-it",
161 'en': "en-us"
162}
163
164Clipperz.PM.Strings.inputTypeToRecordFieldType = {
165 'text': 'TXT',
166 'password': 'PWD',
167 'checkbox': 'CHECK',
168 'radio': 'RADIO',
169 'select': 'SELECT'
170};
171
172//-----------------------------------------------------------------------------
173
174Clipperz.PM.Strings.translateBookmarklet = function (aBookmarkletString) {
175 var result;
176
177 result = aBookmarkletString;
178
179 result = result.replace(/@BOOKMARKLET_NO_EXCEPTION_MESSAGE@/,Clipperz.PM.Strings.getValue('bookmarkletCopy.noExceptionMessage'));
180 result = result.replace(/@BOOKMARKLET_EXCEPTION_MESSAGE@/, Clipperz.PM.Strings.getValue('bookmarkletCopy.exceptionMessage'));
181 result = result.replace(/@BOOKMARKLET_COPY@/, Clipperz.PM.Strings.getValue('bookmarkletCopy.copy'));
182 result = result.replace(/@BOOKMARKLET_SUCCESSFUL_MESSAGE@/, Clipperz.PM.Strings.getValue('bookmarkletCopy.successfulMessage'));
183 result = result.replace(/@BOOKMARKLET_FAIL_MESSAGE@/, Clipperz.PM.Strings.getValue('bookmarkletCopy.failMessage'));
184
185 return result;
186}
187
188//-----------------------------------------------------------------------------
189
190Clipperz.PM.Strings.Languages.setSelectedLanguage = function(aLanguage) {
191 var language;
192 varselectedLanguage;
193
194 language = (aLanguage || Clipperz.PM.Strings.preferredLanguage || 'default').toLowerCase();
195 if (typeof(Clipperz.PM.Strings.defaultLanguages[language]) != 'undefined') {
196 language = Clipperz.PM.Strings.defaultLanguages[language];
197 }
198
199 if (typeof(Clipperz.PM.Strings.Languages[language]) != 'undefined') {
200 selectedLanguage = language;
201 } else if (typeof(Clipperz.PM.Strings.defaultLanguages[language.substr(0,2)]) != 'undefined') {
202 selectedLanguage = Clipperz.PM.Strings.defaultLanguages[language.substr(0,2)];
203 } else {
204 selectedLanguage = Clipperz.PM.Strings.defaultLanguages['default'];
205 }
206
207 if (selectedLanguage != Clipperz.PM.Strings.selectedLanguage) {
208 vartranslations;
209
210 Clipperz.PM.Strings.selectedLanguage = selectedLanguage;
211
212 translations = {};
213 // MochiKit.Base.update(translations, Clipperz.PM.Strings.standardStrings)
214
215 MochiKit.Base.updatetree(translations, Clipperz.PM.Strings.Languages['defaults']);
216 MochiKit.Base.updatetree(translations, Clipperz.PM.Strings.GeneralSettings['defaults']);
217
218 MochiKit.Base.updatetree(translations, Clipperz.PM.Strings.Languages[Clipperz.PM.Strings.defaultLanguages['default']]);
219 MochiKit.Base.updatetree(translations, Clipperz.PM.Strings.GeneralSettings[Clipperz.PM.Strings.defaultLanguages['default']]);
220
221 MochiKit.Base.updatetree(translations, Clipperz.PM.Strings.Languages[selectedLanguage]);
222 MochiKit.Base.updatetree(translations, Clipperz.PM.Strings.GeneralSettings[selectedLanguage]);
223
224 Clipperz.PM.Strings.stringsObjectStore = new Clipperz.KeyValueObjectStore(/*{'name':'String.stringsObjectStore [1]'}*/);
225 Clipperz.PM.Strings.stringsObjectStore.initWithValues(translations);
226
227 if (typeof(bookmarklet) != 'undefined') {
228 Clipperz.PM.Strings.stringsObjectStore.setValue('bookmarklet', Clipperz.PM.Strings.translateBookmarklet(bookmarklet));
229 }
230
231 MochiKit.Signal.signal(Clipperz.PM.Strings.Languages, 'switchLanguage', selectedLanguage);
232 }
233}
234
235//-----------------------------------------------------------------------------
236
237Clipperz.PM.Strings.getValue = function (aKeyPath, someKeyValues) {
238 varresult;
239
240 result = Clipperz.PM.Strings.stringsObjectStore.getValue(aKeyPath);
241
242 if (typeof(result) == 'string') {
243 if (typeof (someKeyValues) != 'undefined') {
244 varkey;
245
246 for (key in someKeyValues) {
247 result = result.replace( new RegExp(key), someKeyValues[key]);
248 }
249 }
250
251 result = result.replace(new RegExp('\n'), '<br>');
252 }
253
254 return result;
255}
256
257Clipperz.PM.Strings.errorDescriptionForException = function (anException) {
258 var result;
259
260 result = Clipperz.PM.Strings.getValue('exceptionsMessages' + '.' + anException.name);
261
262 if (result == null) {
263 result = anException.message;
264 }
265
266 return result;
267},
268
269//-----------------------------------------------------------------------------
270
271Clipperz.PM.Strings.Languages.initSetup = function() {
272 varlanguage;
273 varlanguageParser;
274
275 language = navigator.language || navigator.userLanguage; //en, en-US, .... "de", "nb-no"
276 languageParser = new RegExp("language=([a-z]{2}(?:\-[a-z]{2})?)(\&|$)", "i");
277 if (languageParser.test(window.location.search)) {
278 language = RegExp.$1;
279 }
280
281 Clipperz.PM.Strings.preferredLanguage = language.toLowerCase();
282 Clipperz.PM.Strings.Languages.setSelectedLanguage(Clipperz.PM.Strings.preferredLanguage);
283}
284
285//-----------------------------------------------------------------------------
diff --git a/frontend/delta/js/Clipperz/PM/Strings/MessagePanelConfigurations.js b/frontend/delta/js/Clipperz/PM/Strings/MessagePanelConfigurations.js
new file mode 100644
index 0000000..7565d2d
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Strings/MessagePanelConfigurations.js
@@ -0,0 +1,384 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.Strings) == 'undefined') { Clipperz.PM.Strings = {}; }
27
28Clipperz.PM.Strings.messagePanelConfigurations = {
29
30
31 //-------------------------------------------------------------------------
32 //
33 // Registration - connection
34 //
35 'registration_verify': function() {
36 return {
37 'title': null,
38 'text': Clipperz.PM.Strings['connectionRegistrationSendingRequestMessageText']
39 }
40 },
41
42 'registration_sendingCredentials': function() {
43 return {
44 'title': null,
45 'text': Clipperz.PM.Strings['connectionRegistrationSendingCredentialsMessageText']
46 }
47 },
48
49 //-------------------------------------------------------------------------
50 //
51 // One Time Password login message panel
52 //
53
54 'OTP_login_start': function() {
55 return {
56 'title': Clipperz.PM.Strings['OTPloginMessagePanelInitialTitle'],
57 'text': Clipperz.PM.Strings['OTPloginMessagePanelInitialText'],
58 'steps': '+3',
59 'buttons': {}
60 }
61 },
62
63 'OTP_login_loadingOTP': function() {
64 return {
65 'title': Clipperz.PM.Strings['OTPloginMessagePanelLoadingTitle'],
66 'text': Clipperz.PM.Strings['OTPloginMessagePanelLoadingText']
67 }
68 },
69
70 'OTP_login_extractingPassphrase': function() {
71 return {
72 'title': Clipperz.PM.Strings['OTPloginMessagePanelProcessingTitle'],
73 'text': Clipperz.PM.Strings['OTPloginMessagePanelProcessingText']
74 }
75 },
76
77
78 //-------------------------------------------------------------------------
79 //
80 // Login message panel
81 //
82 'login_start': function() {
83 return {
84 'title': Clipperz.PM.Strings['loginMessagePanelInitialTitle'],
85 'text': Clipperz.PM.Strings['loginMessagePanelInitialText'],
86 'steps': '+7',
87 'buttons': {
88 'ok': Clipperz.PM.Strings['loginMessagePanelInitialButtonLabel']
89 }
90 }
91 },
92
93 'login_connected': function() {
94 return {
95 'title': Clipperz.PM.Strings['loginMessagePanelConnectedTitle'],
96 'text': Clipperz.PM.Strings['loginMessagePanelConnectedText'],
97 'buttons': {}
98 }
99 },
100
101 'login_failed':function() {
102 return {
103 'title': Clipperz.PM.Strings['loginMessagePanelFailureTitle'],
104 'text': Clipperz.PM.Strings['loginMessagePanelFailureText'],
105 'button': Clipperz.PM.Strings['loginMessagePanelFailureButtonLabel']
106 }
107 },
108
109 //-------------------------------------------------------------------------
110 //
111 // Login message panel - connection
112 //
113 'connection_sendingCredentials': function() {
114 return {
115 'title': Clipperz.PM.Strings['connectionLoginSendingCredentialsMessageTitle'],
116 'text': Clipperz.PM.Strings['connectionLoginSendingCredentialsMessageText']
117 }
118 },
119
120 'connection_credentialVerification': function() {
121 return {
122 'title': Clipperz.PM.Strings['connectionLoginCredentialsVerificationMessageTitle'],
123 'text': Clipperz.PM.Strings['connectionLoginCredentialsVerificationMessageText']
124 }
125 },
126
127 'connection_loggedIn': function() {
128 return {
129 'title': Clipperz.PM.Strings['connectionLoginDoneMessageTitle'],
130 'text': Clipperz.PM.Strings['connectionLoginDoneMessageText']
131 }
132 },
133
134 //-------------------------------------------------------------------------
135 //
136 //Login message panel - user
137 //
138 'connection_upgrading': function() {
139 return {
140 'title': Clipperz.PM.Strings['userLoginPanelUpgradingUserCredentialsMessageTitle'],
141 'text': Clipperz.PM.Strings['userLoginPanelUpgradingUserCredentialsMessageText'],
142 'steps': '+1'
143 }
144 },
145
146 'connection_done': function() {
147 return {
148 'title': Clipperz.PM.Strings['userLoginPanelConnectedMessageTitle'],
149 'text': Clipperz.PM.Strings['userLoginPanelConnectedMessageText']
150 }
151 },
152
153 'connection_tryOlderSchema': function() {
154 return {
155 'title': Clipperz.PM.Strings['userLoginPanelTryingAnOlderConnectionSchemaMessageTitle'],
156 'text': Clipperz.PM.Strings['userLoginPanelTryingAnOlderConnectionSchemaMessageText'],
157 'steps': '+4'
158 }
159 },
160
161 'connection_loadingUserData': function() {
162 return {
163 'title': Clipperz.PM.Strings['userLoginPanelLoadingUserDataMessageTitle'],
164 'text': Clipperz.PM.Strings['userLoginPanelLoadingUserDataMessageText']
165 }
166 },
167
168 'connection_decryptingUserData': function() {
169 return {
170 'title': Clipperz.PM.Strings['userLoginPanelDecryptingUserDataMessageTitle'],
171 'text': Clipperz.PM.Strings['userLoginPanelDecryptingUserDataMessageText'],
172 'steps': '+1'
173 }
174 },
175
176 'connection_decryptingUserStatistics': function() {
177 return {
178 'title': Clipperz.PM.Strings['userLoginPanelDecryptingUserStatisticsMessageTitle'],
179 'text': Clipperz.PM.Strings['userLoginPanelDecryptingUserStatisticsMessageText']
180 }
181 },
182
183 'collectingEntropy': function() {
184 return {
185 'text': Clipperz.PM.Strings['panelCollectingEntryopyMessageText'],
186 'steps': '+1'
187 }
188 },
189
190 //-------------------------------------------------------------------------
191 //
192 // Cards block - delete card panel
193 //
194 'deleteRecord_collectData': function() {
195 return {
196 'title': Clipperz.PM.Strings['deleteRecordPanelCollectRecordDataMessageTitle'],
197 'text': Clipperz.PM.Strings['deleteRecordPanelCollectRecordDataMessageText']
198 }
199 },
200
201 'deleteRecord_encryptData': function() {
202 return {
203 'title': Clipperz.PM.Strings['deleteRecordPanelEncryptUserDataMessageTitle'],
204 'text': Clipperz.PM.Strings['deleteRecordPanelEncryptUserDataMessageText']
205 }
206 },
207
208 'deleteRecord_sendingData': function() {
209 return {
210 'title': Clipperz.PM.Strings['deleteRecordPanelSendingDataToTheServerMessageTitle'],
211 'text': Clipperz.PM.Strings['deleteRecordPanelSendingDataToTheServerMessageText']
212 }
213 },
214
215 'deleteRecord_updatingInterface': function() {
216 return {
217 'title': Clipperz.PM.Strings['deleteRecordPanelUpdatingTheInterfaceMessageTitle'],
218 'text': Clipperz.PM.Strings['deleteRecordPanelUpdatingTheInterfaceMessageText']
219 }
220 },
221
222
223 //-------------------------------------------------------------------------
224 //
225 //Cards block - save card panel
226 //
227 'saveCard_collectRecordInfo': function() {
228 return {
229 'title': Clipperz.PM.Strings['recordSaveChangesPanelCollectRecordInfoMessageTitle'],
230 'text': Clipperz.PM.Strings['recordSaveChangesPanelCollectRecordInfoMessageText']
231 }
232 },
233
234 'saveCard_encryptUserData': function() {
235 return {
236 'title': Clipperz.PM.Strings['recordSaveChangesPanelEncryptUserDataMessageTitle'],
237 'text': Clipperz.PM.Strings['recordSaveChangesPanelEncryptUserDataMessageText']
238 }
239 },
240
241 'saveCard_encryptRecordData': function() {
242 return {
243 'title': Clipperz.PM.Strings['recordSaveChangesPanelEncryptRecordDataMessageTitle'],
244 'text': Clipperz.PM.Strings['recordSaveChangesPanelEncryptRecordDataMessageText']
245 }
246 },
247
248 'saveCard_encryptRecordVersions': function() {
249 return {
250 'title': Clipperz.PM.Strings['recordSaveChangesPanelEncryptRecordVersionDataMessageTitle'],
251 'text': Clipperz.PM.Strings['recordSaveChangesPanelEncryptRecordVersionDataMessageText']
252 }
253 },
254
255 'saveCard_sendingData': function() {
256 return {
257 'title': Clipperz.PM.Strings['recordSaveChangesPanelSendingDataToTheServerMessageTitle'],
258 'text': Clipperz.PM.Strings['recordSaveChangesPanelSendingDataToTheServerMessageText']
259 }
260 },
261
262 'saveCard_updatingInterface': function() {
263 return {
264 'title': Clipperz.PM.Strings['recordSaveChangesPanelUpdatingTheInterfaceMessageTitle'],
265 'text': Clipperz.PM.Strings['recordSaveChangesPanelUpdatingTheInterfaceMessageText']
266 }
267 },
268
269 //-------------------------------------------------------------------------
270 //
271 //Account panel - user preferences
272 //
273 'account_savingPreferences_1': function() {
274 return {
275 'title': Clipperz.PM.Strings['accountPreferencesSavingPanelTitle_Step1'],
276 'text': Clipperz.PM.Strings['accountPreferencesSavingPanelText_Step1'],
277 'steps': '+3'
278 }
279 },
280
281 'account_savingPreferences_2': function() {
282 return {
283 'title': Clipperz.PM.Strings['accountPreferencesSavingPanelTitle_Step2'],
284 'text': Clipperz.PM.Strings['accountPreferencesSavingPanelText_Step2']
285 }
286 },
287
288
289 //-------------------------------------------------------------------------
290 //
291 //Account panel - change credentials
292 //
293 'changeCredentials_encryptingData': function() {
294 return {
295 'title': Clipperz.PM.Strings['changeCredentialsPanelEncryptingDataMessageTitle'],
296 'text': Clipperz.PM.Strings['changeCredentialsPanelEncryptingDataMessageText']
297 }
298 },
299
300 'changeCredentials_creatingNewCredentials': function() {
301 return {
302 'title': Clipperz.PM.Strings['changeCredentialsPanelCreatingNewCredentialsMessageTitle'],
303 'text': Clipperz.PM.Strings['changeCredentialsPanelCreatingNewCredentialsMessageText']
304 }
305 },
306
307 'changeCredentials_sendingCredentials': function() {
308 return {
309 'title': Clipperz.PM.Strings['changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle'],
310 'text': Clipperz.PM.Strings['changeCredentialsPanelSendingNewCredentialsToTheServerMessageText']
311 }
312 },
313
314 'changeCredentials_done': function() {
315 return {
316 'title': Clipperz.PM.Strings['changeCredentialsPanelDoneMessageTitle'],
317 'text': Clipperz.PM.Strings['changeCredentialsPanelDoneMessageText']
318 }
319 },
320
321
322 //-------------------------------------------------------------------------
323 //
324 //Account panel - change credentials
325 //
326 'saveOTP_encryptUserData': function() {
327 return {
328 'title': Clipperz.PM.Strings['saveOTP_encryptUserDataTitle'],
329 'text': Clipperz.PM.Strings['saveOTP_encryptUserDataText'],
330 'steps': '+4'
331 }
332 },
333
334 'saveOTP_encryptOTPData': function() {
335 return {
336 'title': Clipperz.PM.Strings['saveOTP_encryptOTPDataTitle'],
337 'text': Clipperz.PM.Strings['saveOTP_encryptOTPDataText']
338 }
339 },
340
341 'saveOTP_sendingData': function() {
342 return {
343 'title': Clipperz.PM.Strings['saveOTP_sendingDataTitle'],
344 'text': Clipperz.PM.Strings['saveOTP_sendingDataText']
345 }
346 },
347
348 'saveOTP_updatingInterface': function() {
349 return {
350 'title': Clipperz.PM.Strings['saveOTP_updatingInterfaceTitle'],
351 'text': Clipperz.PM.Strings['saveOTP_updatingInterfaceText']
352 }
353 },
354
355
356 //-------------------------------------------------------------------------
357 //
358 //Data panel - processingImportData
359 //
360 'parseImportData': function() {
361 return {
362 'title': Clipperz.PM.Strings['importData_parsingDataTitle'],
363 'text': Clipperz.PM.Strings['importData_parsingDataText']
364 }
365 },
366
367 'previewImportData': function() {
368 return {
369 'title': Clipperz.PM.Strings['importData_previewingDataTitle'],
370 'text': Clipperz.PM.Strings['importData_previewingDataText']
371 }
372 },
373
374 'processingImportData': function() {
375 return {
376 'title': Clipperz.PM.Strings['importData_processingDataTitle'],
377 'text': Clipperz.PM.Strings['importData_processingDataText']
378 }
379 },
380
381 //-------------------------------------------------------------------------
382 __syntaxFix__: "syntax fix"
383
384}
diff --git a/frontend/delta/js/Clipperz/PM/Strings/Strings_defaults.js b/frontend/delta/js/Clipperz/PM/Strings/Strings_defaults.js
new file mode 100644
index 0000000..aefd94a
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Strings/Strings_defaults.js
@@ -0,0 +1,385 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26if (typeof(Clipperz.PM.Strings) == 'undefined') { Clipperz.PM.Strings = {}; }
27if (typeof(Clipperz.PM.Strings.Languages) == 'undefined') { Clipperz.PM.Strings.Languages = {}; }
28
29//=============================================================================
30//
31 // D E F A U L T S ( defaults )
32//
33//=============================================================================
34
35Clipperz.PM.Strings.Languages['defaults'] = {
36
37'elapsedTimeDescriptions': {
38 'MORE_THAN_A_MONTH_AGO': "more than a month ago",
39 'MORE_THAN_A_WEEK_AGO': "more than a week ago",
40 'MORE_THAN_*_WEEKS_AGO': "more than __elapsed__ weeks ago",
41 'YESTERDAY': "yesterday",
42 '*_DAYS_AGO': "__elapsed__ days ago",
43 'ABOUT_AN_HOUR_AGO': "about an hour ago",
44 '*_HOURS_AGO': "__elapsed__ hours ago",
45 'JUST_A_FEW_MINUTES_AGO': "just a few minutes ago",
46 'ABOUT_*_MINUTES_AGO': "about __elapsed__ minutes ago"
47},
48/*
49 'unknown_ip': "unknown",
50
51'countries': {
52 '--': "unknown",
53 'AD': "Andorra",
54 'AE': "United Arab Emirates",
55 'AF': "Afghanistan",
56 'AG': "Antigua and Barbuda",
57 'AI': "Anguilla",
58 'AL': "Albania",
59 'AM': "Armenia",
60 'AN': "Netherlands Antilles",
61 'AO': "Angola",
62 'AP': "Non-Spec Asia Pas Location",
63 'AR': "Argentina",
64 'AS': "American Samoa",
65 'AT': "Austria",
66 'AU': "Australia",
67 'AW': "Aruba",
68 'AX': "Aland Islands",
69 'AZ': "Azerbaijan",
70 'BA': "Bosnia and Herzegowina",
71 'BB': "Barbados",
72 'BD': "Bangladesh",
73 'BE': "Belgium",
74 'BF': "Burkina Faso",
75 'BG': "Bulgaria",
76 'BH': "Bahrain",
77 'BI': "Burundi",
78 'BJ': "Benin",
79 'BM': "Bermuda",
80 'BN': "Brunei Darussalam",
81 'BO': "Bolivia",
82 'BR': "Brazil",
83 'BS': "Bahamas",
84 'BT': "Bhutan",
85 'BW': "Botswana",
86 'BY': "Belarus",
87 'BZ': "Belize",
88 'CA': "Canada",
89 'CD': "Congo the Democratic Republic of the",
90 'CF': "Central African Republic",
91 'CH': "Switzerland",
92 'CI': "Cote D'ivoire",
93 'CK': "Cook Islands",
94 'CL': "Chile",
95 'CM': "Cameroon",
96 'CN': "China",
97 'CO': "Colombia",
98 'CR': "Costa Rica",
99 'CS': "Serbia and Montenegro",
100 'CU': "Cuba",
101 'CY': "Cyprus",
102 'CZ': "Czech Republic",
103 'DE': "Germany",
104 'DJ': "Djibouti",
105 'DK': "Denmark",
106 'DO': "Dominican Republic",
107 'DZ': "Algeria",
108 'EC': "Ecuador",
109 'EE': "Estonia",
110 'EG': "Egypt",
111 'ER': "Eritrea",
112 'ES': "Spain",
113 'ET': "Ethiopia",
114 'EU': "European Union",
115 'FI': "Finland",
116 'FJ': "Fiji",
117 'FM': "Micronesia Federated States of",
118 'FO': "Faroe Islands",
119 'FR': "France",
120 'GA': "Gabon",
121 'GB': "United Kingdom",
122 'GD': "Grenada",
123 'GE': "Georgia",
124 'GF': "French Guiana",
125 'GG': "Guernsey",
126 'GH': "Ghana",
127 'GI': "Gibraltar",
128 'GL': "Greenland",
129 'GM': "Gambia",
130 'GP': "Guadeloupe",
131 'GR': "Greece",
132 'GT': "Guatemala",
133 'GU': "Guam",
134 'GW': "Guinea-Bissau",
135 'GY': "Guyana",
136 'HK': "Hong Kong",
137 'HN': "Honduras",
138 'HR': "Croatia (Local Name: Hrvatska)",
139 'HT': "Haiti",
140 'HU': "Hungary",
141 'ID': "Indonesia",
142 'IE': "Ireland",
143 'IL': "Israel",
144 'IM': "Isle of Man",
145 'IN': "India",
146 'IO': "British Indian Ocean Territory",
147 'IQ': "Iraq",
148 'IR': "Iran (Islamic Republic of)",
149 'IS': "Iceland",
150 'IT': "Italy",
151 'JE': "Jersey",
152 'JM': "Jamaica",
153 'JO': "Jordan",
154 'JP': "Japan",
155 'KE': "Kenya",
156 'KG': "Kyrgyzstan",
157 'KH': "Cambodia",
158 'KI': "Kiribati",
159 'KN': "Saint Kitts and Nevis",
160 'KR': "Korea Republic of",
161 'KW': "Kuwait",
162 'KY': "Cayman Islands",
163 'KZ': "Kazakhstan",
164 'LA': "Lao People's Democratic Republic",
165 'LB': "Lebanon",
166 'LC': "Saint Lucia",
167 'LI': "Liechtenstein",
168 'LK': "Sri Lanka",
169 'LR': "Liberia",
170 'LS': "Lesotho",
171 'LT': "Lithuania",
172 'LU': "Luxembourg",
173 'LV': "Latvia",
174 'LY': "Libyan Arab Jamahiriya",
175 'MA': "Morocco",
176 'MC': "Monaco",
177 'MD': "Moldova Republic of",
178 'MG': "Madagascar",
179 'MH': "Marshall Islands",
180 'MK': "Macedonia the Former Yugoslav Republic of",
181 'ML': "Mali",
182 'MM': "Myanmar",
183 'MN': "Mongolia",
184 'MO': "Macau",
185 'MP': "Northern Mariana Islands",
186 'MR': "Mauritania",
187 'MS': "Montserrat",
188 'MT': "Malta",
189 'MU': "Mauritius",
190 'MV': "Maldives",
191 'MW': "Malawi",
192 'MX': "Mexico",
193 'MY': "Malaysia",
194 'MZ': "Mozambique",
195 'NA': "Namibia",
196 'NC': "New Caledonia",
197 'NF': "Norfolk Island",
198 'NG': "Nigeria",
199 'NI': "Nicaragua",
200 'NL': "Netherlands",
201 'NO': "Norway",
202 'NP': "Nepal",
203 'NR': "Nauru",
204 'NU': "Niue",
205 'NZ': "New Zealand",
206 'OM': "Oman",
207 'PA': "Panama",
208 'PE': "Peru",
209 'PF': "French Polynesia",
210 'PG': "Papua New Guinea",
211 'PH': "Philippines",
212 'PK': "Pakistan",
213 'PL': "Poland",
214 'PR': "Puerto Rico",
215 'PS': "Palestinian Territory Occupied",
216 'PT': "Portugal",
217 'PW': "Palau",
218 'PY': "Paraguay",
219 'QA': "Qatar",
220 'RO': "Romania",
221 'RS': "Serbia",
222 'RU': "Russian Federation",
223 'RW': "Rwanda",
224 'SA': "Saudi Arabia",
225 'SB': "Solomon Islands",
226 'SC': "Seychelles",
227 'SD': "Sudan",
228 'SE': "Sweden",
229 'SG': "Singapore",
230 'SI': "Slovenia",
231 'SK': "Slovakia (Slovak Republic)",
232 'SL': "Sierra Leone",
233 'SM': "San Marino",
234 'SN': "Senegal",
235 'SR': "Suriname",
236 'SV': "El Salvador",
237 'SY': "Syrian Arab Republic",
238 'SZ': "Swaziland",
239 'TC': "Turks and Caicos Islands",
240 'TG': "Togo",
241 'TH': "Thailand",
242 'TJ': "Tajikistan",
243 'TM': "Turkmenistan",
244 'TN': "Tunisia",
245 'TO': "Tonga",
246 'TR': "Turkey",
247 'TT': "Trinidad and Tobago",
248 'TV': "Tuvalu",
249 'TW': "Taiwan Province of China",
250 'TZ': "Tanzania United Republic of",
251 'UA': "Ukraine",
252 'UG': "Uganda",
253 'US': "United States",
254 'UY': "Uruguay",
255 'UZ': "Uzbekistan",
256 'VA': "Holy See (Vatican City State)",
257 'VE': "Venezuela",
258 'VG': "Virgin Islands (British)",
259 'VI': "Virgin Islands (U.S.)",
260 'VN': "Viet Nam",
261 'VU': "Vanuatu",
262 'WF': "Wallis and Futuna Islands",
263 'WS': "Samoa",
264 'YE': "Yemen",
265 'ZA': "South Africa",
266 'ZM': "Zambia",
267 'ZW': "Zimbabwe",
268 'ZZ': "Reserved"
269},
270
271'browsers': {
272 'UNKNOWN': "Unknown",
273 'MSIE': "Internet Explorer",
274 'FIREFOX': "Firefox",
275 'OPERA': "Opera",
276 'SAFARI': "Safari",
277 'OMNIWEB': "OmniWeb",
278 'CAMINO': "Camino",
279 'CHROME': "Chrome"
280},
281
282'operatingSystems': {
283 'UNKNOWN': "Unknown",
284 'WINDOWS': "Windows",
285 'MAC': "Mac",
286 'LINUX': "Linux",
287 'IPHONE': "iPhone",
288 'MOBILE': "Mobile",
289 'OPENBSD': "OpenBSD",
290 'FREEBSD': "FreeBSD",
291 'NETBSD': "NetBSD"
292},
293*/
294
295 //Calendar texts
296'calendarStrings': {
297 'months': {
298 '0':"January",
299 '1':"February",
300 '2':"March",
301 '3':"April",
302 '4':"May",
303 '5':"June",
304 '6':"July",
305 '7':"August",
306 '8':"September",
307 '9':"October",
308 '10':"November",
309 '11':"December"
310 },
311 'shortMonths':{
312 '0':"Jan",
313 '1':"Feb",
314 '2':"Mar",
315 '3':"Apr",
316 '4':"May",
317 '5':"Jun",
318 '6':"Jul",
319 '7':"Aug",
320 '8':"Sep",
321 '9':"Oct",
322 '10':"Nov",
323 '11':"Dec"
324 },
325
326 'days':{
327 '0':"Sunday",
328 '1':"Monday",
329 '2':"Tuesday",
330 '3':"Wednesday",
331 '4':"Thursday",
332 '5':"Friday",
333 '6':"Saturday"
334 },
335
336 'shortDays':{
337 '0':"Sun",
338 '1':"Mon",
339 '2':"Tue",
340 '3':"Wed",
341 '4':"Thu",
342 '5':"Fri",
343 '6':"Sat"
344 },
345
346 'veryShortDays':{
347 '0':"Su",
348 '1':"Mo",
349 '2':"Tu",
350 '3':"We",
351 '4':"Th",
352 '5':"Fr",
353 '6':"Sa"
354 },
355
356 'amDesignation':"am",
357 'pmDesignation':"pm"
358
359},
360
361// Date format
362 'fullDate_format':"l, F d, Y H:i:s",
363
364//################################################################################
365
366'pageHeader': {
367 'donation':"donate",
368 'forum':"forum",
369 'credits':"credits",
370 'feedback':"feedback",
371 'help': "help"
372},
373
374'bookmarkletCopy': {
375 'noExceptionMessage':"The direct login configuration has been collected.",
376 'exceptionMessage': "Sorry! There was an error while processing the page.",
377 'copy': "copy",
378 'successfulMessage':"DONE!",
379 'failMessage': "Failed! :("
380},
381
382//################################################################################
383
384__syntaxFix__: "syntax fix"
385}
diff --git a/frontend/delta/js/Clipperz/PM/Strings/Strings_en-US.js b/frontend/delta/js/Clipperz/PM/Strings/Strings_en-US.js
new file mode 100644
index 0000000..72460ba
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Strings/Strings_en-US.js
@@ -0,0 +1,1336 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24//=============================================================================
25//
26 // E N G L I S H A M E R I C A N ( en_US )
27//
28//=============================================================================
29
30Clipperz.PM.Strings.Languages['en-us'] = {
31/*
32 //Login page - description
33'clipperzServiceDescription': "\
34 <!-- FIX CSS DONE -->\
35 <h2>Keep it to yourself!</h2>\
36 <ul>\
37 <li>\
38 <h3>Clipperz is:</h3>\
39 <ul>\
40 <li><p>a secure and simple password manager</p></li>\
41 <li><p>an effective single sign-on solution</p></li>\
42 <li><p>a digital vault for your personal data</p></li>\
43 </ul>\
44 </li>\
45 <li>\
46 <h3>With Clipperz you can:</h3>\
47 <ul>\
48 <li><p>store and manage your passwords and online credentials</p></li>\
49 <li><p>login to your web services without entering any username or password</p></li>\
50 <li><p>protect all your sensitive data: codes for burglar alarms, PINs, credit card numbers, …</p></li>\
51 <li><p>share secrets with family members and associates (coming soon)</p></li>\
52 </ul>\
53 </li>\
54 <li>\
55 <h3>Clipperz benefits:</h3>\
56 <ul>\
57 <li><p>free and completely anonymous</p></li>\
58 <li><p>access it any time from any computer</p></li>\
59 <li><p>no software to download and nothing to install</p></li>\
60 <li><p>avoid keeping secrets on your PC or on paper</p></li>\
61 </ul>\
62 </li>\
63 <li>\
64 <h3>Clipperz security:</h3>\
65 <ul>\
66 <li><p>your secrets are locally encrypted by your browser before being uploaded to Clipperz</p></li>\
67 <li><p>the encryption key is a passphrase known only to you</p></li>\
68 <li><p>Clipperz hosts your sensitive data in encrypted form and could never actually access the data in its plain form</p></li>\
69 <li><p>Clipperz is built upon standard encryption schemes, nothing fancies or homemade</p></li>\
70 <li><p>you can review the source code anytime you like, but you need to know nothing about cryptography to be an happy user!</p></li>\
71 </ul>\
72 </li>\
73 <li>\
74 <a href=\"http://www.clipperz.com\" target=\"_blank\">Learn more</a>\
75 </li>\
76 </ul>",
77
78
79 'loginFormTitle': "login with your Clipperz account",
80 'loginFormUsernameLabel': "username",
81 'loginFormPassphraseLabel': "passphrase",
82 'loginFormDontHaveAnAccountLabel': "don\'t have an account?",
83 'loginFormCreateOneLabel': "create one",
84 'loginFormForgotYourCredentialsLabel': "forgot your credentials?",
85 'loginFormAarghThatsBadLabel': "aargh! that\'s bad!",
86 'loginFormAfraidOfMaliciousScriptsLabel': "afraid of malicious scripts?",
87 'loginFormVerifyTheCodeLabel': "verify the code",
88 'loginFormButtonLabel': "Login",
89 'loginFormOneTimePasswordCheckboxLabel': "use a one-time passphrase",
90'loginFormOneTimePasswordCheckboxDescription': "",
91
92// Login page - language selection
93 'loginPanelSwithLanguageDescription': "<h5>Switch to your preferred language</h5>",
94
95// Login page - browser compatibility
96 'browserCompatibilityDescription': "<p>Have a better and safer Clipperz experience with Firefox. However Clipperz works just fine also with Opera, Safari and MS Internet Explorer!</p>",
97
98// Login with OTP - message panel
99 'OTPloginMessagePanelInitialTitle': "Logging in using a one-time passphrase",
100 'OTPloginMessagePanelInitialText': "Sending OTP credentials …",
101 'OTPloginMessagePanelLoadingTitle': "Logging in using a one-time passphrase",
102 'OTPloginMessagePanelLoadingText': "Fetching encrypted authentication data from the server …",
103 'OTPloginMessagePanelProcessingTitle': "Logging in using a one-time passphrase",
104 'OTPloginMessagePanelProcessingText': "Local decryption of authentication data",
105
106// Regular login - message panel
107 'loginMessagePanelInitialTitle': "Logging in …",
108 'loginMessagePanelInitialText': "---",
109 'loginMessagePanelInitialButtonLabel': "Cancel",
110 'loginMessagePanelConnectedTitle': "Connected",
111 'loginMessagePanelConnectedText': "Done",
112 'loginMessagePanelFailureTitle': "Error",
113 'loginMessagePanelFailureText': "Login failed",
114 'loginMessagePanelFailureButtonLabel': "Close",
115
116// Regular login - message panel - connection
117 'connectionLoginSendingCredentialsMessageTitle': "Verifying credentials",
118 'connectionLoginSendingCredentialsMessageText': "Sending credentials",
119 'connectionLoginCredentialsVerificationMessageTitle':"Verifying credentials",
120 'connectionLoginCredentialsVerificationMessageText':"Performing SRP authentication",
121 'connectionLoginDoneMessageTitle': "Verifying credentials",
122 'connectionLoginDoneMessageText': "Connected",
123
124 //Regular login - message panel - user
125 'userLoginPanelUpgradingUserCredentialsMessageTitle': "Verifying credentials",
126 'userLoginPanelUpgradingUserCredentialsMessageText': "Upgrading your credentials to a new authentication schema",
127 'userLoginPanelConnectedMessageTitle': "User authenticated",
128 'userLoginPanelConnectedMessageText': "Successfully logged in",
129 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle': "Verifying credentials",
130 'userLoginPanelTryingAnOlderConnectionSchemaMessageText': "Trying an older authentication schema",
131 'userLoginPanelLoadingUserDataMessageTitle': "User authenticated",
132 'userLoginPanelLoadingUserDataMessageText': "Downloading encrypted card headers from Clipperz",
133 'userLoginPanelDecryptingUserDataMessageTitle': "User authenticated",
134 'userLoginPanelDecryptingUserDataMessageText': "Local decryption of card headers",
135 'userLoginPanelDecryptingUserStatisticsMessageTitle': "User authenticated",
136 'userLoginPanelDecryptingUserStatisticsMessageText': "Local decryption of usage statistics",
137
138 //Registration page - splash alert
139 'splashAlertTitle':"Welcome to Clipperz!",
140'splashAlertText': "\
141 <!-- FIX CSS DONE! -->\
142 <p>Some security advice</p>\
143 <ul>\
144 <li><p>Storing your data at Clipperz is as secure as the passphrase you choose to protect them. Nobody can access them unless they know your passphrase.</p></li>\
145 <li><p>If you are going to use Clipperz for safeguarding sensitive and critical information please make sure to use a strong passphrase. The longer the better!</p></li>\
146 <li><p>Clipperz will not be able to recover a lost passphrase!</p></li>\
147 </ul>\
148 <p>For any further information, please refer to <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a> website.</p>",
149 'splashAlertCloseButtonLabel':"Ok",
150
151 // Registration page - form
152 'registrationFormTitle': "create your account",
153 'registrationFormUsernameLabel': "username",
154 'registrationFormPassphraseLabel': "passphrase",
155 'registrationFormRetypePassphraseLabel': "re-enter passphrase",
156 'registrationFormSafetyCheckLabel': "I understand that Clipperz will not be able to recover a lost passphrase.",
157 'registrationFormTermsOfServiceCheckLabel': "I have read and agreed to the <a href='https://www.clipperz.com/terms_service' target='_blank'>Terms of Service</a>.",
158 'registrationFormDoYouAlreadyHaveAnAccountLabel': "do you already have an account?",
159 'registrationFormSimplyLoginLabel': "simply login",
160 'registrationFormButtonLabel': "Register",
161
162// Registration page - warning messages
163 'registrationFormWarningMessageNotMatchingPassphrases':"Your passphrases don't match, please re-type them.",
164 'registrationFormWarningMessageSafetyCheckNotSelected':"Please read and check all the boxes below.",
165 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"You need to agree to the Terms of Service.",
166
167 // Registration page - message panel
168 'registrationMessagePanelInitialTitle': "Creating account …",
169 'registrationMessagePanelInitialText': "---",
170 'registrationMessagePanelInitialButtonLabel': "Cancel",
171 'registrationMessagePanelRegistrationDoneTitle': "Registration",
172 'registrationMessagePanelRegistrationDoneText': "Done",
173 'registrationMessagePanelFailureTitle': "Registration failed",
174 'registrationMessagePanelFailureButtonLabel': "Close",
175
176// Registration page - message panel - connection
177 'connectionRegistrationSendingRequestMessageText': "Verifying credentials",
178 'connectionRegistrationSendingCredentialsMessageText':"Sending credentials",
179
180// Registration page - splash panel
181 'registrationSplashPanelTitle': "Security advice",
182 'registrationSplashPanelDescription': "<p>These are your Clipperz credentials, take good care of them. Clipperz will never display your username and passphrase a second time!</p>",
183 'registrationSplashPanelUsernameLabel': "username",
184 'registrationSplashPanelPassphraseLabel':"passphrase",
185
186 'registrationSplashPanelShowPassphraseButtonLabel':"show passphrase",
187
188 //Header links
189 'donateHeaderLinkLabel': "donate",
190 'creditsHeaderLinkLabel': "credits",
191 'feedbackHeaderLinkLabel': "feedback",
192 'helpHeaderLinkLabel': "help",
193 'forumHeaderLinkLabel': "forum",
194
195 //Menu labels
196 'recordMenuLabel': "cards",
197 'accountMenuLabel': "account",
198 'dataMenuLabel': "data",
199 'contactsMenuLabel': "contacts",
200 'toolsMenuLabel': "tools",
201 'logoutMenuLabel': "logout",
202 'lockMenuLabel': "lock",
203
204 //Lock dialog
205 'lockTitle': "The account is locked",
206 'lockDescription': "<p>To unlock your account, please enter your passphrase.</p>",
207 'unlockButtonLabel': "Unlock",
208
209 //Account panel - change passphrase
210 'changePasswordTabLabel': "Change your passphrase",
211 'changePasswordTabTitle': "Change your passphrase",
212
213 'changePasswordFormUsernameLabel': "username",
214 'changePasswordFormOldPassphraseLabel': "old passphrase",
215 'changePasswordFormNewPassphraseLabel': "new passphrase",
216 'changePasswordFormRetypePassphraseLabel':"re-enter new passphrase",
217 'changePasswordFormSafetyCheckboxLabel':"I understand that Clipperz will not be able to recover a lost passphrase.",
218 'changePasswordFormSubmitLabel': "Change passphrase",
219
220 //Account panel - change passphrase - warning messages
221 'changePasswordFormWrongUsernameWarning': "Wrong username",
222 'changePasswordFormWrongPassphraseWarning': "Wrong passphrase",
223 'changePasswordFormWrongRetypePassphraseWarning':"Your passphrases don't match, please re-type them.",
224 'changePasswordFormSafetyCheckWarning': "Please read and check the box below.",
225
226 //Account panel - change passphrase - progress dialog
227 'changePasswordFormProgressDialogTitle': "Changing user credentials",
228 'changePasswordFormProgressDialogEmptyText': "---",
229 'changePasswordFormProgressDialogConnectedMessageTitle': "Connected",
230 'changePasswordFormProgressDialogConnectedMessageText': "Done",
231 'changePasswordFormProgressDialogErrorMessageTitle': "Error",
232 'changePasswordFormProgressDialogErrorMessageText': "Credentials change failed!",
233
234 'changeCredentialsPanelEncryptingDataMessageTitle': "Changing your passphrase",
235 'changeCredentialsPanelEncryptingDataMessageText': "Local encryption of card headers",
236 'changeCredentialsPanelCreatingNewCredentialsMessageTitle': "Changing your passphrase",
237 'changeCredentialsPanelCreatingNewCredentialsMessageText': "Updating your credentials",
238 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Changing your passphrase",
239 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Uploading your encrypted credentials to Clipperz",
240 'changeCredentialsPanelDoneMessageTitle': "Changing your passphrase",
241 'changeCredentialsPanelDoneMessageText': "Done",
242
243 //Account panel - OTP
244 'manageOTPTabLabel': "Manage your one-time passphrases",
245 'manageOTPTabTitle': "Manage your one-time passphrases",
246
247 'manageOTPTabDescription':"\
248 <p>A one-time passphrase works like your regular passphrase, but can be used only once.</p>\
249 <p>If the same passphrase is used again at a later stage in a login attempt it will be rejected and the login process will fail.</p>\
250 <p>Immediately after a successful login, your one-time passphrase will be deleted preventing any fraudulent access.</p>\
251 <p>One-time passphrases are an excellent choice if one is concerned about keyloggers or spyware infections that may be collecting data from compromised machines.</p>\
252 <p><b>It's strongly advisable to use one-time passphrases when accessing Clipperz from public terminals, such as Internet cafes and libraries.</b></p>",
253
254 //Account panel - OTP - OTP table
255'oneTimePasswordReadOnlyMessage': "\
256 <h6>Sorry!</h6>\
257 <p>You cannot manage your one-time passphrases when using the offline version of Clipperz.</p>",
258
259 'oneTimePasswordLoadingMessage':"\
260 <h6>Loading data</h6>\
261 <p>Please wait …</p>",
262
263 'oneTimePasswordNoPasswordAvailable':"\
264 <h6>No one-time passphrase available</h6>\
265 <p>Click the “New” button above to add one-time passphrases to your account.</p>",
266
267 'createNewOTPButtonLabel': "New",
268 'deleteOTPButtonLabel': "Delete",
269 'printOTPButtonLabel': "Print",
270
271 'disabledOneTimePassword_warning': "disabled",
272
273 'oneTimePasswordSelectionLink_selectLabel':"Select:",
274 'oneTimePasswordSelectionLink_all': "all",
275 'oneTimePasswordSelectionLink_none': "none",
276 'oneTimePasswordSelectionLink_used': "used",
277 'oneTimePasswordSelectionLink_unused': "unused",
278
279//Account panel - OTP - saving new OTP dialog
280 'saveOTP_encryptUserDataTitle': "Saving one-time passphrase",
281 'saveOTP_encryptUserDataText': "Processing new OTP credentials …",
282 'saveOTP_encryptOTPDataTitle': "Saving one-time passphrase",
283 'saveOTP_encryptOTPDataText': "Local encryption of authentication data …",
284 'saveOTP_sendingDataTitle': "Saving one-time passphrase",
285 'saveOTP_sendingDataText': "Sending authentication data to the server …",
286 'saveOTP_updatingInterfaceTitle': "Saving one-time passphrase",
287 'saveOTP_updatingInterfaceText': "Updating interface",
288
289// Account panel - preferences
290 'accountPreferencesLabel': "Preferences",
291 'accountPreferencesTabTitle': "Preferences",
292
293 'accountPreferencesLanguageTitle': "Language",
294 'accountPreferencesLanguageDescription':"<p>Choose your preferred language from the list below.</p>",
295
296 'showDonationReminderPanelTitle': "Donation reminders",
297 'showDonationReminderPanelDescription': "<p>Show donation reminders</p>",
298
299 'saveUserPreferencesFormSubmitLabel': "Save",
300 'cancelUserPreferencesFormSubmitLabel': "Cancel",
301
302// Account panel - preferences - saving dialog
303 'accountPreferencesSavingPanelTitle_Step1': "Saving preferences",
304 'accountPreferencesSavingPanelText_Step1': "Local encryption of your preferences",
305 'accountPreferencesSavingPanelTitle_Step2': "Saving preferences",
306 'accountPreferencesSavingPanelText_Step2': "Sending encrypted preferences to Clipperz",
307
308 //Account panel - login history
309 'accountLoginHistoryLabel': "Login history",
310 'loginHistoryTabTitle': "Login history",
311
312 'loginHistoryReadOnlyMessage': "\
313 <h6>Sorry!</h6>\
314 <p>The login history is not available while using the offline version of Clipperz.</p>",
315
316 'loginHistoryLoadingMessage': "\
317 <h6>Loading data</h6>\
318 <p>Please wait …</p>",
319
320 'loginHistoryLoadedMessage': "\
321 <h6>Your latest 10 logins</h6>\
322 <p></p>",
323
324 'loginHistoryIPLabel': "IP",
325 'loginHistoryTimeLabel': "date",
326 'loginHistoryCurrentSessionText': "current session",
327 'loginHistoryReloadButtonLabel': "Reload login history",
328
329 //Account panel - delete account
330 'deleteAccountTabLabel': "Delete your account",
331 'deleteAccountTabTitle': "Delete your account",
332
333 'deleteAccountFormUsernameLabel': "username",
334 'deleteAccountFormPassphraseLabel': "passphrase",
335 'deleteAccountFormSafetyCheckboxLabel': "I understand that all my data will be deleted and that this action is irreversible.",
336 'deleteAccountFormSubmitLabel': "Delete my account",
337
338//Account panel - delete account - warnings
339 'deleteAccountFormWrongUsernameWarning':"Wrong username",
340 'deleteAccountFormWrongPassphraseWarning':"Wrong passphrase",
341 'deleteAccountFormSafetyCheckWarning': "Please read and check the box below.",
342
343//Account panel - delete account - confirmation
344 'accountPanelDeletingAccountPanelConfirmationTitle':"ATTENTION",
345 'accountPanelDeleteAccountPanelConfirmationText': "Are your sure you want to delete your account?",
346 'accountPanelDeleteAccountPanelConfirmButtonLabel': "Yes",
347 'accountPanelDeleteAccountPanelDenyButtonLabel': "No",
348
349//Account panel - delete account - confirmation
350 'accountPanelDeletingAccountPanelProgressTitle': "Deleting the account data",
351 'accountPanelDeletingAccountPanelProgressText': "The operation could take long, please be patient.",
352
353//Data panel - offline copy
354 'offlineCopyTabLabel': "Offline copy",
355 'offlineCopyTabTitle': "Offline copy",
356
357'offlineCopyTabDescription': "\
358 <!-- FIX CSS DONE! -->\
359 <p>With just one click you can dump all your encrypted data from Clipperz servers to your hard disk and create a read-only offline version of Clipperz to be used when you are not connected to the Internet.</p>\
360 <p>The read-only version is as secure as the read-and-write one and will not expose your data to higher risks since they both share the same code and security architecture.</p>\
361 <ol>\
362 <li><p>Click the link below to start the download.</p></li>\
363 <li><p>The browser will ask you what to do with the “Clipperz_YYYYMMDD.html” file. Save it on your hard disk.</p></li>\
364 <li><p>Double click on the downloaded file to launch the offline version in your browser.</p></li>\
365 <li><p>Enter the usual username and passphrase.</p></li>\
366 </ol>",
367
368 'offlineCopyDownloadLinkLabel': "Download",
369
370 //Data panel - offline copy - not updated
371 'offlineCopyDownloadWarning': "\
372 <!-- FIX CSS DONE! -->\
373 <h4><a href=\"#\" id=\"offlineCopyDownloadWarningLink\">Update your “offline copy”!</a></h4>\
374 <p>You have recently created or modified one or more cards, it would be wise to download a new copy of the offline version.</p>",
375
376 'offlineCopyDownloadOk': "",
377
378 //Data panel - sharing
379 'sharingTabLabel': "Sharing",
380 'sharingTabTitle': "Sharing",
381
382 'sharingTabDescription': "\
383 <p>Quite often a confidential piece of information needs to be shared with one or more persons.</p>\
384 <p>This could be as simple as giving your colleague the access code of your voice mailbox when you are out of the office, or as complicated as enabling the entitled heirs to access your safe deposit box at the local bank when you pass on.</p>\
385 <p>Clipperz can make sharing your secrets a secure and straightforward process.</p>\
386 <p></p>\
387 <p><b>Coming soon …</b></p>",
388
389 // Data panel - import
390 'importTabLabel': "Import",
391 'importTabTitle': "Import",
392
393 'importTabDescription': "<p>You can bulk import data to your Clipperz account from several file formats.</p>",
394
395 //Data panel - export
396 'printingTabLabel': "Export",
397 'printingTabTitle': "Export",
398
399 'printingTabDescription': "\
400 <h5>Printing</h5>\
401 <p>Click on the link below to open a new window displaying all your cards in a printable format.</p>\
402 <p>If you are going to print for backup purposes, please consider the safer option provided by the “offline copy”.</p>",
403
404 'printingLinkLabel': "Printable version",
405
406 'exportTabDescription': "\
407 <h5>Exporting to JSON</h5>\
408 <p>JSON enables a “lossless” export of your cards. All the information will be preserved, including direct login configurations.</p>\
409 <p>This custom format it’s quite convenient if you need to move some of all of your cards to a different Clipperz account. Or if you want to restore a card that has been accidentally deleted.</p>\
410 <p>Click on the link below to start the export process.</p>",
411
412 'exportLinkLabel': "Export to JSON",
413
414 'exportDataInProgressDescription':"<h4>Exporting, please wait while your data are being processed …</h4>",
415
416 'exportDataDescription': "\
417 <h4>Instructions</h4>\
418 <p>Copy the text below to your favorite editor and save it. (e.g. “clipperz_export_20071217.json”)</p>",
419
420 //Contacts panel
421 'contactsTabLabel': "Contacts",
422 'contactsTabTitle': "Contacts",
423
424//Tools panel - password generator
425 'passwordGeneratorTabLabel': "Password generator",
426 'bookmarkletTabLabel': "Bookmarklet",
427 'compactTabLabel': "Compact edition",
428 'httpAuthTabLabel': "HTTP authentication",
429
430 'passwordGeneratorTabTitle': "Password generator",
431 'bookmarkletTabTitle': "Bookmarklet",
432 'compactTabTitle': "Compact edition",
433 'httpAuthTabTitle': "HTTP authentication",
434
435
436 //Tools panel - password generator - description
437 'paswordGeneratorTabDescription':"<p></p>",
438 'passwordGeneratorTabButtonLabel':"Generate password",
439
440 //Tools panel - bookmarklet
441 'bookmarkletTabLabel': "Bookmarklet",
442 'bookmarkletTabTitle': "Bookmarklet",
443
444 'bookmarkletTabDescription': "\
445 <!-- FIX CSS DONE! -->\
446 <p>A bookmarklet is a simple “one-click” tool that can perform very useful tasks. It can be saved and used like a normal web page bookmark.</p>\
447 <p>The Clipperz bookmarklet will help you to quickly create new cards and new “direct logins” within existing cards.</p>\
448 <p><b>Please note that the bookmarklet does not include any information related to your account (e.g. your username or passphrase), the bookmarklet is a general tool containing the same code for every Clipperz user.</b></p>\
449 <h3>How to install the bookmarklet</h3>\
450 <h>Firefox, Camino, Opera, Safari</h5>\
451 <ol>\
452 <li><p>Make sure that the “Bookmarks Bar” is displayed by selecting “View > Toolbars > Bookmarks”, or similar menu items, from the browser menu.</p></li>\
453 <li><p>Drag and drop the “Add to Clipperz” link below to the bookmark bar.</p></li>\
454 </ol>\
455 \
456 <h5>Internet Explorer</h5>\
457 <ol>\
458 <li><p>Make sure that the “Links” toolbar is displayed by selecting “View > Toolbars > Links” from the browser menu.</p></li>\
459 <li><p>Right-click on the “Add to Clipperz” link below.</p></li>\
460 <li><p>Select “Add to favorites” from the contextual menu.</p></li>\
461 <li><p>Click “Yes” for any security message that pops up.</p></li>\
462 <li><p>Open the “Links” folder and click “OK”</p></li>\
463 </ol>",
464
465 'bookmarkletTabBookmarkletTitle':"Add to Clipperz",
466
467 //Tools panel - bookmarklet - instructions
468 'bookmarkletTabInstructions': "\
469 <!-- FIX CSS DONE! -->\
470 <h3>How to create a new card inclusive of a “direct login” link to an online service</h3>\
471 <ol>\
472 <li><p>Open the web page where the login form is hosted. (this is the page where you usually enter your sign-in credentials)</p></li>\
473 <li><p>Launch the bookmarklet by clicking on it: a pop-up window will appear over the web page.</p></li>\
474 <li><p>Copy to the clipboard the content of the large text area within the pop-up. (ctrl-C)</p></li>\
475 <li><p>Enter your Clipperz account and click on the <b>Add new card</b> button.</p></li>\
476 <li><p>Select the “Direct login” template and paste the content of the clipboard to the large text area in the form. (ctrl-V)</p></li>\
477 <li><p>Press the <b>Create</b> button, complete and review the details, then click <b>Save</b>.</p></li>\
478 </ol>\
479 \
480 <h3>How to add a “direct login” link to an existing card</h3>\
481 <ol>\
482 <li><p>Same as above.</p></li>\
483 <li><p>Same as above.</p></li>\
484 <li><p>Same as above.</p></li>\
485 <li><p>Enter your Clipperz account and select the card containing the credentials for the web service you just visited and click the <b>Edit</b> button.</p></li>\
486 <li><p>Paste the content of the clipboard to the large text area in the “Direct logins” section. (ctrl-V)</p></li>\
487 <li><p>Press the <b>Add direct login</b> button, review the details and then click <b>Save</b>.</p></li>\
488 </ol>\
489 \
490 <p></p>\
491 <p>Further information about the bookmarklet are <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">available here</a>.</p>",
492
493 //Tools panel - Compact - instructions
494 'compactTabDescription': "\
495 <!-- FIX CSS DONE! -->\
496 <p>Clipperz Compact is a special version of Clipperz designed to be opened in the Firefox sidebar.</p>\
497 <p>Its purpose is to keep your collection of “direct logins” always at hand. Read more <a href=\"http://www.clipperz.com/support/user_guide/clipperz_compact\", target=\"blank\">here</a></p>\
498 \
499 <h3>How to launch Clipperz Compact in the sidebar</h3>\
500 <ol>\
501 <li><p>Get Firefox! Sidebars are only available in Firefox and you need to switch to Firefox in order to enjoy the convenience of Clipperz Compact.</p></li>\
502 <li>\
503 <p>Add the following URL to Firefox bookmarks, or even better, drag it to the bookmark bar.</p>\
504 <div id=\"compactLinkBox\"><a href=\"https://www.clipperz.com/beta/index.html?compact\" target=\"_search\">Clipperz Compact</a></div>\
505 </li>\
506 <li><p>Change the properties of the bookmark so that “load this bookmark in the sidebar” is checked.</p></li>\
507 </ol>\
508 \
509 <h5>Added bonus: Clipperz Compact works also in Opera’s panel.</h5>",
510
511 //Tools panel - HTTP authentication - instructions
512 'httpAuthTabDescription': "\
513 <!-- FIX CSS DONE! -->\
514 <p>HTTP authentication is a method designed to allow a web browser to provide credentials – in the form of a username and password – including them in a website address (HTTP or HTTPS URL).</p>\
515 <p>Nowadays it is rarely used, but it can still be found on small, private websites. You can tell that a website is protected by HTTP authentication when the browser displays a pop-up window to enter username and password.</p>\
516 <p>Unfortunately the Clipperz bookmarklet does not work on websites that use HTTP authentication. However you can still create a “direct login”.</p>\
517 \
518 <h3>How to create a “direct login” for a website that uses HTTP authentication</h3>\
519 <ol>\
520 <li><p>Store website URL, username and password in a new card.</p></li>\
521 <li><p>Copy the configuration below and paste it to the large text area in the “Direct logins” section of the new card.</p></li>\
522 <li><p>Press the <b>Add direct login</b> button, bind URL, username and password fields and then click <b>Save</b>.</p></li>\
523 </ol>\
524 \
525 <h5><a href=\"http://support.microsoft.com/kb/834489\" target=\"_blank\">Warning: Internet Explorer does not support HTTP authentication.</a></h5>",
526
527// Direct logins block
528 'mainPanelDirectLoginBlockLabel': "Direct logins",
529 'directLinkReferenceShowButtonLabel': "show",
530
531// Direct logins - blank slate
532 'mainPanelDirectLoginBlockDescription': "\
533 <!-- FIX CSS DONE! -->\
534 <p>Add “direct logins” to sign in to your web accounts without typing usernames and passwords!</p>\
535 <p>“Direct logins” greatly enhance your password security since you can:</p>\
536 <ul>\
537 <li><p>conveniently adopt and enter complex passwords;</p></li>\
538 <li><p>never re-use the same and easy-to-guess password.</p></li>\
539 </ul>\
540 <p>Simple and quick configuration with the <b>Clipperz bookmarklet</b>.</p>\
541 <a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">Learn more about “direct logins”</a>",
542
543 // Cards block
544 'mainPanelRecordsBlockLabel': "Cards",
545 'mainPanelAddRecordButtonLabel': "Add new card",
546 'mainPanelRemoveRecordButtonLabel': "Delete card",
547
548// Cards block - filter tabs
549 'mainPanelRecordFilterBlockAllLabel': "all",
550 'mainPanelRecordFilterBlockTagsLabel': "tags",
551 'mainPanelRecordFilterBlockSearchLabel':"search",
552
553// Cards block - blank slate
554 'recordDetailNoRecordAtAllTitle': "Welcome to Clipperz!",
555 'recordDetailNoRecordAtAllDescription': "\
556 <h5>Get started by adding cards to your account.</h5>\
557 <p>Cards are simple and flexible forms where you can store your passwords and any other confidential data.</p>\
558 <p>Cards could contain credentials for accessing a web site, the combination of your bicycle lock, details of your credit card, …</p>\
559 \
560 <h5>Don't forget the Clipperz bookmarklet!</h5>\
561 <p>Before you start, install the “Add to Clipperz” bookmarklet: it will make creating cards easier and more fun.</p>\
562 <p>Go to the “Tools” tab to discover how to install it and how it use it.</p>\
563 <p></p>\
564 <p>Then simply click the <b>\"Add new card\"</b> button and enjoy your Clipperz account.</p>\
565 <p></p>\
566 <a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">Learn more about creating and managing cards</a>",
567
568// Cards block - new card wizard - bookmarklet configuration
569 'newRecordWizardTitleBox': "\
570 <h5>Please select a template</h5>\
571 <p>Cards are simple and flexible forms where you can store passwords or any other confidential data.</p>\
572 <p>Start choosing one of the templates below. You can always customize your cards later by adding or removing fields.</p>",
573
574 'newRecordWizardBookmarkletConfigurationTitle': "Direct login",
575 'newRecordWizardBookmarkletConfigurationDescription':"\
576 <p>Paste below the configuration code generated by the Clipperz bookmarklet.</p>\
577 <p>A new card complete with a direct login to your web account will be created.</p>",
578
579 'newRecordWizardCreateButtonLabel': "Create",
580 'newRecordWizardCancelButtonLabel': "Cancel",
581
582 //Create new card - Donation splash
583 'donateSplashPanelTitle': "Support Clipperz, make a donation today!",
584 'donateSplashPanelDescription': "\
585 <!-- FIX CSS DONE! -->\
586 <p>A few good reasons to make a donation:</p>\
587 <ul>\
588 <li><p>support the development of new features</p></li>\
589 <li><p>keep Clipperz free</p></li>\
590 <li><p>show appreciation for our hard work</p></li>\
591 </ul>\
592 <p>For any further information, please visit our <a href=\"http://www.clipperz.com/donations\" target=\"_blank\">Donations page</a>.</p>\
593 <p><b>Ready to donate?</b></p>",
594
595 'donateCloseButtonLabel': "Not yet",
596 'donateDonateButtonLabel': "Yes",
597
598// Card templates
599'recordTemplates': {
600
601//Web password
602 'WebAccount': {
603 'title': "Web password",
604 'description':"<p>A simple card to store login credentials for your online services.</p>",
605 'fields': [
606 {label:"Web address", type:'URL'},
607 {label:"Username or email", type:'TXT'},
608 {label:"Password", type:'PWD'}
609 ]
610 },
611
612 //Bank account
613 'BankAccount': {
614 'title': "Bank account",
615 'description':"<p>Safely store your bank account number and online banking credentials.</p>",
616 'fields': [
617 {label:"Bank", type:'TXT'},
618 {label:"Account number", type:'TXT'},
619 {label:"Bank website", type:'URL'},
620 {label:"Online banking ID", type:'TXT'},
621 {label:"Online banking password", type:'PWD'}
622 ]
623 },
624
625 // Credit card
626 'CreditCard': {
627 'title': "Credit card",
628 'description':"<p>Card number, expire date, CVV2 and PIN always at hand with Clipperz.</p>",
629 'fields': [
630 {label:"Type (Visa, AmEx, …)", type:'TXT'},
631 {label:"Number", type:'TXT'},
632 {label:"Owner name", type:'TXT'},
633 {label:"Expiry date", type:'TXT'},
634 {label:"CVV2", type:'TXT'},
635 {label:"PIN", type:'PWD'},
636 {label:"Card website", type:'URL'},
637 {label:"Username", type:'TXT'},
638 {label:"Password", type:'PWD'}
639 ]
640 },
641
642 // Address book entry
643 'AddressBookEntry': {
644 'title': "Address book entry",
645 'description':"<p>Clipperz could also work as your new private address book. Use this template to easily add a new entry.</p>",
646 'fields': [
647 {label:"Name", type:'TXT'},
648 {label:"Email", type:'TXT'},
649 {label:"Phone", type:'TXT'},
650 {label:"Mobile", type:'TXT'},
651 {label:"Address", type:'ADDR'}
652 ]
653 },
654
655//Custom card
656 'Custom': {
657 'title': "Custom card",
658 'description':"<p>No matter which kind of confidential data you need to protect, create a custom card to match your needs.</p>",
659 'fields': [
660 {label:"Label 1", type:'TXT'},
661 {label:"Label 2", type:'TXT'},
662 {label:"Label 3", type:'TXT'}
663 ]
664 }
665},
666
667
668'recordFieldTypologies': {
669 'TXT': {
670 description: "simple text field",
671 shortDescription: "text"
672 },
673 'PWD': {
674 description: "simple text field, with default status set to hidden",
675 shortDescription: "password"
676 },
677 'URL': {
678 description: "simple text field in edit mode, that became an active url in view mode",
679 shortDescription: "web address"
680 },
681 'DATE': {
682 description: "a value set with a calendar helper",
683 shortDescription: "date"
684 },
685 'ADDR': {
686 description: "just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
687 shortDescription: "street address"
688 },
689 'CHECK': {
690 description: "check description",
691 shortDescription: "check"
692 },
693 'RADIO': {
694 description: "radio description",
695 shortDescription: "radio"
696 },
697 'SELECT': {
698 description: "select description",
699 shortDescription: "select"
700 }
701},
702
703// Cards block - new card - warnings
704 'newRecordPanelGeneralExceptionTitle': "Error",
705 'newRecordPanelGeneralExceptionMessage': "The configuration text is not valid. Make sure to get your text from the bookmarklet pop-up and retry.",
706 'newRecordPanelWrongBookmarkletVersionExceptionTitle': "Error",
707 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"The configuration text has been generated by an old version of the bookmarklet. Please update your bookmarklet and retry.",
708 'newRecordPanelExceptionPanelCloseButtonLabel': "Cancel",
709
710// Cards block - delete card
711 'mainPanelDeletingRecordPanelConfirmationTitle': "Deleting selected card",
712 'mainPanelDeleteRecordPanelConfirmationText': "Do your really want to delete the selected card?",
713 'mainPanelDeleteRecordPanelConfirmButtonLabel': "Yes",
714 'mainPanelDeleteRecordPanelDenyButtonLabel': "No",
715 'mainPanelDeletingRecordPanelInitialTitle': "Deleting selected card",
716 'mainPanelDeletingRecordPanelInitialText': "---",
717 'mainPanelDeletingRecordPanelCompletedText': "Done",
718
719// Cards block - delete card panel
720 'deleteRecordPanelCollectRecordDataMessageTitle': "Delete card",
721 'deleteRecordPanelCollectRecordDataMessageText': "Updating card list",
722 'deleteRecordPanelEncryptUserDataMessageTitle': "Delete card",
723 'deleteRecordPanelEncryptUserDataMessageText': "Local encryption of card headers",
724 'deleteRecordPanelSendingDataToTheServerMessageTitle': "Delete card",
725 'deleteRecordPanelSendingDataToTheServerMessageText': "Uploading encrypted card headers to Clipperz",
726 'deleteRecordPanelUpdatingTheInterfaceMessageTitle': "Delete card",
727 'deleteRecordPanelUpdatingTheInterfaceMessageText': "Updating the interface",
728
729// Cards block - no record selected
730 'recordDetailNoRecordSelectedTitle': "No card selected",
731 'recordDetailNoRecordSelectedDescription': "<p>Please select a card from the list on the left.</p>",
732
733 // Cards block - loading messages
734 'recordDetailLoadingRecordMessage': "Downloading encrypted card from Clipperz",
735 'recordDetailDecryptingRecordMessage': "Local decryption of card\'s data",
736 'recordDetailLoadingRecordVersionMessage': "Downloading latest card version",
737 'recordDetailDecryptingRecordVersionMessage': "Local decryption of latest version",
738 'recordDetailLoadingErrorMessageTitle': "Error while downloading the card",
739
740// Cards block - card details
741 'recordDetailNotesLabel': "Notes",
742 'recordDetailLabelFieldColumnLabel': "Field label",
743 'recordDetailDataFieldColumnLabel': "Field data",
744 'recordDetailTypeFieldColumnLabel': "Type",
745
746 'recordDetailSavingChangesMessagePanelInitialTitle': "Saving card",
747 'recordDetailSavingChangesMessagePanelInitialText': "---",
748
749 'recordDetailRemoveFieldButtonLabel': "-",
750 'recordDetailAddFieldButtonLabel': "Add new field",
751 'recordDetailPasswordFieldHelpLabel': "click the stars to select the password and then Ctrl-C to copy",
752
753 'recordDetailPasswordFieldScrambleLabel': "scramble",
754 'recordDetailPasswordFieldUnscrambleLabel': "unscramble",
755
756 'recordDetailDirectLoginBlockTitle': "Direct logins",
757 'recordDetailNewDirectLoginDescription': "<p>Direct login configuration</p>",
758
759 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"\
760 <p>Does this card contain credentials to access an online service?</p>\
761 <p>Use the bookmarklet to configure a “direct login” from Clipperz with just one click!</p>",
762
763 'recordDetailDeleteDirectLoginButtonLabel': "-",
764 'recordDetailAddNewDirectLoginButtonLabel': "Add new direct login",
765
766 'recordDetailEditButtonLabel': "Edit",
767 'recordDetailSaveButtonLabel': "Save",
768 'recordDetailCancelButtonLabel': "Cancel",
769
770 'newRecordTitleLabel': "_new card_",
771 'newDirectLoginLabelSuffix': "",
772
773// Cards block - save card panel
774 'recordSaveChangesPanelCollectRecordInfoMessageTitle': "Save card",
775 'recordSaveChangesPanelCollectRecordInfoMessageText': "Updating card headers",
776 'recordSaveChangesPanelEncryptUserDataMessageTitle': "Save card",
777 'recordSaveChangesPanelEncryptUserDataMessageText': "Local encryption of card headers",
778 'recordSaveChangesPanelEncryptRecordDataMessageTitle': "Save card",
779 'recordSaveChangesPanelEncryptRecordDataMessageText': "Local encryption of card's data",
780 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Save card",
781 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Local encryption of card's version data",
782 'recordSaveChangesPanelSendingDataToTheServerMessageTitle': "Save card",
783 'recordSaveChangesPanelSendingDataToTheServerMessageText': "Uploading encrypted card's header to Clipperz",
784 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle': "Save card",
785 'recordSaveChangesPanelUpdatingTheInterfaceMessageText': "Updating the interface",
786
787 //Password Generator strings
788 'passwordGeneratorPanelTitle': "Password generator",
789 'passwordGeneratorPanelOkLabel': "Ok",
790 'passwordGeneratorPanelCancelLabel': "Cancel",
791
792 'passwordGeneratorLowercaseLabel': "abc",
793 'passwordGeneratorUppercaseLabel': "ABC",
794 'passwordGeneratorNumberLabel': "012",
795 'passwordGeneratorSymbolLabel': "@#$",
796
797 'passwordGeneratorLengthLabel': "length:",
798
799
800 //Miscellaneous strings
801
802 'comingSoon': "coming soon …",
803 'panelCollectingEntryopyMessageText': "Collecting entropy",
804 'directLoginConfigurationCheckBoxFieldSelectedValue': "Yes",
805 'directLoginConfigurationCheckBoxFieldNotSelectedValue': "No",
806
807
808
809// NEW - Import panel
810 'importFormats':{
811 'CSV': {
812 'label': "CSV",
813 'description':"<p>A widely recognized file format that stores tabular data. Several password managers can export data to this format.</p>"
814 },
815 'Excel': {
816 'label': "Excel",
817 'description':"<p>The popular spreadsheet from Microsoft. Storing passwords in Excel files is very common but not advisable.</p>"
818 },
819 'KeePass': {
820 'label': "KeePass",
821 'description':"<p>The custom TXT file created by KeePass password manager.</p>"
822 },
823 'PasswordPlus': {
824 'label': "Password Plus",
825 'description':"<p>The custom CSV format produced by Password Plus, a password manager mostly used on mobile devices.</p>"
826 },
827 'Roboform': {
828 'label': "RoboForm",
829 'description':"<p>The special HTML file created by Roboform password manager when displaying Passcard and Safenotes for printing.</p>"
830 },
831 'ClipperzExport': {
832 'label': "JSON",
833 'description':"<p>The file created by Clipperz itself in JSON format. It preserves all information contained in your cards, even direct login configurations.</p>"
834 }
835},
836
837 //JSON
838 'Clipperz_ImportWizard_Title': "JSON import",
839 'importOptions_clipperz_description': "<p>Open the JSON file exported from Clipperz in a text editor. Then copy and paste its content to the text area below.</p>",
840
841 //CSV
842 'CSV_ImportWizard_Title': "CSV import",
843 'importOptions_csv_description_': "\
844 <p>Open the CSV file in a text editor. Then copy and paste its content to the text area below.</p>\
845 <p>Please select the special characters used within your file.</p>",
846
847 //Excel
848 'Excel_ImportWizard_Title': "Excel import",
849 'importOptions_excel_description_': "<p>Open the Excel file and select the cells you want to import. Then copy and paste them to the text area below.</p>",
850
851 //KeePass
852 'KeePass_ImportWizard_Title': "KeePass import",
853 'importOptions_keePass_description_': "<p>Open the TXT file created by Keepass in a text editor. Then copy and paste its content to the text area below.</p>",
854
855 //PasswordPlus
856 'PasswordPlus_ImportWizard_Title': "Password Plus import",
857 'importOptions_passwordPlus_description':"<p>Open the CSV file created by PasswordPlus in a text editor. Then copy and paste its content to the text area below.</p>",
858
859 //RoboForm
860 'RoboForm_ImportWizard_Title': "RoboForm import",
861 'importOptions_roboForm_description': "<p>Open the HTML file created by RoboForm in a text editor. Then copy and paste its content to the text area below.</p>",
862
863
864 'importData_parsingDataTitle': "Import",
865 'importData_parsingDataText': "Parsing data …",
866
867 'importData_previewingDataTitle': "Import",
868 'importData_previewingDataText': "Processing data …",
869
870 'importData_processingDataTitle': "Import",
871 'importData_processingDataText': "Creating new cards …",
872
873'ImportWizard': {
874 'EDIT': "edit",
875 'PREVIEW': "preview",
876 'IMPORT': "import",
877
878 'KEEPASS_SETTINGS': "settings",
879
880 'CSV_EDIT': "paste",
881 'CSV_COLUMNS': "columns",
882 'CSV_HEADER': "labels",
883 'CSV_TITLE': "titles",
884 'CSV_NOTES': "notes",
885 'CSV_FIELDS': "types",
886
887 'EXCEL_EDIT': "edit"
888},
889
890 'CSV_ImportWizard_Columns': "<p>Select the columns you want to import.</p>",
891 'CSV_ImportWizard_Header': "<p>If the first row of the CSV file contains field labels, tick off the checkbox below.</p>",
892 'CSV_ImportWizard_Header_Settings_firstRowHeaderLabel':"Use the first row as labels?",
893 'CSV_ImportWizard_Title': "<p>Select the column that contains titles of the cards you are importing. (mandatory)</p>",
894 'CSV_ImportWizard_Notes': "<p>Select the column that represents a \"notes\" field. (optional)</p>",
895 'CSV_ImportWizard_Notes_Settings_noSelectionLabel': "\"notes\" field not present",
896 'CSV_ImportWizard_Fields': "<p>Select the correct type for each column from the drop down lists.</p>",
897 'CSV_ImportWizard_Fields_MissingLabelWarning': "Missing label",
898
899 'importData_importConfirmation_title': "Import",
900 'importData_importConfirmation_text': "Do you want to import __numberOfRecords__ cards?",
901
902
903 //Vulnerability warning
904 'VulnerabilityWarning_Panel_title': "Vulnerability warning",
905 'VulnerabilityWarning_Panel_message': "The action as been aborted due to a catched vulnerability",
906 'VulnerabilityWarning_Panel_buttonLabel':"Close",
907
908
909
910 //All the loginInfo panel infos
911
912 'WELCOME_BACK': "Welcome back!",
913
914 'currentConnectionText': "You are connected from ip&nbsp;__ip__, apparently from __country__, using __browser__ on __operatingSystem__.",
915 'latestConnectionText': "Your latest connection was __elapsedTimeDescription__ (__time__) from ip&nbsp;__ip__, apparently from __country__, using __browser__ on __operatingSystem__.",
916
917 'fullLoginHistoryLinkLabel': "show login history",
918
919'elapsedTimeDescriptions': {
920 'MORE_THAN_A_MONTH_AGO': "more than a month ago",
921 'MORE_THAN_A_WEEK_AGO': "more than a week ago",
922 'MORE_THAN_*_WEEKS_AGO': "more than __elapsed__ weeks ago",
923 'YESTERDAY': "yesterday",
924 '*_DAYS_AGO': "__elapsed__ days ago",
925 'ABOUT_AN_HOUR_AGO': "about an hour ago",
926 '*_HOURS_AGO': "__elapsed__ hours ago",
927 'JUST_A_FEW_MINUTES_AGO': "just a few minutes ago",
928 'ABOUT_*_MINUTES_AGO': "about __elapsed__ minutes ago"
929},
930
931 'unknown_ip': "unknown",
932
933'countries': {
934 '--': "unknown",
935 'AD': "Andorra",
936 'AE': "United Arab Emirates",
937 'AF': "Afghanistan",
938 'AG': "Antigua and Barbuda",
939 'AI': "Anguilla",
940 'AL': "Albania",
941 'AM': "Armenia",
942 'AN': "Netherlands Antilles",
943 'AO': "Angola",
944 'AP': "Non-Spec Asia Pas Location",
945 'AR': "Argentina",
946 'AS': "American Samoa",
947 'AT': "Austria",
948 'AU': "Australia",
949 'AW': "Aruba",
950 'AX': "Aland Islands",
951 'AZ': "Azerbaijan",
952 'BA': "Bosnia and Herzegowina",
953 'BB': "Barbados",
954 'BD': "Bangladesh",
955 'BE': "Belgium",
956 'BF': "Burkina Faso",
957 'BG': "Bulgaria",
958 'BH': "Bahrain",
959 'BI': "Burundi",
960 'BJ': "Benin",
961 'BM': "Bermuda",
962 'BN': "Brunei Darussalam",
963 'BO': "Bolivia",
964 'BR': "Brazil",
965 'BS': "Bahamas",
966 'BT': "Bhutan",
967 'BW': "Botswana",
968 'BY': "Belarus",
969 'BZ': "Belize",
970 'CA': "Canada",
971 'CD': "Congo the Democratic Republic of the",
972 'CF': "Central African Republic",
973 'CH': "Switzerland",
974 'CI': "Cote D'ivoire",
975 'CK': "Cook Islands",
976 'CL': "Chile",
977 'CM': "Cameroon",
978 'CN': "China",
979 'CO': "Colombia",
980 'CR': "Costa Rica",
981 'CS': "Serbia and Montenegro",
982 'CU': "Cuba",
983 'CY': "Cyprus",
984 'CZ': "Czech Republic",
985 'DE': "Germany",
986 'DJ': "Djibouti",
987 'DK': "Denmark",
988 'DO': "Dominican Republic",
989 'DZ': "Algeria",
990 'EC': "Ecuador",
991 'EE': "Estonia",
992 'EG': "Egypt",
993 'ER': "Eritrea",
994 'ES': "Spain",
995 'ET': "Ethiopia",
996 'EU': "European Union",
997 'FI': "Finland",
998 'FJ': "Fiji",
999 'FM': "Micronesia Federated States of",
1000 'FO': "Faroe Islands",
1001 'FR': "France",
1002 'GA': "Gabon",
1003 'GB': "United Kingdom",
1004 'GD': "Grenada",
1005 'GE': "Georgia",
1006 'GF': "French Guiana",
1007 'GG': "Guernsey",
1008 'GH': "Ghana",
1009 'GI': "Gibraltar",
1010 'GL': "Greenland",
1011 'GM': "Gambia",
1012 'GP': "Guadeloupe",
1013 'GR': "Greece",
1014 'GT': "Guatemala",
1015 'GU': "Guam",
1016 'GW': "Guinea-Bissau",
1017 'GY': "Guyana",
1018 'HK': "Hong Kong",
1019 'HN': "Honduras",
1020 'HR': "Croatia (Local Name: Hrvatska)",
1021 'HT': "Haiti",
1022 'HU': "Hungary",
1023 'ID': "Indonesia",
1024 'IE': "Ireland",
1025 'IL': "Israel",
1026 'IM': "Isle of Man",
1027 'IN': "India",
1028 'IO': "British Indian Ocean Territory",
1029 'IQ': "Iraq",
1030 'IR': "Iran (Islamic Republic of)",
1031 'IS': "Iceland",
1032 'IT': "Italy",
1033 'JE': "Jersey",
1034 'JM': "Jamaica",
1035 'JO': "Jordan",
1036 'JP': "Japan",
1037 'KE': "Kenya",
1038 'KG': "Kyrgyzstan",
1039 'KH': "Cambodia",
1040 'KI': "Kiribati",
1041 'KN': "Saint Kitts and Nevis",
1042 'KR': "Korea Republic of",
1043 'KW': "Kuwait",
1044 'KY': "Cayman Islands",
1045 'KZ': "Kazakhstan",
1046 'LA': "Lao People's Democratic Republic",
1047 'LB': "Lebanon",
1048 'LC': "Saint Lucia",
1049 'LI': "Liechtenstein",
1050 'LK': "Sri Lanka",
1051 'LR': "Liberia",
1052 'LS': "Lesotho",
1053 'LT': "Lithuania",
1054 'LU': "Luxembourg",
1055 'LV': "Latvia",
1056 'LY': "Libyan Arab Jamahiriya",
1057 'MA': "Morocco",
1058 'MC': "Monaco",
1059 'MD': "Moldova Republic of",
1060 'MG': "Madagascar",
1061 'MH': "Marshall Islands",
1062 'MK': "Macedonia the Former Yugoslav Republic of",
1063 'ML': "Mali",
1064 'MM': "Myanmar",
1065 'MN': "Mongolia",
1066 'MO': "Macau",
1067 'MP': "Northern Mariana Islands",
1068 'MR': "Mauritania",
1069 'MS': "Montserrat",
1070 'MT': "Malta",
1071 'MU': "Mauritius",
1072 'MV': "Maldives",
1073 'MW': "Malawi",
1074 'MX': "Mexico",
1075 'MY': "Malaysia",
1076 'MZ': "Mozambique",
1077 'NA': "Namibia",
1078 'NC': "New Caledonia",
1079 'NF': "Norfolk Island",
1080 'NG': "Nigeria",
1081 'NI': "Nicaragua",
1082 'NL': "Netherlands",
1083 'NO': "Norway",
1084 'NP': "Nepal",
1085 'NR': "Nauru",
1086 'NU': "Niue",
1087 'NZ': "New Zealand",
1088 'OM': "Oman",
1089 'PA': "Panama",
1090 'PE': "Peru",
1091 'PF': "French Polynesia",
1092 'PG': "Papua New Guinea",
1093 'PH': "Philippines",
1094 'PK': "Pakistan",
1095 'PL': "Poland",
1096 'PR': "Puerto Rico",
1097 'PS': "Palestinian Territory Occupied",
1098 'PT': "Portugal",
1099 'PW': "Palau",
1100 'PY': "Paraguay",
1101 'QA': "Qatar",
1102 'RO': "Romania",
1103 'RS': "Serbia",
1104 'RU': "Russian Federation",
1105 'RW': "Rwanda",
1106 'SA': "Saudi Arabia",
1107 'SB': "Solomon Islands",
1108 'SC': "Seychelles",
1109 'SD': "Sudan",
1110 'SE': "Sweden",
1111 'SG': "Singapore",
1112 'SI': "Slovenia",
1113 'SK': "Slovakia (Slovak Republic)",
1114 'SL': "Sierra Leone",
1115 'SM': "San Marino",
1116 'SN': "Senegal",
1117 'SR': "Suriname",
1118 'SV': "El Salvador",
1119 'SY': "Syrian Arab Republic",
1120 'SZ': "Swaziland",
1121 'TC': "Turks and Caicos Islands",
1122 'TG': "Togo",
1123 'TH': "Thailand",
1124 'TJ': "Tajikistan",
1125 'TM': "Turkmenistan",
1126 'TN': "Tunisia",
1127 'TO': "Tonga",
1128 'TR': "Turkey",
1129 'TT': "Trinidad and Tobago",
1130 'TV': "Tuvalu",
1131 'TW': "Taiwan Province of China",
1132 'TZ': "Tanzania United Republic of",
1133 'UA': "Ukraine",
1134 'UG': "Uganda",
1135 'US': "United States",
1136 'UY': "Uruguay",
1137 'UZ': "Uzbekistan",
1138 'VA': "Holy See (Vatican City State)",
1139 'VE': "Venezuela",
1140 'VG': "Virgin Islands (British)",
1141 'VI': "Virgin Islands (U.S.)",
1142 'VN': "Viet Nam",
1143 'VU': "Vanuatu",
1144 'WF': "Wallis and Futuna Islands",
1145 'WS': "Samoa",
1146 'YE': "Yemen",
1147 'ZA': "South Africa",
1148 'ZM': "Zambia",
1149 'ZW': "Zimbabwe",
1150 'ZZ': "Reserved"
1151},
1152
1153'browsers': {
1154 'UNKNOWN': "Unknown",
1155 'MSIE': "Internet Explorer",
1156 'FIREFOX': "Firefox",
1157 'OPERA': "Opera",
1158 'SAFARI': "Safari",
1159 'OMNIWEB': "OmniWeb",
1160 'CAMINO': "Camino",
1161 'CHROME': "Chrome"
1162},
1163
1164'operatingSystems': {
1165 'UNKNOWN': "Unknown",
1166 'WINDOWS': "Windows",
1167 'MAC': "Mac",
1168 'LINUX': "Linux",
1169 'IPHONE': "iPhone",
1170 'MOBILE': "Mobile",
1171 'OPENBSD': "OpenBSD",
1172 'FREEBSD': "FreeBSD",
1173 'NETBSD': "NetBSD"
1174},
1175
1176
1177 //Calendar texts
1178'calendarStrings': {
1179 'months': {
1180 '0':"January",
1181 '1':"February",
1182 '2':"March",
1183 '3':"April",
1184 '4':"May",
1185 '5':"June",
1186 '6':"July",
1187 '7':"August",
1188 '8':"September",
1189 '9':"October",
1190 '10':"November",
1191 '11':"December"
1192 },
1193 'shortMonths':{
1194 '0':"Jan",
1195 '1':"Feb",
1196 '2':"Mar",
1197 '3':"Apr",
1198 '4':"May",
1199 '5':"Jun",
1200 '6':"Jul",
1201 '7':"Aug",
1202 '8':"Sep",
1203 '9':"Oct",
1204 '10':"Nov",
1205 '11':"Dec"
1206 },
1207
1208 'days':{
1209 '0':"Sunday",
1210 '1':"Monday",
1211 '2':"Tuesday",
1212 '3':"Wednesday",
1213 '4':"Thursday",
1214 '5':"Friday",
1215 '6':"Saturday"
1216 },
1217
1218 'shortDays':{
1219 '0':"Sun",
1220 '1':"Mon",
1221 '2':"Tue",
1222 '3':"Wed",
1223 '4':"Thu",
1224 '5':"Fri",
1225 '6':"Sat"
1226 },
1227
1228 'veryShortDays':{
1229 '0':"Su",
1230 '1':"Mo",
1231 '2':"Tu",
1232 '3':"We",
1233 '4':"Th",
1234 '5':"Fr",
1235 '6':"Sa"
1236 },
1237
1238 'amDesignation':"am",
1239 'pmDesignation':"pm"
1240
1241},
1242
1243// Date format
1244 'fullDate_format':"l, F d, Y H:i:s",
1245*/
1246//################################################################################
1247/*
1248'pageHeader': {
1249 'donation':"donAte",
1250 'forum':"foRum",
1251 'credits':"creDits",
1252 'feedback':"feeDback",
1253 'help': "hElp"
1254},
1255
1256
1257'bookmarkletCopy': {
1258 'noExceptionMessage':"The direct login configuration has been collected.",
1259 'exceptionMessage': "Sorry! There was an error while processing the page.",
1260 'copy': "copy",
1261 'successfulMessage':"DONE!",
1262 'failMessage': "Failed! :("
1263},
1264*/
1265//################################################################################
1266
1267'Wizards': {
1268 'DirectLoginWizard': {
1269 'LABEL': {
1270 'name': "label",
1271 'description': "Enter a name for your new direct login."
1272 },
1273 'TYPE': {
1274 'name': "type",
1275 'description': "short description of the different types of direct login available"
1276 },
1277 'CONFIGURATION': {
1278 'name': "config", //"bookmarklet config",
1279 'description': "Paste the code collected by the bookmarklet. (To install the bookmarklet drag the link below to the bookmark bar of your browser.)"
1280 },
1281 'BINDINGS': {
1282 'name': "bindings",
1283 'description': "Select the right value for each field from the drop down menus."
1284 },
1285 'FAVICON': {
1286 'name': "favicon",
1287 'description': "If you are not satisfied with the small icon for this direct login, enter the URL of a new image file (.ico, .png, .jpg)."
1288 },
1289 'DONE': {
1290 'name': "done",
1291 'description': "Congratulations! You have created a new direct login using credentials contained in your '__cardName__' card.\nEnjoy 1-clik access to '__directLoginName__'!"
1292 }
1293 },
1294 'NewUserWizard': {
1295 'CREDENTIALS': {
1296 'name': "credentials",
1297 'description': "[choose you credentials]"
1298 },
1299 'CHECK_CREDENTIALS': {
1300 'name': "check credentials",
1301 'description': "[check credentials]"
1302 },
1303 'TERMS_OF_SERVICE': {
1304 'name': "terms of service",
1305 'description': "[terms of service]"
1306 },
1307 'CREATE_USER': {
1308 'name': "login",
1309 'description': "[create user]"
1310 }//,
1311/*
1312 'LOGIN': {
1313 'name': "login",
1314 'description': "[enjoy Clipperz]"
1315 },
1316*/
1317 }
1318},
1319
1320
1321'exceptionsMessages': {
1322 'Clipperz': {
1323 'Crypto': {
1324 'Base': {
1325 'exception': {
1326 'CorruptedMessage': "Corrupted message"
1327 }
1328 }
1329 }
1330 }
1331},
1332
1333
1334__syntaxFix__: "syntax fix"
1335
1336}
diff --git a/frontend/delta/js/Clipperz/PM/Toll.js b/frontend/delta/js/Clipperz/PM/Toll.js
new file mode 100644
index 0000000..e9c3092
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/Toll.js
@@ -0,0 +1,189 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
26
27//=============================================================================
28
29Clipperz.PM.Toll = function(args) {
30 args = args || {};
31
32 this._requestType = args.requestType;
33 this._targetValue = args.targetValue;
34 this._cost = args.cost;
35 this._toll = null;
36
37 return this;
38}
39
40Clipperz.PM.Toll.prototype = MochiKit.Base.update(null, {
41
42 'toString': function() {
43 return "Clipperz.PM.Toll (" + this.requestType() + ": " + this.cost() + " - " + ((this.toll() == null)? 'UNPAID' : 'PAID') + ")";
44 },
45
46 //-------------------------------------------------------------------------
47
48 'requestType': function() {
49 return this._requestType;
50 },
51
52 //-------------------------------------------------------------------------
53
54 'targetValue': function() {
55 return this._targetValue;
56 },
57
58 //-------------------------------------------------------------------------
59
60 'cost': function() {
61 return this._cost;
62 },
63
64 //-------------------------------------------------------------------------
65
66 'toll': function() {
67 return this._toll;
68 },
69
70 //-------------------------------------------------------------------------
71/*
72 '__pay': function() {
73 varresult;
74 vartargetData;
75 vartargetMatchSize;
76 var prefixMatchingBits;
77 varpayment;
78 var i;
79
80 if (this.toll() == null) {
81 i = 0;
82 targetData = new Clipperz.ByteArray("0x" + this.targetValue());
83 targetMatchSize = this.cost();
84
85 payment = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32);
86
87 do {
88 varpaymentData;
89
90 //payment = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32);
91 payment.increment();
92 paymentData = Clipperz.Crypto.SHA.sha256(payment);
93 // prefixMatchingBits = this.prefixMatchingBits(targetData, paymentData);
94 prefixMatchingBits = Clipperz.ByteArray.prefixMatchingBits(targetData, paymentData);
95 i++;
96 } while (prefixMatchingBits < targetMatchSize);
97
98 this._toll = payment.toHexString().substring(2)
99 }
100
101 return this;
102 },
103 */
104 //-------------------------------------------------------------------------
105
106 'innerDeferredPay': function (aTargetValue, aCost, aPayment) {
107 var deferredResult;
108 var result;
109 var payment;
110 var i;
111
112 result = null;
113 payment = aPayment;
114 i = 0;
115
116 while ((result == null) && (i < Clipperz.PM.Toll.numberOfCloseLoopIterations)) {
117 if (Clipperz.ByteArray.prefixMatchingBits(aTargetValue, Clipperz.Crypto.SHA.sha256(payment)) > aCost) {
118 result = payment;
119 } else {
120 payment.increment();
121 }
122
123 i ++;
124 }
125
126 if (result == null) {
127 deferredResult = MochiKit.Async.callLater(Clipperz.PM.Toll.pauseBetweenEachCloseLoop, MochiKit.Base.method(this, 'innerDeferredPay', aTargetValue, aCost, aPayment));
128 } else {
129 deferredResult = MochiKit.Async.succeed(result);
130 }
131
132 return deferredResult;
133 },
134
135 'deferredPay': function () {
136 vardeferredResult;
137 vartoll;
138
139 toll = this;
140 deferredResult = new Clipperz.Async.Deferred("Toll.deferredPay");
141//deferredResult.addLog("--->>> deferredPay - " + this.cost());
142 deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'getRandomBytes', 32);
143 deferredResult.addMethod(toll, 'innerDeferredPay', new Clipperz.ByteArray("0x" + this.targetValue()), this.cost());
144 deferredResult.addCallback(MochiKit.Base.bind(function(aPayment) {
145 var result;
146
147 result = {
148 targetValue: this.targetValue(),
149 toll: aPayment.toHexString().substr(2)
150 };
151
152 return result;
153 }, this));
154//deferredResult.addLog("<<<--- deferredPay - " + this.cost());
155 deferredResult.callback();
156
157 return deferredResult;
158 },
159
160 //=========================================================================
161 __syntaxFix__: "syntax fix"
162
163});
164
165
166Clipperz.PM.Toll.validate = function(aTargetValue, aToll, aCost) {
167 var result;
168 vartollValue;
169 var targetValue;
170 var hashedTollValue;
171 var payedToll;
172
173 tollValue = new Clipperz.ByteArray("0x" + aToll);
174 targetValue = new Clipperz.ByteArray("0x" + aTargetValue);
175 hashedTollValue = Clipperz.Crypto.SHA.sha256(tollValue);
176
177 payedToll = Clipperz.ByteArray.prefixMatchingBits(targetValue, hashedTollValue);
178
179 if (payedToll < aCost) {
180 result = false;
181 } else {
182 result = true;
183 }
184
185 return result;
186};
187
188Clipperz.PM.Toll.numberOfCloseLoopIterations = 50;
189Clipperz.PM.Toll.pauseBetweenEachCloseLoop = 0.5; \ No newline at end of file
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js b/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
new file mode 100644
index 0000000..df514a2
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
@@ -0,0 +1,142 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.PM.UI.Components.CardDetail = React.createClass({
25
26 getDefaultProps: function () {
27 return {
28 // searchDelay: 0.3
29 }
30 },
31
32 propTypes: {
33 card: React.PropTypes.object.isRequired
34 },
35
36 getInitialState: function () {
37 return {
38 // showSearch: false,
39 // searchTimer: null,
40 starred: false
41 };
42 },
43
44 handleDirectLoginClick: function (aDirectLoginReference, anEvent) {
45 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference});
46 },
47
48 //=========================================================================
49
50 normalizeFieldValue: function (aValue) {
51 varresult = [];
52 varrows = aValue.split('\n');
53
54 for (var i = 0; i < rows.length; i++) {
55 if (i > 0) {
56 result.push(React.DOM.br());
57 }
58 result.push(rows[i].replace(/[\s]/g, '\u00A0'));
59 }
60
61 return result;
62 },
63
64 renderField: function (aField) {
65//console.log("FIELD", aField);
66 varactionLabel;
67
68 if (aField['actionType'] == 'URL') {
69 actionLabel = "go";
70 } else if (aField['actionType'] == 'PASSWORD') {
71 actionLabel = "locked";
72 } else if (aField['actionType'] == 'EMAIL') {
73 actionLabel = "email";
74 } else {
75 actionLabel = "";
76 }
77
78 returnReact.DOM.div({className:'listItem ' + aField['actionType']}, [
79 React.DOM.div({className:'fieldWrapper'}, [
80 React.DOM.div({className:'fieldInnerWrapper'}, [
81 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])),
82 React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + aField['actionType']}, this.normalizeFieldValue(aField['value'])))
83 ])
84 ]),
85 React.DOM.div({className:'actionWrapper'}, [
86 React.DOM.div({className:aField['actionType']}, actionLabel)
87 ])
88 ]);
89 },
90
91 renderDirectLogin: function (aDirectLogin) {
92//console.log("DIRECT LOGIN", aDirectLogin);
93 returnReact.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleDirectLoginClick', aDirectLogin['reference'])}, [
94 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aDirectLogin['label'])),
95 React.DOM.div({className:'faviconWrapper'}, React.DOM.img({className:'favicon', src:aDirectLogin['favicon']})),
96 React.DOM.div({className:'directLoginLinkWrapper'}, React.DOM.span({className:'directLoginLink'}, "go"))
97 ]);
98 },
99
100 handleBackClick: function (anEvent) {
101 window.history.back();
102 },
103
104 handleStarClick: function (anEvent) {
105 this.setState({starred: !this.state['starred']});
106 },
107
108 //=========================================================================
109
110 render: function () {
111 var card = this.props.card;
112 var starredStatus = (this.state['starred'] ? "starred" : "unstarred");
113
114 if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) {
115 card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] })
116 }
117
118 returnReact.DOM.div({className:'cardDetail'}, [
119 React.DOM.div({className:'header'}, [
120 React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)),
121 // React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title + ' ' + card.title + ' ' + card.title + ' ' + card.title)),
122 React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
123 React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus))
124 ]),
125 React.DOM.div({className:'content'}, [
126 card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null,
127 card.directLogins ? React.DOM.div({className:'directLogins'}, MochiKit.Base.map(this.renderDirectLogin,card.directLogins)): null
128 ]),
129 React.DOM.div({className:'footer'}, [
130 /*
131 // React.DOM.a({className:'cancel'}, "cancel"),
132 // React.DOM.a({className:'save'}, "save")
133
134 React.DOM.a({className:'cancel button'}, "failed"),
135 React.DOM.a({className:'save button'}, "done")
136*/
137 ])
138 ]);
139 }
140
141 //=========================================================================
142});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js b/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js
new file mode 100644
index 0000000..66d20f1
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js
@@ -0,0 +1,161 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.PM.UI.Components.CardList = React.createClass({
25
26 getDefaultProps: function () {
27 return {
28 selectedCard: null,
29 searchDelay: 0.3
30 }
31 },
32
33 propTypes: {
34 searchDelay: React.PropTypes.number
35 },
36
37 getInitialState: function () {
38 return {
39 showSearch: false,
40 searchTimer: null,
41 searchText: '',
42 // passphrase: '',
43 // pin: ''
44 };
45 },
46
47 //=========================================================================
48
49 toggleSearch: function (anEvent) {
50 varshowSearchBox;
51
52 showSearchBox = !this.state.showSearch;
53
54 this.setState({showSearch: showSearchBox});
55
56 if (showSearchBox) {
57 MochiKit.Async.callLater(0.1, MochiKit.Base.method(this, 'focusOnSearchField'));
58 }
59 },
60
61 updateSearchText: function (anEvent) {
62 varsearchText;
63
64 searchText = anEvent.target.value;
65//console.log(">>> updateSearchText", searchText);
66
67 if ((this.state['searchTimer'] != null) && (searchText != this.state['searchText'])) {
68 this.state['searchTimer'].cancel();
69 }
70
71 if (searchText != this.state['searchText']) {
72 this.state['searchText'] = searchText;
73 this.state['searchTimer'] = MochiKit.Async.callLater(this.props['searchDelay'], MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'searchCards', searchText);
74 }
75 },
76
77 focusOnSearchField: function () {
78console.log("focusOnSearchField", this.refs['searchField']);
79 this.refs['searchField'].getDOMNode.focus();
80 },
81
82 searchBox: function () {
83 var result;
84
85 if (this.state.showSearch) {
86 result =React.DOM.div({className:'searchBox'}, [
87 React.DOM.div(null, [
88 React.DOM.input({type:'search', placeholder:"search", ref:'searchField', onChange:this.updateSearchText})
89 ])
90 ]);
91 } else {
92 result = null;
93 }
94
95 return result;
96 },
97
98 //=========================================================================
99
100 cardItem: function (aRecordReference) {
101 varreference = aRecordReference['_reference'];
102 varselectedCard = (reference == this.props.selectedCard);
103
104 returnReact.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleClickOnCardDetail', reference)}, [
105 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label)),
106 // React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label)),
107 React.DOM.div({className:'faviconWrapper'}, aRecordReference.favicon ? React.DOM.img({className:'favicon', src:aRecordReference.favicon}) : React.DOM.div({className:'favicon'}, '\u00A0')),
108 React.DOM.div({className:'detailLinkWrapper'}, React.DOM.span({className:'detailLink ' + (selectedCard ? 'icon-spin' : '')}, (selectedCard ? "loading" : "detail")))
109 ]);
110 },
111
112 handleClickOnCardDetail: function (aRecordReference, anEvent) {
113 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRecord', aRecordReference);
114 },
115
116 cardListItems: function () {
117 varlist;
118 varresult;
119
120 list = this.props['cardList'];
121
122 if (typeof(list) != 'undefined') {
123 result = MochiKit.Base.map(MochiKit.Base.method(this, 'cardItem'), list);
124 } else {
125 result = null;
126 }
127
128 return result;
129 },
130
131 //=========================================================================
132
133 handleChange: function (anEvent) {
134 // varrefs = this.refs;
135 // var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
136 // var newState = {};
137//
138 // newState[refName] = event.target.value;
139 // this.setState(newState);
140 },
141
142 //=========================================================================
143
144 render: function() {
145 returnReact.DOM.div(null, [
146 React.DOM.div({className:'header'}, [
147 React.DOM.a({className:'account'}, 'clipperz'),
148 React.DOM.div({className:'features'}, [
149 React.DOM.a({className:'addCard'}, 'add'),
150 React.DOM.a({className:'search ' + (this.state.showSearch ? 'selected' : ''), onClick:this.toggleSearch}, 'search'),
151 React.DOM.a({className:'settings'}, 'settings')
152 ]),
153 // this.searchBox()
154 ]),
155 this.searchBox(),
156 React.DOM.div({className:'content cardList'}, this.cardListItems()),
157 ]);
158 }
159
160 //=========================================================================
161});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js b/frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js
new file mode 100644
index 0000000..a1979ec
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js
@@ -0,0 +1,46 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.PM.UI.Components.ErrorPage = React.createClass({
25
26 getDefaultProps: function () {
27 return {
28 template: Clipperz.PM.UI.Components.PageTemplate
29 }
30 },
31
32 'propTypes': {
33 // type: React.PropTypes.oneOf(['PERMANENT', 'TEMPORARY']),
34 message:React.PropTypes.string.isRequired,
35 template:React.PropTypes.func
36 },
37
38
39 _render: function () {
40 returnReact.DOM.div({className:'error-message'}, this.props.message);
41 },
42
43 render: function () {
44 returnnew this.props.template({'innerComponent': this._render()});
45 }
46});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js b/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js
new file mode 100644
index 0000000..2b5b4a4
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js
@@ -0,0 +1,150 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.PM.UI.Components.LoginForm = React.createClass({
25
26 getDefaultProps: function () {
27 return {
28 mode: 'CREDENTIALS',
29 isNewUserRegistrationAvailable: false,
30 disabled: false,
31 template: Clipperz.PM.UI.Components.PageTemplate
32 }
33 },
34
35 propTypes: {
36 mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']),
37 isNewUserRegistrationAvailable:React.PropTypes.bool,
38 disabled: React.PropTypes.bool,
39 template: React.PropTypes.func
40 },
41
42 getInitialState: function () {
43 return {
44 username: '',
45 passphrase: '',
46 pin: ''
47 };
48 },
49
50 //=========================================================================
51
52 handleChange: function (anEvent) {
53 varrefs = this.refs;
54 var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
55 var newState = {};
56
57 newState[refName] = event.target.value;
58 this.setState(newState);
59 },
60
61 //=========================================================================
62
63 handleCredentialSubmit: function (event) {
64 event.preventDefault();
65
66 this.refs['passphrase'].getDOMNode().blur();
67
68 var credentials = {
69 'username': this.refs['username'].getDOMNode().value,
70 'passphrase': this.refs['passphrase'].getDOMNode().value
71 }
72 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials);
73 },
74
75 handleRegistrationLinkClick: function (event) {
76 event.preventDefault();
77 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRegistrationForm');
78 },
79
80 //-------------------------------------------------------------------------
81
82 shouldEnableLoginButton: function () {
83 var result;
84
85 return(
86 ((this.state['username'] != '') && (this.state['passphrase'] != ''))
87 ||
88 (this.state['pin'] != '')
89 ) && !this.props['disabled'];
90 },
91
92
93 loginForm: function () {
94 registrationLink =React.DOM.div({'className':'registrationLink'}, [
95 React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Need an account")
96 ]);
97 returnReact.DOM.div({'className':'loginForm credentials'},[
98 React.DOM.form({onChange: this.handleChange, onSubmit:this.handleCredentialSubmit}, [
99 React.DOM.div(null,[
100 React.DOM.label({'for':'name'}, "username"),
101 React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}),
102 React.DOM.label({'for':'passphrase'}, "passphrase"),
103 React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'})
104 ]),
105 React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login")
106 ]),
107 this.props.isNewUserRegistrationAvailable ? registrationLink : null
108 ]);
109 },
110
111 handlePINSubmit: function (event) {
112 event.preventDefault();
113
114 this.refs['pin'].getDOMNode().blur();
115
116 var credentials = {
117 pin: this.refs['pin'].getDOMNode().value
118 }
119
120 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials);
121 },
122
123 pinForm: function () {
124 returnReact.DOM.div({'className':'loginForm pin'},[
125 React.DOM.form({onChange: this.handleChange, onSubmit:this.handlePINSubmit}, [
126 React.DOM.div(null,[
127 React.DOM.label({'for':'pin'}, "pin"),
128 React.DOM.input({'type':'text', 'name':'pin', 'ref':'pin', placeholder:"PIN", 'key':'pin', 'autocapitalize':'none'})
129 ]),
130 React.DOM.button({'type':'submit', 'disabled':this.props.disabled, 'className':'button'}, "login")
131 ])
132 ]);
133 },
134
135 setInitialFocus: function () {
136 if (this.props.mode == 'PIN') {
137 this.refs['pin'].getDOMNode().select();
138 } else {
139 if (this.refs['username'].getDOMNode().value == '') {
140 this.refs['username'].getDOMNode().focus();
141 } else{
142 this.refs['passphrase'].getDOMNode().select();
143 }
144 }
145 },
146
147 render: function() {
148 returnnew this.props.template({'innerComponent': this.props.mode == 'PIN' ? this.pinForm() : this.loginForm()});
149 }
150});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js b/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js
new file mode 100644
index 0000000..cc4a06c
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js
@@ -0,0 +1,122 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.Base.module('Clipperz.PM.UI.Components');
25
26Clipperz.PM.UI.Components.Overlay = function(args) {
27 args = args || {};
28
29 this._defaultDelay = 2;
30 this._element = MochiKit.DOM.getElement('overlay');
31
32 return this;
33}
34
35//=============================================================================
36
37Clipperz.Base.extend(Clipperz.PM.UI.Components.Overlay, Object, {
38
39 //-------------------------------------------------------------------------
40
41 'toString': function () {
42 return "Clipperz.PM.UI.Components.Overlay component";
43 },
44
45 'element': function () {
46 // return MochiKit.DOM.getElement('overlay');
47 return this._element;
48 },
49
50 'getElement': function (aClass) {
51 return MochiKit.Selector.findChildElements(this.element(), ['.'+aClass])[0];
52 },
53
54 //-------------------------------------------------------------------------
55
56 'show': function (aMessage) {
57 this.resetStatus();
58 this.setMessage(aMessage);
59 MochiKit.DOM.removeElementClass(this.element(), 'ios-overlay-hide');
60 MochiKit.DOM.addElementClass(this.element(), 'ios-overlay-show');
61 },
62
63 'done': function (aMessage, aDelayBeforeHiding) {
64 this.completed(this.showDoneIcon, aMessage, aDelayBeforeHiding);
65 },
66
67 'failed': function (aMessage, aDelayBeforeHiding) {
68 this.completed(this.showFailIcon, aMessage, aDelayBeforeHiding);
69 },
70
71 //-------------------------------------------------------------------------
72
73 'resetStatus': function () {
74 MochiKit.Style.showElement(this.element());
75 MochiKit.Style.showElement(this.getElement('spinner'));
76 MochiKit.Style.hideElement(this.getElement('done'));
77 MochiKit.Style.hideElement(this.getElement('failed'));
78 },
79
80 'setMessage': function (aMessage) {
81 if (typeof(aMessage) != 'undefined') {
82 this.getElement('title').innerHTML = aMessage;
83 }
84 },
85
86 'completed': function (aFunctionToShowResult, aMessage, aDelayBeforeHiding) {
87 var delay = aDelayBeforeHiding || this.defaultDelay();
88
89 this.hideSpinner();
90 MochiKit.Base.bind(aFunctionToShowResult, this)();
91 this.setMessage(aMessage);
92
93 MochiKit.Async.callLater(delay, MochiKit.Base.bind(this.hide, this))
94 },
95
96 'hide': function () {
97 MochiKit.DOM.removeElementClass(this.element(), 'ios-overlay-show');
98 MochiKit.DOM.addElementClass(this.element(), 'ios-overlay-hide');
99 MochiKit.Async.callLater(1, MochiKit.Style.hideElement, this.element());
100 },
101
102 'hideSpinner': function () {
103 MochiKit.Style.hideElement(this.getElement('spinner'));
104 },
105
106 'showDoneIcon': function () {
107 MochiKit.Style.showElement(this.getElement('done'));
108 },
109
110 'showFailIcon': function () {
111 MochiKit.Style.showElement(this.getElement('failed'));
112 },
113
114 //-------------------------------------------------------------------------
115
116 'defaultDelay': function () {
117 return this._defaultDelay;
118 },
119
120 //-------------------------------------------------------------------------
121 __syntaxFix__: "syntax fix"
122});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js b/frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js
new file mode 100644
index 0000000..9b7c748
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js
@@ -0,0 +1,33 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.PM.UI.Components.PageTemplate = React.createClass({
25 render: function() {
26 returnReact.DOM.div(null, [
27 React.DOM.div({'className': 'header'}, [
28 React.DOM.h1(null, "clipperz")
29 ]),
30 React.DOM.div({'className': 'content'}, this.props.innerComponent)
31 ])
32 }
33});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/RegistrationWizard.js b/frontend/delta/js/Clipperz/PM/UI/Components/RegistrationWizard.js
new file mode 100644
index 0000000..051dcc5
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/RegistrationWizard.js
@@ -0,0 +1,240 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({
25
26 getDefaultProps: function () {
27 return {
28 steps: [
29 {name:'CREDENTIALS', label:'registration', _label:'credentials',description:"Choose your credentails"},
30 {name:'PASSWORD_VERIFICATION', label:'registration', _label:'verify', description:"Verify your passphrase"},
31 {name:'TERMS_OF_SERVICE', label:'registration', _label:'terms', description:"Check our terms of service"}
32 ],
33 disabled: false,
34 template: Clipperz.PM.UI.Components.PageTemplate
35 }
36 },
37
38 getInitialState: function () {
39 return {
40 currentStep: this.props['steps'][0]['name'],
41 username: '',
42 passphrase: '',
43 verify_passphrase: '',
44 no_password_recovery: false,
45 agree_terms_of_service: false
46 };
47 },
48
49 'propTypes': {
50 // steps: React.PropTypes.array,
51 disabled:React.PropTypes.bool,
52 template:React.PropTypes.func
53 },
54
55 //=========================================================================
56
57 currentStepIndex: function () {
58 return this.indexOfStepNamed(this.state['currentStep']);
59 },
60
61 indexOfStepNamed: function (aStepName) {
62 var stepConfiguration;
63 varresult;
64
65 stepConfiguration = this.props['steps'].filter(function (aConfig) { return aConfig['name'] == aStepName})[0];
66 result = this.props['steps'].indexOf(stepConfiguration);
67 return result;
68 },
69
70 //=========================================================================
71
72 statusClassForStep: function (aStep) {
73 varcurrentStepIndex = this.currentStepIndex();
74 var stepIndex = this.indexOfStepNamed(aStep['name']);
75 varresult;
76
77 if (stepIndex < currentStepIndex) {
78 result = 'left';
79 } else if (stepIndex == currentStepIndex) {
80 result = 'center';
81 } else {
82 result = 'right';
83 }
84
85 return result;
86 },
87
88 //=========================================================================
89
90 handleBackClick: function (anEvent) {
91 var nextStep;
92 anEvent.preventDefault();
93
94 if (this.currentStepIndex() > 0) {
95 nextStep = this.props['steps'][this.currentStepIndex() - 1];
96 this.setState({currentStep: nextStep['name']});
97 } else {
98 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
99 }
100 },
101
102 handleForwardClick: function (anEvent) {
103 var nextStep;
104 anEvent.preventDefault();
105
106 if (this.canMoveForward()) {
107
108 if (this.currentStepIndex() < this.props['steps'].length - 1) {
109 nextStep = this.props['steps'][this.currentStepIndex() + 1];
110 this.setState({currentStep: nextStep['name']});
111 } else {
112 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'registerNewUser', {
113 username: this.state['username'],
114 passphrase: this.state['passphrase']
115 })
116 }
117 }
118 },
119
120 //-------------------------------------------------------------------------
121
122 canMoveForward: function () {
123 var result;
124 var currentStep;
125
126 result = false;
127 currentStep = this.state['currentStep'];
128 if (currentStep == 'CREDENTIALS') {
129 result = ((this.state['username'] != '') && (this.state['passphrase'] != ''));
130 } else if (currentStep == 'PASSWORD_VERIFICATION') {
131 result = (this.state['passphrase'] == this.state['verify_passphrase']);
132 } else if (currentStep == 'TERMS_OF_SERVICE') {
133 result = (this.state['no_password_recovery'] && this.state['agree_terms_of_service']);
134 }
135
136 return result && !this.props['disabled'];
137 },
138
139 //=========================================================================
140
141 handleChange: function (anEvent) {
142 varrefs = this.refs;
143 var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
144 var newState = {};
145
146 if ((event.target.type == 'checkbox') || (event.target.type == 'radio')) {
147 newState[refName] = event.target.checked;
148 } else {
149 newState[refName] = event.target.value;
150 }
151 this.setState(newState);
152 },
153
154 //=========================================================================
155
156 renderIndexStep: function (aStep) {
157 returnReact.DOM.div({'className':'stepIndexItem ' + this.statusClassForStep(aStep)}, '.');
158 },
159
160 renderButtons: function () {
161 return [
162 React.DOM.a({className:'back button step_' + (this.currentStepIndex() - 1), onClick:this.handleBackClick}, '<<'),
163 React.DOM.a({className:'forward button step_' + (this.currentStepIndex() + 1) + ' ' + (this.canMoveForward() ? 'enabled' : 'disabled'), onClick:this.handleForwardClick}, '>>')
164 ];
165 },
166
167 render_CREDENTIALS: function () {
168 returnReact.DOM.div(null,[
169 React.DOM.label({'for':'name'}, "username"),
170 React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'/*, value:this.state.username*/}),
171 React.DOM.label({'for':'passphrase'}, "passphrase"),
172 React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'/*, value:this.state.passphrase*/})
173 ]);
174 },
175
176 render_PASSWORD_VERIFICATION: function () {
177 returnReact.DOM.div(null,[
178 React.DOM.label({'for':'verify_passphrase'}, "passphrase"),
179 React.DOM.input({'type':'password', 'name':'verify_passphrase', 'ref':'verify_passphrase', 'placeholder':"verify passphrase", 'key':'verify_passphrase'})
180 ]);
181 },
182
183 render_TERMS_OF_SERVICE: function () {
184 returnReact.DOM.div(null, [
185 React.DOM.div({className:'checkboxBlock'}, [
186 React.DOM.label({'for':'no_password_recovery'}, "I understand that Clipperz will not be able to recover a lost passphrase."),
187 React.DOM.input({'type':'checkbox', 'name':'no_password_recovery', 'ref':'no_password_recovery', 'key':'no_password_recovery'}),
188 React.DOM.p(null, "I understand that Clipperz will not be able to recover a lost passphrase.")
189 ]),
190 React.DOM.div({className:'checkboxBlock'}, [
191 React.DOM.label({'for':'agree_terms_of_service'}, "I have read and agreed to the Terms of Service."),
192 React.DOM.input({'type':'checkbox', 'name':'agree_terms_of_service', 'ref':'agree_terms_of_service', 'key':'agree_terms_of_service'}),
193 React.DOM.p(null, [
194 "I have read and agreed to the ",
195 React.DOM.a({href:'https://clipperz.com/terms_service/', target:'_blank'}, "Terms of Service.")
196 ])
197 ])
198 ]);
199 },
200
201 renderStep: function (aStep) {
202 returnReact.DOM.div({'className':'step' + ' ' + aStep['name'] + ' ' + this.statusClassForStep(aStep) + ' step_' + this.currentStepIndex()}, [
203 React.DOM.h1(null, aStep['label']),
204 React.DOM.p(null, aStep['description']),
205 this['render_' + aStep['name']].apply(),
206 React.DOM.div({'className':'stepIndex'}, MochiKit.Base.map(this.renderIndexStep, this.props['steps'])),
207 React.DOM.div({'className':'buttons'}, this.renderButtons())
208 ]);
209 },
210
211 _render: function () {
212 returnReact.DOM.div({'className':'registrationForm'},[
213 React.DOM.form({onChange: this.handleChange}, [
214 React.DOM.div({'className':'steps'}, MochiKit.Base.map(this.renderStep, this.props['steps']))
215 ])
216 ]);
217 },
218
219 render: function () {
220 returnnew this.props.template({'innerComponent': this._render()});
221 },
222
223 //=========================================================================
224
225 setInitialFocus: function () {
226 this.refs['username'].getDOMNode().focus();
227 },
228
229 componentDidUpdate: function (prevProps, prevState, rootNode) {
230 if (prevState['currentStep'] != this.state['currentStep']) {
231 if (this.state['currentStep'] == 'CREDENTIALS') {
232 this.refs['passphrase'].getDOMNode().select();
233 } else if (this.state['currentStep'] == 'PASSWORD_VERIFICATION') {
234 this.refs['verify_passphrase'].getDOMNode().select();
235 }
236 }
237 }
238
239 //=========================================================================
240});
diff --git a/frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js b/frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js
new file mode 100644
index 0000000..d9dfe6d
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js
@@ -0,0 +1,256 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.Base.module('Clipperz.PM.UI');
25
26Clipperz.PM.UI.DirectLoginRunner = function(args) {
27 this._directLogin = args['directLogin'] || Clipperz.Base.exception.raise('MandatoryParameter');
28 this._target = Clipperz.PM.Crypto.randomKey();
29
30 return this;
31}
32
33MochiKit.Base.update(Clipperz.PM.UI.DirectLoginRunner.prototype, {
34
35 'toString': function() {
36 return "Clipperz.PM.UI.DirectLoginRunner";
37 },
38
39 //-----------------------------------------------------------------------------
40
41 'directLogin': function () {
42 return this._directLogin;
43 },
44
45 //-----------------------------------------------------------------------------
46
47 'target': function () {
48 return this._target;
49 },
50
51 //=============================================================================
52
53 'setWindowTitle': function (aWindow, aTitle) {
54 aWindow.document.title = aTitle;
55 },
56
57 'setWindowBody': function (aWindow, anHTML) {
58 aWindow.document.body.innerHTML = anHTML;
59 },
60
61 //=============================================================================
62
63 'initialWindowSetup': function (aWindow) {
64 this.setWindowTitle(aWindow, "Loading Clipperz Direct Login");
65 this.setWindowBody (aWindow, MochiKit.DOM.toHTML(MochiKit.DOM.H3("Loading Clipperz Direct Login ...")));
66 },
67
68 //-----------------------------------------------------------------------------
69
70 'updateWindowWithDirectLoginLabel': function (aWindow, aLabel) {
71 var titleText;
72 var bodyText;
73
74 titleText = "Loading '__label__' Direct Login".replace(/__label__/, aLabel)
75 bodyText = "Loading '__label__' Direct Login... ".replace(/__label__/, aLabel)
76
77 this.setWindowTitle(aWindow, titleText);
78 this.setWindowBody (aWindow, MochiKit.DOM.toHTML(MochiKit.DOM.H3(bodyText)));
79 },
80
81 //-----------------------------------------------------------------------------
82
83 'updateWindowWithHTMLContent': function (aWindow, anHtml) {
84 this.setWindowBody(aWindow, anHtml);
85 },
86
87 //=============================================================================
88
89 'submitLoginForm': function(aWindow, aSubmitFunction) {
90 MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function () {
91 var formElement;
92 var submitButtons;
93
94 formElement = MochiKit.DOM.getElement('directLoginForm');
95
96 submitButtons = MochiKit.Base.filter(function(anInputElement) {
97 return ((anInputElement.tagName.toLowerCase() == 'input') && (anInputElement.getAttribute('type').toLowerCase() == 'submit'));
98 }, formElement.elements);
99
100 if (submitButtons.length == 0) {
101 if (typeof(formElement.submit) == 'function') {
102 formElement.submit();
103 } else {
104 aSubmitFunction.apply(formElement);
105 }
106/*
107 varformSubmitFunction;
108
109 formSubmitFunction = MochiKit.Base.method(formElement, 'submit');
110 if (Clipperz_IEisBroken == true) {
111 formElement.submit();
112 } else {
113 formSubmitFunction();
114 }
115*/
116 } else {
117 submitButtons[0].click();
118 }
119 }, this));
120 },
121
122 //-------------------------------------------------------------------------
123
124 'runSubmitFormDirectLogin': function (aWindow, someAttributes) {
125 var html;
126 var formElement;
127 var submitFunction;
128
129 formElement = MochiKit.DOM.FORM({
130 'id':'directLoginForm',
131 'method':someAttributes['formAttributes']['method'],
132 'action':someAttributes['formAttributes']['action']
133 });
134
135 submitFunction = formElement.submit;
136
137 MochiKit.DOM.appendChildNodes(formElement, MochiKit.Base.map(function (anInputAttributes) {
138 return MochiKit.DOM.INPUT({'type':'hidden', 'name':anInputAttributes[0], 'value':anInputAttributes[1]});
139 }, MochiKit.Base.items(someAttributes['inputValues'])));
140
141 html ='';
142 html += '<h3>Loading ' + someAttributes['label'] + ' ...</h3>';
143 html +=MochiKit.DOM.appendChildNodes(MochiKit.DOM.DIV(), MochiKit.DOM.appendChildNodes(MochiKit.DOM.DIV({style:'display:none; visibility:hidden;'}), formElement)).innerHTML;
144
145 this.updateWindowWithHTMLContent(aWindow, html);
146 this.submitLoginForm(aWindow, submitFunction);
147 },
148
149 //-------------------------------------------------------------------------
150
151 'runHttpAuthDirectLogin': function(aWindow, someAttributes) {
152 var completeUrl;
153 var url;
154
155 url = someAttributes['inputValues']['url'];
156
157 if (/^https?\:\/\//.test(url) == false) {
158 url = 'http://' + url;
159 }
160
161 if (Clipperz_IEisBroken === true) {
162 completeUrl = url;
163 } else {
164 var username;
165 var password;
166
167 username = someAttributes['inputValues']['username'];
168 password = someAttributes['inputValues']['password'];
169 /(^https?\:\/\/)?(.*)/.test(url);
170
171 completeUrl = RegExp.$1 + username + ':' + password + '@' + RegExp.$2;
172 }
173
174 window.open(completeUrl, this.target());
175 },
176
177 //=============================================================================
178
179 'runDirectLogin': function (aWindow) {
180 var deferredResult;
181
182 deferredResult = new Clipperz.Async.Deferred("DirectLoginRunner.openDirectLogin", {trace:false});
183 deferredResult.addMethod(this, 'initialWindowSetup', aWindow);
184 deferredResult.addMethod(this.directLogin(), 'label');
185 deferredResult.addMethod(this, 'updateWindowWithDirectLoginLabel', aWindow);
186 deferredResult.collectResults({
187 'type': MochiKit.Base.method(this.directLogin(), 'type'),
188 'label': MochiKit.Base.method(this.directLogin(), 'label'),
189 'formAttributes':MochiKit.Base.method(this.directLogin(), 'formAttributes'),
190 'inputValues': MochiKit.Base.method(this.directLogin(), 'inputValues')
191 });
192 deferredResult.addCallback(MochiKit.Base.bind(function (someAttributes) {
193 switch (someAttributes['type']) {
194 case 'http_auth':
195 this.runHttpAuthDirectLogin(aWindow, someAttributes);
196 break;
197 case 'simple_url':
198 this.runSimpleUrlDirectLogin(aWindow, someAttributes);
199 break;
200 default:
201 this.runSubmitFormDirectLogin(aWindow, someAttributes);
202 break;
203 }
204 }, this));
205 deferredResult.callback();
206
207 return deferredResult;
208 },
209
210 //=============================================================================
211
212 'run': function () {
213 var newWindow;
214
215 newWindow = window.open(Clipperz.PM.Strings.getValue('directLoginJumpPageUrl'), this.target());
216
217 return this.runDirectLogin(newWindow);
218 },
219
220 //=============================================================================
221
222 'test': function () {
223 var iFrame;
224 var newWindow;
225
226 iFrame = MochiKit.DOM.createDOM('iframe');
227 MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body, iFrame);
228
229 newWindow = iFrame.contentWindow;
230
231 return this.runDirectLogin(newWindow);
232 },
233
234 //=============================================================================
235 __syntaxFix__: "syntax fix"
236});
237
238//-----------------------------------------------------------------------------
239
240Clipperz.PM.UI.DirectLoginRunner.openDirectLogin = function (aDirectLogin) {
241 varrunner;
242
243 runner = new Clipperz.PM.UI.DirectLoginRunner({directLogin:aDirectLogin});
244 return runner.run();
245};
246
247//-----------------------------------------------------------------------------
248
249Clipperz.PM.UI.DirectLoginRunner.testDirectLogin = function (aDirectLogin) {
250 varrunner;
251
252 runner = new Clipperz.PM.UI.DirectLoginRunner({directLogin:aDirectLogin});
253 return runner.test();
254};
255
256//-----------------------------------------------------------------------------
diff --git a/frontend/delta/js/Clipperz/PM/UI/MainController.js b/frontend/delta/js/Clipperz/PM/UI/MainController.js
new file mode 100644
index 0000000..da7540e
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/MainController.js
@@ -0,0 +1,491 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.Base.module('Clipperz.PM.UI');
25
26Clipperz.PM.UI.MainController = function() {
27 var pages;
28
29 this._proxy = null;
30 this._user = null;
31 this._filter= '';
32
33 //this._currentPage = 'loadingPage';
34
35 this._pageStack = ['loadingPage'];
36 this._overlay = new Clipperz.PM.UI.Components.Overlay();
37 pages = {
38 'loginPage': new Clipperz.PM.UI.Components.LoginForm(),
39 'registrationPage':new Clipperz.PM.UI.Components.RegistrationWizard(),
40 'cardListPage': new Clipperz.PM.UI.Components.CardList(),
41 'cardDetailPage':new Clipperz.PM.UI.Components.CardDetail({card: {}}),
42 'errorPage': new Clipperz.PM.UI.Components.ErrorPage({message:''})
43 };
44
45 MochiKit.Base.map(function (anId) {React.renderComponent(pages[anId], MochiKit.DOM.getElement(anId))}, MochiKit.Base.keys(pages));
46 this._pages = pages;
47 this.registerForNotificationCenterEvents();
48
49 return this;
50}
51
52MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
53
54 toString: function () {
55 return "Clipperz.PM.UI.MainController";
56 },
57
58 //=========================================================================
59
60 overlay: function () {
61 return this._overlay;
62 },
63
64 loginForm: function () {
65 return this._loginForm;
66 },
67
68 registrationWizard: function () {
69 return this._registrationWizard;
70 },
71
72 //=========================================================================
73
74 isOnline: function() {
75 return navigator.onLine;
76 },
77
78 hasLocalData: function() {
79 return false;
80 },
81
82 loginMode: function () {
83 //PIN is set using this command:
84 //Clipperz.PM.PIN.setCredentialsWithPIN('1234', {'username':'joe', 'passphrase':'clipperz'});
85
86 return Clipperz.PM.PIN.isSet() ? 'PIN' : 'CREDENTIALS';
87 },
88
89 //=========================================================================
90
91 pages: function () {
92 return this._pages;
93 },
94
95 pageStack: function () {
96 return this._pageStack;
97 },
98
99 //=========================================================================
100
101 selectInitialProxy: function () {
102 if (this.isOnline()) {
103 this._proxy = Clipperz.PM.Proxy.defaultProxy;
104 } else {
105 if (this.hasLocalData()) {
106 this._proxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
107 } else {
108 this.showOfflineError();
109 }
110 }
111 },
112
113 proxy: function () {
114 return this._proxy;
115 },
116
117 //=========================================================================
118
119 registerForNotificationCenterEvents: function () {
120 var events= ['doLogin', 'registerNewUser', 'showRegistrationForm', 'goBack', 'showRecord', 'searchCards', 'runDirectLogin'];
121 var self= this;
122
123 MochiKit.Base.map(function (anEvent) {
124 MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, anEvent));
125 }, events);
126
127 // MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
128 MochiKit.Signal.connect(window, 'onbeforeunload',MochiKit.Base.method(this, 'shouldExitApp'));
129 },
130
131 //-------------------------------------------------------------------------
132
133 run: function (parameters) {
134 var shouldShowRegistrationForm;
135
136 this.selectInitialProxy();
137 shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && this.proxy().canRegisterNewUsers();
138 this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()});
139
140 if (shouldShowRegistrationForm) {
141 this.showRegistrationForm();
142 } else {
143 this.showLoginForm();
144 }
145 this.overlay().done("", 0.5);
146 },
147
148 //-------------------------------------------------------------------------
149
150 showLoginForm: function () {
151 varloginFormPage;
152
153 loginFormPage = this.pages()['loginPage'];
154 loginFormPage.setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()});
155 this.moveInPage(this.currentPage(), 'loginPage');
156 MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus'));
157 },
158
159 showRegistrationForm: function () {
160 var currentPage;
161 varregistrationPage;
162
163 currentPage = this.currentPage();
164 registrationPage = this.pages()['registrationPage'];
165 this.setCurrentPage('loginPage');
166 registrationPage.setProps({});
167 this.moveInPage(currentPage, 'registrationPage');
168 MochiKit.Async.callLater(0.5, MochiKit.Base.method(registrationPage, 'setInitialFocus'));
169 },
170
171 //=========================================================================
172
173 doLogin: function (event) {
174 varcredentials;
175 var getPassphraseDelegate;
176 varuser;
177
178 user = null;
179
180 this.overlay().show("logging in");
181 this.pages()['loginPage'].setProps({disabled:true});
182
183 if ('pin' in event) {
184 credentials = Clipperz.PM.PIN.credentialsWithPIN(event['pin']);
185 } else {
186 credentials = event;
187 }
188 getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, credentials.passphrase);
189 user = new Clipperz.PM.DataModel.User({'username':credentials.username, 'getPassphraseFunction':getPassphraseDelegate});
190
191 deferredResult = new Clipperz.Async.Deferred('MainController.doLogin', {trace:false});
192 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
193 deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'deferredEntropyCollection');
194 deferredResult.addMethod(user, 'login');
195 deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount');
196 deferredResult.addMethod(this, 'setUser', user);
197
198 // deferredResult.addMethod(this, 'setupApplication');
199 deferredResult.addMethod(this, 'runApplication');
200 deferredResult.addMethod(this.overlay(), 'done', "", 1);
201 deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
202 deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) {
203 if (anError['isPermanent'] != true) {
204 this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()});
205 this.pages()['loginPage'].setInitialFocus();
206 }
207 return anError;
208 }, this, event))
209 deferredResult.callback();
210
211 return deferredResult;
212 },
213
214 //-------------------------------------------------------------------------
215
216 registerNewUser: function (credentials) {
217 vardeferredResult;
218
219 this.overlay().show("creating user");
220
221 this.pages()['registrationPage'].setProps({disabled:true});
222 deferredResult = new Clipperz.Async.Deferred('MainController.registerNewUser', {trace:false});
223 deferredResult.addCallback(Clipperz.PM.DataModel.User.registerNewAccount,
224 credentials['username'],
225 MochiKit.Base.partial(MochiKit.Async.succeed, credentials['passphrase'])
226 );
227 deferredResult.addMethod(this, 'doLogin', credentials);
228 deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
229 deferredResult.addErrback(MochiKit.Base.bind(function (anError) {
230 if (anError['isPermanent'] != true) {
231 this.pages()['registrationPage'].setProps({disabled:false});
232 this.pages()['registrationPage'].setInitialFocus();
233 }
234 return anError;
235 }, this));
236
237 deferredResult.callback();
238
239 return deferredResult;
240
241 },
242
243 //-------------------------------------------------------------------------
244
245 user: function () {
246 return this._user;
247 },
248
249 setUser: function (aUser) {
250 this._user = aUser;
251 return this._user;
252 },
253
254 //=========================================================================
255
256 allCardInfo: function () {
257 var deferredResult;
258 varcardInfo;
259
260 cardInfo = {
261 '_rowObject': MochiKit.Async.succeed,
262 '_reference': MochiKit.Base.methodcaller('reference'),
263 '_searchableContent':MochiKit.Base.methodcaller('searchableContent'),
264 'label': MochiKit.Base.methodcaller('label'),
265 'favicon': MochiKit.Base.methodcaller('favicon')
266 };
267
268 deferredResult = new Clipperz.Async.Deferred('MainController.allCardInfo', {trace:false});
269 deferredResult.addMethod(this.user(), 'getRecords');
270 deferredResult.addCallback(MochiKit.Base.map, Clipperz.Async.collectResults("CardList.value - collectResults", cardInfo, {trace:false}));
271 deferredResult.addCallback(Clipperz.Async.collectAll);
272 deferredResult.callback();
273
274 return deferredResult;
275 },
276
277 filterCards: function (someCardInfo) {
278 var filter;
279 varfilterRegExp;
280 varresult;
281
282 filter = this.filter().replace(/[^A-Za-z0-9]/g, "\\$&");
283 filterRegExp = new RegExp(filter, "i");
284 result = MochiKit.Base.filter(function (aCardInfo) { return filterRegExp.test(aCardInfo['_searchableContent'])}, someCardInfo);
285
286 return result;
287 },
288
289 sortCards: function (someCardInfo) {
290 return someCardInfo.sort(Clipperz.Base.caseInsensitiveKeyComparator('label'));
291 },
292
293 showRecordList: function () {
294 var deferredResult;
295
296 deferredResult = new Clipperz.Async.Deferred('MainController.showRecordList', {trace:false});
297 deferredResult.addMethod(this, 'allCardInfo');
298 deferredResult.addMethod(this, 'filterCards');
299 deferredResult.addMethod(this, 'sortCards');
300 deferredResult.addCallback(MochiKit.Base.bind(function (someRecordInfo) {
301 this.pages()['cardListPage'].setProps({cardList: someRecordInfo});
302 }, this));
303 deferredResult.callback();
304
305 return deferredResult;
306 },
307
308 filter: function (){
309 return this._filter;
310 },
311
312 setFilter: function (aValue) {
313 this._filter = aValue;
314 },
315
316 searchCards: function (someParameters) {
317//console.log("SEARCH CARDS", someParameters);
318 this.setFilter(someParameters);
319 this.showRecordList();
320 },
321
322 //=========================================================================
323
324 runApplication: function () {
325 MochiKit.Signal.connect(window, 'onpopstate',MochiKit.Base.method(this, 'historyGoBack'));
326 this.moveInPage(this.currentPage(), 'cardListPage');
327 return this.showRecordList();
328 },
329
330 showRecord: function (aRecordReference) {
331//console.log("Show Record", aRecordReference);
332 vardeferredResult;
333
334 this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
335 deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:false});
336 // deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
337 deferredResult.addMethod(this.user(), 'getRecord', aRecordReference);
338 deferredResult.addMethodcaller('content');
339 deferredResult.addCallback(MochiKit.Base.bind(function (aCard) {
340//console.log("CARD DETAILS", aCard);
341 this.pages()['cardDetailPage'].setProps({card: aCard});
342 this.pages()['cardListPage'].setProps({selectedCard: null});
343 }, this));
344 deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'cardDetailPage', true);
345 deferredResult.callback();
346
347 return deferredResult;
348 },
349
350 runDirectLogin: function (someParameters) {
351console.log("RUN DIRECT LOGIN", someParameters);
352 vardeferredResult;
353
354 // this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
355 deferredResult = new Clipperz.Async.Deferred('MainController.runDirectLogin', {trace:false});
356 // deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
357 deferredResult.addMethod(this.user(), 'getRecord', someParameters['record']);
358 deferredResult.addMethodcaller('directLoginWithReference', someParameters['directLogin']);
359 deferredResult.addCallback(Clipperz.PM.UI.DirectLoginRunner.openDirectLogin);
360 deferredResult.callback();
361
362 return deferredResult;
363 },
364
365 shouldExitApp: function (anEvent) {
366console.log("SHOULD EXIT APP");
367 anEvent.preventDefault();
368 anEvent.stopPropagation();
369 },
370
371 //=========================================================================
372
373 genericErrorHandler: function (anEvent, anError) {
374 var errorMessage;
375 varresult;
376
377 result = anError;
378 errorMessage = "login failed";
379
380 if (anError['isPermanent'] === true) {
381 this.pages()['errorPage'].setProps({message:anError.message});
382 this.moveInPage(this.currentPage(), 'errorPage');
383 errorMessage = "failure";
384 } else {
385 if ('pin' in anEvent) {
386 errorCount = Clipperz.PM.PIN.recordFailedAttempt();
387 if (errorCount == -1) {
388 errorMessage = "PIN resetted";
389 }
390 }
391 }
392 this.overlay().failed(errorMessage, 1);
393
394 return result;
395 },
396
397 //=========================================================================
398
399 slidePage: function (fromPage, toPage, direction) {
400 varfromPosition;
401 var toPosition;
402
403 if (direction == "LEFT") {
404 fromPosition = 'right';
405 toPosition = 'left'
406 } else {
407 fromPosition = 'left';
408 toPosition = 'right'
409 }
410
411 MochiKit.DOM.addElementClass(fromPage, toPosition + ' transition');
412
413 MochiKit.DOM.addElementClass(toPage, fromPosition);
414 MochiKit.DOM.removeElementClass(toPage, toPosition);
415 MochiKit.DOM.addElementClass(toPage, 'transition');
416 MochiKit.Async.callLater(0.1, function () {
417 MochiKit.DOM.removeElementClass(toPage, fromPosition);
418 })
419
420 MochiKit.Async.callLater(0.5, function () {
421 MochiKit.DOM.removeElementClass(fromPage, 'transition');
422 MochiKit.DOM.removeElementClass(toPage, 'transition');
423 })
424 },
425
426 rotateInPage: function (fromPage, toPage) {
427 //Broken! :(
428 MochiKit.DOM.addElementClass(MochiKit.DOM.getElement('mainDiv'), 'show-right');
429 },
430
431 //.........................................................................
432
433 goBack: function () {
434 varfromPage;
435 var toPage;
436
437 fromPage = this.pageStack().shift();
438 toPage = this.currentPage();
439 this.pages()[toPage].setProps({});
440 this.moveOutPage(fromPage, toPage);
441 },
442
443 historyGoBack: function (anEvent) {
444 anEvent.preventDefault();
445 anEvent.stopPropagation();
446 this.goBack();
447 },
448
449 currentPage: function () {
450 return this.pageStack()[0];
451 },
452
453 setCurrentPage: function (aPage) {
454 this.pageStack().unshift(aPage);
455 },
456
457 moveInPage: function (fromPage, toPage, addToHistory) {
458 varshouldAddItemToHistory;
459
460 shouldAddItemToHistory = typeof(addToHistory) == 'undefined' ? false : addToHistory;
461
462 this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'LEFT');
463 this.setCurrentPage(toPage);
464
465 if (shouldAddItemToHistory) {
466//console.log("ADD ITEM TO HISTORY");
467//console.log("ADD ITEM TO HISTORY - window", window);
468//console.log("ADD ITEM TO HISTORY - window.history", window.history);
469 window.history.pushState({'fromPage': fromPage, 'toPage': toPage});
470 //# window.history.pushState();
471//console.log("ADDED ITEM TO HISTORY");
472 } else {
473//console.log("Skip HISTORY");
474 }
475 },
476
477 moveOutPage: function (fromPage, toPage) {
478 this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'RIGHT');
479 this.setCurrentPage(toPage);
480 },
481
482 //=========================================================================
483/*
484 wrongAppVersion: function (anError) {
485 // this.pages()['errorPage'].setProps({message:anError.message});
486 // this.moveInPage('errorPage', this.currentPage());
487 },
488*/
489 //=========================================================================
490 __syntaxFix__: "syntax fix"
491});