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

js/app/controllers/edit_credential.js   F

Complexity

Total Complexity 63
Complexity/F 2.52

Size

Lines of Code 339
Function Count 25

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
dl 0
loc 339
rs 3.36
c 0
b 0
f 0
nc 1024
wmc 63
mnd 3
bc 58
fnc 25
bpm 2.32
cpm 2.52
noi 4

1 Function

Rating   Name   Duplication   Size   Complexity  
C angular.controller(ꞌCredentialEditCtrlꞌ) 0 325 8

How to fix   Complexity   

Complexity

Complex classes like js/app/controllers/edit_credential.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('CredentialEditCtrl', ['$scope', 'VaultService', 'CredentialService', 'SettingsService', '$location', '$routeParams', 'FileService', 'EncryptService', 'TagService', 'NotificationService', 'ShareService', '$translate',
36
			function ($scope, VaultService, CredentialService, SettingsService, $location, $routeParams, FileService, EncryptService, TagService, NotificationService, ShareService, $translate) {
37
				$scope.active_vault = VaultService.getActiveVault();
38
				if (!SettingsService.getSetting('defaultVault') || !SettingsService.getSetting('defaultVaultPass')) {
39
					if (!$scope.active_vault) {
40
						$location.path('/');
41
						return;
42
					}
43
				} else {
44
					if (SettingsService.getSetting('defaultVault') && SettingsService.getSetting('defaultVaultPass')) {
45
						var _vault = angular.copy(SettingsService.getSetting('defaultVault'));
46
						_vault.vaultKey = SettingsService.getSetting('defaultVaultPass');
47
						VaultService.setActiveVault(_vault);
48
						$scope.active_vault = _vault;
49
					}
50
				}
51
52
				VaultService.getVault($scope.active_vault).then(function (vault) {
53
					vault.vaultKey = VaultService.getActiveVault().vaultKey;
54
					delete vault.credentials;
55
					VaultService.setActiveVault(vault);
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
				$scope.currentTab = {
71
					title: $translate.instant('general'),
72
					url: 'views/partials/forms/edit_credential/basics.html',
73
					color: 'blue'
74
				};
75
				$scope.otpType = 'qrcode';
76
				$translate(['general', 'password', 'custom.fields','files','otp']).then(function (translations) {
77
					$scope.tabs = [{
78
						title: translations.general,
79
						url: 'views/partials/forms/edit_credential/basics.html',
80
						color: 'blue'
81
					}, {
82
						title: translations.password,
83
						url: 'views/partials/forms/edit_credential/password.html',
84
						color: 'green'
85
					}, {
86
						title:translations['custom.fields'],
87
						url: 'views/partials/forms/edit_credential/custom_fields.html',
88
						color: 'orange'
89
					}, {
90
						title: translations.files,
91
						url: 'views/partials/forms/edit_credential/files.html',
92
						color: 'yellow'
93
					}, {
94
						title: translations.otp,
95
						url: 'views/partials/forms/edit_credential/otp.html',
96
						color: 'purple'
97
					}];
98
					$scope.currentTab = $scope.tabs[0];
99
				});
100
101
				if ($scope.active_vault) {
102
					$scope.$parent.selectedVault = true;
103
				}
104
				var storedCredential = SettingsService.getSetting('edit_credential');
105
106
				if (!storedCredential) {
107
					CredentialService.getCredential($routeParams.credential_id).then(function (result) {
108
						$scope.storedCredential = CredentialService.decryptCredential(angular.copy(result));
109
					});
110
				} else {
111
					$scope.storedCredential = CredentialService.decryptCredential(angular.copy(storedCredential));
112
					$scope.storedCredential.password_repeat = angular.copy($scope.storedCredential.password);
113
					$scope.storedCredential.expire_time = $scope.storedCredential.expire_time * 1000;
114
				}
115
116
				$scope.getTags = function ($query) {
117
					return TagService.searchTag($query);
118
				};
119
120
121
				$scope.onClickTab = function (tab) {
122
					$scope.currentTab = tab;
123
				};
124
125
				$scope.isActiveTab = function (tab) {
126
					return tab.url === $scope.currentTab.url;
127
				};
128
129
				/**
130
				 * Below general edit functions
131
				 */
132
133
				$scope.pwGenerated = function (pass) {
134
					$scope.storedCredential.password_repeat = pass;
135
				};
136
137
138
				var _customField = {
139
					label: '',
140
					value: '',
141
					secret: false,
142
					field_type: 'text'
143
				};
144
				$scope.selected_field_type = 'text';
145
				$scope.new_custom_field = angular.copy(_customField);
146
147
				$scope.addCustomField = function () {
148
					var _field = angular.copy($scope.new_custom_field);
149
					if (!_field.label) {
150
						NotificationService.showNotification($translate.instant('error.no.label'), 3000);
151
					}
152
					if (!_field.value) {
153
						NotificationService.showNotification($translate.instant('error.no.value'), 3000);
154
					}
155
					if (!_field.label || !_field.value) {
156
						return;
157
					}
158
					$scope.selected_field_type = 'text';
159
					_field.secret = (_field.field_type === 'password');
160
					if(_field.field_type === 'file'){
161
						var key = false;
162
						var _file = $scope.new_custom_field.value;
163
						if (!$scope.storedCredential.hasOwnProperty('acl') && $scope.storedCredential.hasOwnProperty('shared_key')) {
164
165
							if ($scope.storedCredential.shared_key) {
166
								key = EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key));
167
							}
168
						}
169
170
						if ($scope.storedCredential.hasOwnProperty('acl')) {
171
							key = EncryptService.decryptString(angular.copy($scope.storedCredential.acl.shared_key));
172
						}
173
174
						FileService.uploadFile(_file, key).then(function (result) {
175
							delete result.file_data;
176
							result.filename = EncryptService.decryptString(result.filename, key);
177
							_field.value = result;
178
							$scope.storedCredential.custom_fields.push(_field);
179
							$scope.new_custom_field = angular.copy(_customField);
180
						});
181
					} else {
182
						$scope.storedCredential.custom_fields.push(_field);
183
						$scope.new_custom_field = angular.copy(_customField);
184
					}
185
186
				};
187
188
				$scope.addFileToCustomField = function (file) {
189
          $scope.new_custom_field.value = {
190
            filename: file.name,
191
            size: file.size,
192
            mimetype: file.type,
193
            data: file.data
194
          };
195
					$scope.$digest();
196
				};
197
198
				$scope.deleteCustomField = function (field) {
199
					if(field.hasOwnProperty('field_type')) {
200
						if (field.field_type === 'file') {
201
							FileService.deleteFile(field.value);
202
						}
203
					}
204
					var idx = $scope.storedCredential.custom_fields.indexOf(field);
205
					$scope.storedCredential.custom_fields.splice(idx, 1);
206
				};
207
208
				$scope.new_file = {
209
					name: '',
210
					data: null
211
				};
212
213
				$scope.deleteFile = function (file) {
214
					var idx = $scope.storedCredential.files.indexOf(file);
215
					FileService.deleteFile(file).then(function () {
216
						$scope.storedCredential.files.splice(idx, 1);
217
					});
218
				};
219
220
				$scope.fileLoaded = function (file) {
221
					var key;
222
					var _file = {
223
						filename: file.name,
224
						size: file.size,
225
						mimetype: file.type,
226
						data: file.data
227
					};
228
229
					if (!$scope.storedCredential.hasOwnProperty('acl') && $scope.storedCredential.hasOwnProperty('shared_key')) {
230
231
						if ($scope.storedCredential.shared_key) {
232
							key = EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key));
233
						}
234
					}
235
236
					if ($scope.storedCredential.hasOwnProperty('acl')) {
237
						key = EncryptService.decryptString(angular.copy($scope.storedCredential.acl.shared_key));
238
					}
239
240
241
					FileService.uploadFile(_file, key).then(function (result) {
242
						delete result.file_data;
243
						result.filename = EncryptService.decryptString(result.filename, key);
0 ignored issues
show
Bug introduced by
The variable key seems to not be initialized for all possible execution paths. Are you sure decryptString handles undefined variables?
Loading history...
244
						$scope.storedCredential.files.push(result);
245
					});
246
247
248
					$scope.$digest();
249
				};
250
251
				$scope.fileLoadError = function (error) {
252
					console.log($translate.instant('error.loading.file'), error);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
253
				};
254
255
				$scope.selected_file = '';
256
				$scope.fileprogress = [];
257
				$scope.fileSelectProgress = function (progress) {
258
					if (progress) {
259
						$scope.fileprogress = progress;
260
						$scope.$digest();
261
262
					}
263
				};
264
				$scope.renewIntervalValue = 0;
265
				$scope.renewIntervalModifier = '0';
266
267
				$scope.updateInterval = function (renewIntervalValue, renewIntervalModifier) {
268
					var value = parseInt(renewIntervalValue);
269
					var modifier = parseInt(renewIntervalModifier);
270
					if (value && modifier) {
271
						$scope.storedCredential.renew_interval = value * modifier;
272
					}
273
				};
274
275
				$scope.parseQR = function (QRCode) {
276
					if (!QRCode) {
277
						NotificationService.showNotification($translate.instant('invalid.qr'), 5000);
278
						return;
279
					}
280
					/** global: URL */
281
					var uri = new URL(QRCode.qrData);
282
					var type = (uri.href.indexOf('totp/') !== -1) ? 'totp' : 'hotp';
283
					var label = uri.pathname.replace('//'+ type +'/', '');
284
					$scope.storedCredential.otp = {
285
						type: type,
286
						label: decodeURIComponent(label),
287
						qr_uri: QRCode,
288
						issuer: uri.searchParams.get('issuer'),
289
						secret: uri.searchParams.get('secret')
290
					};
291
					$scope.$digest();
292
				};
293
				$scope.saving = false;
294
				$scope.saveCredential = function () {
295
          $scope.saving = true;
296
297
298
					if ($scope.new_custom_field.label && $scope.new_custom_field.value) {
299
						$scope.storedCredential.custom_fields.push(angular.copy($scope.new_custom_field));
300
					}
301
302
303
					if ($scope.storedCredential.password !== $scope.storedCredential.password_repeat){
304
            $scope.saving = false;
305
            NotificationService.showNotification($translate.instant('password.do.not.match'), 5000);
306
						return;
307
					}
308
309
					//@TODO  validation
310
					//@TODO When credential is expired and has renew interval set, calc new expire time.
311
					delete $scope.storedCredential.password_repeat;
312
					
313
					if (!$scope.storedCredential.credential_id) {
314
						$scope.storedCredential.vault_id = $scope.active_vault.vault_id;
315
						CredentialService.createCredential($scope.storedCredential).then(function () {
316
              $scope.saving = false;
317
							$location.path('/vault/' + $routeParams.vault_id);
318
							NotificationService.showNotification($translate.instant('credential.created'), 5000);
319
320
						});
321
					} else {
322
323
						var key, _credential;
324
						if (!$scope.storedCredential.hasOwnProperty('acl') && $scope.storedCredential.hasOwnProperty('shared_key')) {
325
326
							if ($scope.storedCredential.shared_key) {
327
								key = EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key));
328
							}
329
						}
330
331
						if ($scope.storedCredential.hasOwnProperty('acl')) {
332
							key = EncryptService.decryptString(angular.copy($scope.storedCredential.acl.shared_key));
333
						}
334
335
						if (key) {
336
							_credential = ShareService.encryptSharedCredential($scope.storedCredential, key);
337
						} else {
338
							_credential = angular.copy($scope.storedCredential);
339
						}
340
341
						delete _credential.shared_key;
342
						var _useKey = (key != null);
0 ignored issues
show
Bug introduced by
The variable key seems to not be initialized for all possible execution paths.
Loading history...
Coding Style introduced by
It is recommended to use !== to compare with null.

Generally, it is recommended to use strict comparison whenever possible and not to rely on the weaker type-juggling comparison operator.

Read more about comparison operations.

Loading history...
343
						var regex = /(<([^>]+)>)/ig;
344
						if(_credential.description && _credential.description !== "") {
345
							_credential.description = _credential.description.replace(regex, "");
346
						}
347
						CredentialService.updateCredential(_credential, _useKey).then(function () {
348
              $scope.saving = false;
349
							SettingsService.setSetting('edit_credential', null);
350
							$location.path('/vault/' + $routeParams.vault_id);
351
							NotificationService.showNotification($translate.instant('credential.updated'), 5000);
352
						});
353
					}
354
355
				};
356
357
				$scope.cancel = function () {
358
					$location.path('/vault/' + $routeParams.vault_id);
359
				};
360
			}]);
361
}());