Completed
Push — master ( e88c19...17669b )
by Rain
03:00
created

dev/View/Popup/ComposeOpenPgp.js   F

Complexity

Total Complexity 99
Complexity/F 2.83

Size

Lines of Code 474
Function Count 35

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 0
c 3
b 0
f 0
nc 1536
dl 0
loc 474
rs 3.12
wmc 99
mnd 5
bc 74
fnc 35
bpm 2.1142
cpm 2.8285
noi 0

How to fix   Complexity   

Complexity

Complex classes like dev/View/Popup/ComposeOpenPgp.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
import _ from '_';
3
import $ from '$';
4
import ko from 'ko';
5
import key from 'key';
6
7
import {
8
	inArray, createCommand,
9
	pString, log, isUnd, trim,
10
	defautOptionsAfterRender
11
} from 'Common/Utils';
12
13
import {Magics, KeyState} from 'Common/Enums';
14
import {i18n} from 'Common/Translator';
15
16
import PgpStore from 'Stores/User/Pgp';
17
18
import {EmailModel} from 'Model/Email';
19
20
import {view, ViewType} from 'Knoin/Knoin';
21
import {AbstractViewNext} from 'Knoin/AbstractViewNext';
22
23
@view({
24
	name: 'View/Popup/ComposeOpenPgp',
25
	type: ViewType.Popup,
26
	templateID: 'PopupsComposeOpenPgp'
27
})
28
class ComposeOpenPgpPopupView extends AbstractViewNext
29
{
30
	constructor() {
31
		super();
32
33
		this.publicKeysOptionsCaption = i18n('PGP_NOTIFICATIONS/ADD_A_PUBLICK_KEY');
34
		this.privateKeysOptionsCaption = i18n('PGP_NOTIFICATIONS/SELECT_A_PRIVATE_KEY');
35
36
		this.notification = ko.observable('');
37
38
		this.sign = ko.observable(false);
39
		this.encrypt = ko.observable(false);
40
41
		this.password = ko.observable('');
42
		this.password.focus = ko.observable(false);
43
		this.buttonFocus = ko.observable(false);
44
45
		this.text = ko.observable('');
46
		this.selectedPrivateKey = ko.observable(null);
47
		this.selectedPublicKey = ko.observable(null);
48
49
		this.signKey = ko.observable(null);
50
		this.encryptKeys = ko.observableArray([]);
51
52
		this.encryptKeysView = ko.computed(
53
			() => _.compact(_.map(this.encryptKeys(), (oKey) => (oKey ? oKey.key : null)))
54
		);
55
56
		this.privateKeysOptions = ko.computed(() => {
57
			const opts = _.map(PgpStore.openpgpkeysPrivate(), (oKey, iIndex) => {
58
				if (this.signKey() && this.signKey().key.id === oKey.id)
59
				{
60
					return null;
61
				}
62
				return _.map(oKey.users, (user) => ({
63
					'id': oKey.guid,
64
					'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + user,
65
					'key': oKey,
66
					'class': iIndex % 2 ? 'odd' : 'even'
67
				}));
68
			});
69
70
			return _.compact(_.flatten(opts, true));
71
		});
72
73
		this.publicKeysOptions = ko.computed(() => {
74
			const opts = _.map(PgpStore.openpgpkeysPublic(), (oKey, index) => {
75
				if (-1 < inArray(oKey, this.encryptKeysView()))
76
				{
77
					return null;
78
				}
79
				return _.map(oKey.users, (user) => ({
80
					'id': oKey.guid,
81
					'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + user,
82
					'key': oKey,
83
					'class': index % 2 ? 'odd' : 'even'
84
				}));
85
			});
86
			return _.compact(_.flatten(opts, true));
87
		});
88
89
		this.submitRequest = ko.observable(false);
90
91
		this.resultCallback = null;
92
93
		// commands
94
		this.doCommand = createCommand(() => {
95
96
			let
97
				result = true,
98
				privateKey = null,
99
				aPublicKeys = [];
100
101
			this.submitRequest(true);
102
103
			if (result && this.sign())
104
			{
105
				if (!this.signKey())
106
				{
107
					this.notification(i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND'));
108
					result = false;
109
				}
110
				else if (!this.signKey().key)
111
				{
112
					this.notification(i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND_FOR', {
113
						'EMAIL': this.signKey().email
114
					}));
115
116
					result = false;
117
				}
118
119
				if (result)
120
				{
121
					const privateKeys = this.signKey().key.getNativeKeys();
122
					privateKey = privateKeys[0] || null;
123
124
					try
125
					{
126
						if (privateKey)
127
						{
128
							privateKey.decrypt(pString(this.password()));
129
						}
130
					}
131
					catch (e)
132
					{
133
						privateKey = null;
134
					}
135
136
					if (!privateKey)
137
					{
138
						this.notification(i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND'));
139
						result = false;
140
					}
141
				}
142
			}
143
144
			if (result && this.encrypt())
145
			{
146
				if (0 === this.encryptKeys().length)
147
				{
148
					this.notification(i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND'));
149
					result = false;
150
				}
151
				else if (this.encryptKeys())
152
				{
153
					aPublicKeys = [];
154
155
					_.each(this.encryptKeys(), (oKey) => {
156
						if (oKey && oKey.key)
157
						{
158
							aPublicKeys = aPublicKeys.concat(_.compact(_.flatten(oKey.key.getNativeKeys())));
159
						}
160
						else if (oKey && oKey.email)
161
						{
162
							this.notification(i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', {
163
								'EMAIL': oKey.email
164
							}));
165
166
							result = false;
167
						}
168
					});
169
170
					if (result && (0 === aPublicKeys.length || this.encryptKeys().length !== aPublicKeys.length))
171
					{
172
						result = false;
173
					}
174
				}
175
			}
176
177
			if (result && this.resultCallback)
178
			{
179
				_.delay(() => {
180
181
					let pgpPromise = null;
182
183
					try
184
					{
185
						if (privateKey && 0 === aPublicKeys.length)
186
						{
187
							pgpPromise = PgpStore.openpgp.sign({
188
								data: this.text(),
189
								privateKeys: [privateKey]
190
							});
191
						}
192
						else if (privateKey && 0 < aPublicKeys.length)
193
						{
194
							pgpPromise = PgpStore.openpgp.encrypt({
195
								data: this.text(),
196
								publicKeys: aPublicKeys,
197
								privateKeys: [privateKey]
198
							});
199
						}
200
						else if (!privateKey && 0 < aPublicKeys.length)
201
						{
202
							pgpPromise = PgpStore.openpgp.encrypt({
203
								data: this.text(),
204
								publicKeys: aPublicKeys
205
							});
206
						}
207
					}
208
					catch (e)
209
					{
210
						log(e);
211
212
						this.notification(i18n('PGP_NOTIFICATIONS/PGP_ERROR', {
213
							'ERROR': '' + e
214
						}));
215
					}
216
217
					if (pgpPromise)
218
					{
219
						try
220
						{
221
							pgpPromise.then((mData) => {
222
								this.resultCallback(mData.data);
223
								this.cancelCommand();
224
							}).catch((e) => {
225
								this.notification(i18n('PGP_NOTIFICATIONS/PGP_ERROR', {
226
									'ERROR': '' + e
227
								}));
228
							});
229
						}
230
						catch (e)
231
						{
232
							this.notification(i18n('PGP_NOTIFICATIONS/PGP_ERROR', {
233
								'ERROR': '' + e
234
							}));
235
						}
236
					}
237
238
					this.submitRequest(false);
239
240
				}, Magics.Time20ms);
241
			}
242
			else
243
			{
244
				this.submitRequest(false);
245
			}
246
247
			return result;
248
249
		}, () => !this.submitRequest() && (this.sign() || this.encrypt()));
250
251
		this.selectCommand = createCommand(() => {
252
253
			const
254
				keyId = this.selectedPrivateKey(),
255
				option = keyId ? _.find(this.privateKeysOptions(), (oItem) => oItem && keyId === oItem.id) : null;
256
257
			if (option)
258
			{
259
				this.signKey({
260
					'empty': !option.key,
261
					'selected': ko.observable(!!option.key),
262
					'users': option.key.users,
263
					'hash': option.key.id.substr(-8).toUpperCase(),
264
					'key': option.key
265
				});
266
			}
267
		});
268
269
		this.addCommand = createCommand(() => {
270
271
			const
272
				keyId = this.selectedPublicKey(),
273
				keys = this.encryptKeys(),
274
				option = keyId ? _.find(this.publicKeysOptions(), (item) => (item && keyId === item.id)) : null;
275
276
			if (option)
277
			{
278
				keys.push({
279
					'empty': !option.key,
280
					'selected': ko.observable(!!option.key),
281
					'removable': ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== option.key.id),
282
					'users': option.key.users,
283
					'hash': option.key.id.substr(-8).toUpperCase(),
284
					'key': option.key
285
				});
286
287
				this.encryptKeys(keys);
288
			}
289
		});
290
291
		this.updateCommand = createCommand(() => {
292
			_.each(this.encryptKeys(), (oKey) => {
293
				oKey.removable(!this.sign() || !this.signKey() || this.signKey().key.id !== oKey.key.id);
294
			});
295
		});
296
297
		this.selectedPrivateKey.subscribe((value) => {
298
			if (value)
299
			{
300
				this.selectCommand();
301
				this.updateCommand();
302
			}
303
		});
304
305
		this.selectedPublicKey.subscribe((value) => {
306
			if (value)
307
			{
308
				this.addCommand();
309
			}
310
		});
311
312
		this.sDefaultKeyScope = KeyState.PopupComposeOpenPGP;
313
314
		this.defautOptionsAfterRender = defautOptionsAfterRender;
315
316
		this.addOptionClass = (domOption, item) => {
317
318
			this.defautOptionsAfterRender(domOption, item);
319
320
			if (item && !isUnd(item.class) && domOption)
321
			{
322
				$(domOption).addClass(item.class);
323
			}
324
		};
325
326
		this.deletePublickKey = _.bind(this.deletePublickKey, this);
327
	}
328
329
	deletePublickKey(publicKey) {
330
		this.encryptKeys.remove(publicKey);
331
	}
332
333
	clearPopup() {
334
		this.notification('');
335
336
		this.sign(false);
337
		this.encrypt(false);
338
339
		this.password('');
340
		this.password.focus(false);
341
		this.buttonFocus(false);
342
343
		this.signKey(null);
344
		this.encryptKeys([]);
345
		this.text('');
346
347
		this.resultCallback = null;
348
	}
349
350
	onBuild() {
351
		key('tab,shift+tab', KeyState.PopupComposeOpenPGP, () => {
352
			switch (true)
353
			{
354
				case this.password.focus():
355
					this.buttonFocus(true);
356
					break;
357
				case this.buttonFocus():
358
					this.password.focus(true);
359
					break;
360
				// no default
361
			}
362
			return false;
363
		});
364
	}
365
366
	onHideWithDelay() {
367
		this.clearPopup();
368
	}
369
370
	onShowWithDelay() {
371
		if (this.sign())
372
		{
373
			this.password.focus(true);
374
		}
375
		else
376
		{
377
			this.buttonFocus(true);
378
		}
379
	}
380
381
	onShow(fCallback, sText, identity, sTo, sCc, sBcc) {
382
383
		this.clearPopup();
384
385
		let
386
			rec = [],
387
			emailLine = '';
388
389
		const email = new EmailModel();
390
391
		this.resultCallback = fCallback;
392
393
		if ('' !== sTo)
394
		{
395
			rec.push(sTo);
396
		}
397
398
		if ('' !== sCc)
399
		{
400
			rec.push(sCc);
401
		}
402
403
		if ('' !== sBcc)
404
		{
405
			rec.push(sBcc);
406
		}
407
408
		rec = rec.join(', ').split(',');
409
		rec = _.compact(_.map(rec, (value) => {
410
			email.clear();
411
			email.mailsoParse(trim(value));
412
			return '' === email.email ? false : email.email;
413
		}));
414
415
		if (identity && identity.email())
416
		{
417
			emailLine = identity.email();
418
			rec.unshift(emailLine);
419
420
			const keys = PgpStore.findAllPrivateKeysByEmailNotNative(emailLine);
421
			if (keys && keys[0])
422
			{
423
				this.signKey({
424
					'users': keys[0].users || [emailLine],
425
					'hash': keys[0].id.substr(-8).toUpperCase(),
426
					'key': keys[0]
427
				});
428
			}
429
		}
430
431
		if (this.signKey())
432
		{
433
			this.sign(true);
434
		}
435
436
		if (rec && 0 < rec.length)
437
		{
438
			this.encryptKeys(_.uniq(_.compact(_.flatten(_.map(rec, (recEmail) => {
439
				const keys = PgpStore.findAllPublicKeysByEmailNotNative(recEmail);
440
				return keys ? _.map(keys, (oKey) => ({
441
					'empty': !oKey,
442
					'selected': ko.observable(!!oKey),
443
					'removable': ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== oKey.id),
444
					'users': oKey ? (oKey.users || [recEmail]) : [recEmail],
445
					'hash': oKey ? oKey.id.substr(-8).toUpperCase() : '',
446
					'key': oKey
447
				})) : [];
448
			}), true)), (encryptKey) => encryptKey.hash));
449
450
			if (0 < this.encryptKeys().length)
451
			{
452
				this.encrypt(true);
453
			}
454
		}
455
456
		this.text(sText);
457
	}
458
}
459
460
module.exports = ComposeOpenPgpPopupView;
461