Completed
Push — master ( 641a91...fc9f6a )
by
unknown
10:16
created

js/app/controllers/bookmarklet.js   F

Complexity

Total Complexity 64
Complexity/F 1.64

Size

Lines of Code 395
Function Count 39

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
dl 0
loc 395
rs 3.28
c 0
b 0
f 0
nc 16
wmc 64
mnd 3
bc 63
fnc 39
bpm 1.6153
cpm 1.641
noi 1

1 Function

Rating   Name   Duplication   Size   Complexity  
B angular.controller(ꞌBookmarkletCtrlꞌ) 0 379 4

How to fix   Complexity   

Complexity

Complex classes like js/app/controllers/bookmarklet.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 * Nextcloud - passman
3
 *
4
 * @copyright Copyright (c) 2016, Sander Brand ([email protected])
5
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel ([email protected])
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
(function () {
24
	'use strict';
25
26
27
	/**
28
	 * @ngdoc function
29
	 * @name passmanApp.controller:MainCtrl
30
	 * @description
31
	 * # MainCtrl
32
	 * Controller of the passmanApp
33
	 */
34
	angular.module('passmanApp')
35
		.controller('BookmarkletCtrl', ['$scope', '$rootScope', '$location', 'VaultService', 'CredentialService', 'SettingsService', 'NotificationService', 'EncryptService', 'TagService', 'FileService', 'ShareService', '$translate',
36
			function ($scope, $rootScope, $location, VaultService, CredentialService, SettingsService, NotificationService, EncryptService, TagService, FileService, ShareService, $translate) {
37
				$scope.active_vault = false;
38
39
				$scope.http_warning_hidden = true;
40
				if ($location.$$protocol === 'http') {
41
					$scope.using_http = true;
42
					//$scope.http_warning_hidden = false;
43
44
				}
45
46
				$scope.logout = function () {
47
					$scope.active_vault = false;
48
				};
49
				if (SettingsService.getSetting('defaultVault') && SettingsService.getSetting('defaultVaultPass')) {
50
					var _vault = angular.copy(SettingsService.getSetting('defaultVault'));
51
					VaultService.getVault(_vault).then(function (vault) {
52
						vault.vaultKey = angular.copy(SettingsService.getSetting('defaultVaultPass'));
53
						VaultService.setActiveVault(vault);
54
						$scope.active_vault = vault;
55
56
						$scope.pwSettings = VaultService.getVaultSetting('pwSettings',
57
							{
58
								'length': 12,
59
								'useUppercase': true,
60
								'useLowercase': true,
61
								'useDigits': true,
62
								'useSpecialChars': true,
63
								'minimumDigitCount': 3,
64
								'avoidAmbiguousCharacters': false,
65
								'requireEveryCharType': true,
66
								'generateOnCreate': true
67
							});
68
					});
69
				}
70
				/**
71
				 * Vault selection stuff
72
				 */
73
				VaultService.getVaults().then(function (vaults) {
74
					$scope.vaults = vaults;
75
76
				});
77
				$scope.default_vault = false;
78
				$scope.remember_vault_password = false;
79
				$scope.list_selected_vault = false;
80
81
82
				$scope.toggleDefaultVault = function () {
83
					$scope.default_vault = !$scope.default_vault;
84
					if ($scope.default_vault === true) {
85
						SettingsService.setSetting('defaultVault', $scope.list_selected_vault);
86
					} else {
87
						SettingsService.setSetting('defaultVault', null);
88
					}
89
				};
90
91
				$scope.toggleRememberPassword = function () {
92
					$scope.remember_vault_password = !$scope.remember_vault_password;
93
					if ($scope.remember_vault_password) {
94
						SettingsService.setSetting('defaultVault', $scope.list_selected_vault);
95
						$scope.default_vault = true;
96
					}
97
					if ($scope.remember_vault_password !== true) {
98
						SettingsService.setSetting('defaultVault', null);
99
					}
100
				};
101
102
				$scope.clearState = function () {
103
					$scope.list_selected_vault = false;
104
					$scope.creating_vault = false;
105
					$scope.error = false;
106
				};
107
108
				$scope.selectVault = function (vault) {
109
					$scope.list_selected_vault = vault;
110
				};
111
				$scope.sharing_keys = {};
112
				$scope.newVault = function () {
113
					$scope.creating_vault = true;
114
					var key_size = 1024;
115
					ShareService.generateRSAKeys(key_size).progress(function (progress) {
116
						var p = progress > 0 ? 2 : 1;
117
						var msg =  $translate.instant('generating.sharing.keys');
118
						msg = msg.replace('%step', p);
119
						$scope.creating_keys = msg;
120
						$scope.$digest();
121
					}).then(function (kp) {
122
						var pem = ShareService.rsaKeyPairToPEM(kp);
123
						$scope.creating_keys = false;
124
						$scope.sharing_keys.private_sharing_key = pem.privateKey;
125
						$scope.sharing_keys.public_sharing_key = pem.publicKey;
126
						$scope.$digest();
127
					});
128
129
				};
130
131
				var _loginToVault = function (vault, vault_key) {
132
					var _vault = angular.copy(vault);
133
					_vault.vaultKey = angular.copy(vault_key);
134
					delete _vault.credentials;
135
					$scope.active_vault = _vault;
136
137
				};
138
139
				$scope.vaultDecryptionKey = '';
140
				$scope.loginToVault = function (vault, vault_key) {
141
					$scope.error = false;
142
					var _vault = angular.copy(vault);
143
					_vault.vaultKey = angular.copy(vault_key);
144
145
					VaultService.setActiveVault(_vault);
146
					try {
147
						EncryptService.decryptString(vault.challenge_password);
148
						if ($scope.remember_vault_password) {
149
							SettingsService.setSetting('defaultVaultPass', vault_key);
150
						}
151
						_loginToVault(vault, vault_key);
152
153
					} catch (e) {
154
						$scope.error = $translate.instant('invalid.vault.key');
155
					}
156
157
				};
158
159
160
				$scope.createVault = function (vault_name, vault_key, vault_key2) {
161
					if (vault_key !== vault_key2) {
162
						$scope.error = $translate.instant('password.do.not.match');
163
						return;
164
					}
165
					VaultService.createVault(vault_name).then(function (vault) {
166
						$scope.vaults.push(vault);
167
						var _vault = angular.copy(vault);
168
						_vault.vaultKey = angular.copy(vault_key);
169
						VaultService.setActiveVault(_vault);
170
						var test_credential = CredentialService.newCredential();
171
						test_credential.label = 'Test key for vault ' + vault_name;
172
						test_credential.hidden = true;
173
						test_credential.vault_id = vault.vault_id;
174
						test_credential.password = 'lorum ipsum';
175
						CredentialService.createCredential(test_credential).then(function () {
176
							_vault.public_sharing_key = angular.copy($scope.sharing_keys.public_sharing_key);
177
							_vault.private_sharing_key = EncryptService.encryptString(angular.copy($scope.sharing_keys.private_sharing_key));
178
							VaultService.updateSharingKeys(_vault).then(function () {
179
								_loginToVault(vault, vault_key);
180
							});
181
						});
182
					});
183
				};
184
185
186
				/**
187
				 * End vault selection stiff
188
				 */
189
				$scope.storedCredential = CredentialService.newCredential();
190
191
				var QueryString = function () {
192
					// This function is anonymous, is executed immediately and
193
					// the return value is assigned to QueryString!
194
					var query_string = {};
195
					var query = window.location.search.substring(1);
196
					var vars = query.split("&");
197
					for (var i = 0; i < vars.length; i++) {
198
						var pair = vars[i].split("=");
199
						// If first entry with this name
200
						if (typeof query_string[pair[0]] === "undefined") {
201
							query_string[pair[0]] = decodeURIComponent(pair[1]);
202
							// If second entry with this name
203
						} else if (typeof query_string[pair[0]] === "string") {
204
							var arr = [query_string[pair[0]], decodeURIComponent(pair[1])];
205
							query_string[pair[0]] = arr;
206
							// If third or later entry with this name
207
						} else {
208
							query_string[pair[0]].push(decodeURIComponent(pair[1]));
209
						}
210
					}
211
					return query_string;
212
				}();
213
				var query_string = QueryString;
214
				$scope.storedCredential.label = query_string.title;
215
				$scope.storedCredential.url = query_string.url;
216
217
				$scope.setHttpWarning = function (state) {
218
					$scope.http_warning_hidden = state;
219
				};
220
221
222
223
224
				$translate(['general', 'password', 'custom.fields','files','otp']).then(function (translations) {
225
					$scope.tabs = [{
226
						title: translations.general,
227
						url: 'views/partials/forms/edit_credential/basics.html',
228
						color: 'blue'
229
					}, {
230
						title: translations.password,
231
						url: 'views/partials/forms/edit_credential/password.html',
232
						color: 'green'
233
					}, {
234
						title:translations['custom.fields'],
235
						url: 'views/partials/forms/edit_credential/custom_fields.html',
236
						color: 'orange'
237
					}, {
238
						title: translations.files,
239
						url: 'views/partials/forms/edit_credential/files.html',
240
						color: 'yellow'
241
					}, {
242
						title: translations.otp,
243
						url: 'views/partials/forms/edit_credential/otp.html',
244
						color: 'purple'
245
					}];
246
					$scope.currentTab = $scope.tabs[0];
247
				});
248
249
				$scope.getTags = function ($query) {
250
					return TagService.searchTag($query);
251
				};
252
253
254
				$scope.onClickTab = function (tab) {
255
					$scope.currentTab = tab;
256
				};
257
258
				$scope.isActiveTab = function (tab) {
259
					return tab.url === $scope.currentTab.url;
260
				};
261
262
				/**
263
				 * Below general edit functions
264
				 */
265
266
				$scope.pwGenerated = function (pass) {
267
					$scope.storedCredential.password_repeat = pass;
268
				};
269
270
				var _customField = {
271
					label: '',
272
					value: '',
273
					secret: false,
274
					field_type: 'text'
275
				};
276
				$scope.selected_field_type = 'text';
277
				$scope.new_custom_field = angular.copy(_customField);
278
279
				$scope.addCustomField = function () {
280
					var _field = angular.copy($scope.new_custom_field);
281
282
					if (!_field.label) {
283
						NotificationService.showNotification($translate.instant('error.no.label'), 3000);
284
					}
285
					if (!_field.value) {
286
						NotificationService.showNotification($translate.instant('error.no.value'), 3000);
287
					}
288
					if (!_field.label || !_field.value) {
289
						return;
290
					}
291
					$scope.selected_field_type = 'text';
292
293
					_field.secret = angular.copy(($scope.selected_field_type === 'password'));
294
					_field.field_type =  angular.copy($scope.selected_field_type);
295
					if(_field.field_type === 'file'){
296
						var _file = $scope.new_custom_field.value;
297
						FileService.uploadFile(_file).then(function (result) {
298
							delete result.file_data;
299
							result.filename = EncryptService.decryptString(result.filename);
300
							_field.value = result;
301
							$scope.storedCredential.custom_fields.push(_field);
302
							$scope.new_custom_field = angular.copy(_customField);
303
						});
304
					} else {
305
						$scope.storedCredential.custom_fields.push(_field);
306
						$scope.new_custom_field = angular.copy(_customField);
307
					}
308
309
				};
310
311
				$scope.addFileToCustomField = function (file) {
312
					var _file = {
313
						filename: file.name,
314
						size: file.size,
315
						mimetype: file.type,
316
						data: file.data
317
					};
318
					$scope.new_custom_field.value = _file;
319
					$scope.$digest();
320
				};
321
322
				$scope.deleteCustomField = function (field) {
323
					if(field.hasOwnProperty('field_type')) {
324
						if (field.field_type === 'file') {
325
							FileService.deleteFile(field.value);
326
						}
327
					}
328
					var idx = $scope.storedCredential.custom_fields.indexOf(field);
329
					$scope.storedCredential.custom_fields.splice(idx, 1);
330
				};
331
332
				$scope.new_file = {
333
					name: '',
334
					data: null
335
				};
336
337
				$scope.deleteFile = function (file) {
338
					var idx = $scope.storedCredential.files.indexOf(file);
339
					FileService.deleteFile(file).then(function () {
340
						$scope.storedCredential.files.splice(idx, 1);
341
					});
342
				};
343
344
				$scope.fileLoaded = function (file) {
345
					var _file = {
346
						filename: file.name,
347
						size: file.size,
348
						mimetype: file.type,
349
						data: file.data
350
					};
351
					FileService.uploadFile(_file).then(function (result) {
352
						delete result.file_data;
353
						result.filename = EncryptService.decryptString(result.filename);
354
						$scope.storedCredential.files.push(result);
355
					});
356
357
358
					$scope.$digest();
359
				};
360
361
				$scope.fileLoadError = function (error) {
362
					return error;
363
				};
364
365
				$scope.selected_file = '';
366
				$scope.fileprogress = [];
367
				$scope.fileSelectProgress = function (progress) {
368
					if (progress) {
369
						$scope.fileprogress = progress;
370
						$scope.$digest();
371
372
					}
373
				};
374
				$scope.renewIntervalValue = 0;
375
				$scope.renewIntervalModifier = '0';
376
377
				$scope.updateInterval = function (renewIntervalValue, renewIntervalModifier) {
378
					var value = parseInt(renewIntervalValue);
379
					var modifier = parseInt(renewIntervalModifier);
380
					if (value && modifier) {
381
						$scope.storedCredential.renew_interval = value * modifier;
382
					}
383
				};
384
385
				$scope.parseQR = function (QRCode) {
386
					var re = /otpauth:\/\/(totp|hotp)\/(.*)\?(secret|issuer)=(.*)&(issuer|secret)=(.*)/, parsedQR, qrInfo;
387
					qrInfo = [];
388
					parsedQR = (QRCode.qrData.match(re));
389
					if (parsedQR)
390
						qrInfo = {
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
391
							type: parsedQR[1],
392
							label: decodeURIComponent(parsedQR[2]),
393
							qr_uri: QRCode
394
						};
395
					qrInfo[parsedQR[3]] = parsedQR[4];
396
					qrInfo[parsedQR[5]] = parsedQR[6];
397
					$scope.storedCredential.otp = qrInfo;
398
					$scope.$digest();
399
				};
400
401
402
				$scope.saveCredential = function () {
403
					//@TODO  validation
404
					delete $scope.storedCredential.password_repeat;
405
					if (!$scope.storedCredential.credential_id) {
406
						$scope.storedCredential.vault_id = $scope.active_vault.vault_id;
407
408
						CredentialService.createCredential($scope.storedCredential).then(function () {
409
							NotificationService.showNotification($translate.instant('credential.created'), 5000);
410
						});
411
					}
412
				};
413
414
			}
415
		]);
416
417
}());