]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/Parser.js
ui: eslint: enforce "dot-notation" rule
[pve-manager.git] / www / manager6 / Parser.js
CommitLineData
fcb64fe4
DM
1// Some configuration values are complex strings -
2// so we need parsers/generators for them.
3
8058410f
TL
4Ext.define('PVE.Parser', {
5 statics: {
fcb64fe4
DM
6
7 // this class only contains static functions
8
899c4f45
DC
9 printACME: function(value) {
10 if (Ext.isArray(value.domains)) {
11 value.domains = value.domains.join(';');
12 }
13 return PVE.Parser.printPropertyString(value);
14 },
15
488be4c2
DC
16 parseACME: function(value) {
17 if (!value) {
6ac64c3a 18 return {};
488be4c2
DC
19 }
20
21 var res = {};
08a61c7b 22 var error;
488be4c2
DC
23
24 Ext.Array.each(value.split(','), function(p) {
08a61c7b
FG
25 var kv = p.split('=', 2);
26 if (Ext.isDefined(kv[1])) {
27 res[kv[0]] = kv[1];
488be4c2 28 } else {
08a61c7b 29 error = 'Failed to parse key-value pair: '+p;
488be4c2
DC
30 return false;
31 }
32 });
33
08a61c7b
FG
34 if (error !== undefined) {
35 console.error(error);
488be4c2
DC
36 return;
37 }
38
08a61c7b
FG
39 if (res.domains !== undefined) {
40 res.domains = res.domains.split(/;/);
41 }
42
488be4c2
DC
43 return res;
44 },
45
4c1c0d5d 46 parseBoolean: function(value, default_value) {
84de645d 47 if (!Ext.isDefined(value)) {
4c1c0d5d 48 return default_value;
84de645d 49 }
4c1c0d5d 50 value = value.toLowerCase();
ec0bd652 51 return value === '1' ||
4c1c0d5d
EK
52 value === 'on' ||
53 value === 'yes' ||
54 value === 'true';
55 },
56
3d6189d3
SI
57 parsePropertyString: function(value, defaultKey) {
58 var res = {},
9bbdcdff 59 error;
3d6189d3 60
4a7248d4
TL
61 if (typeof value !== 'string' || value === '') {
62 return res;
63 }
64
3d6189d3
SI
65 Ext.Array.each(value.split(','), function(p) {
66 var kv = p.split('=', 2);
67 if (Ext.isDefined(kv[1])) {
68 res[kv[0]] = kv[1];
69 } else if (Ext.isDefined(defaultKey)) {
70 if (Ext.isDefined(res[defaultKey])) {
9bbdcdff
TL
71 error = 'defaultKey may be only defined once in propertyString';
72 return false; // break
3d6189d3
SI
73 }
74 res[defaultKey] = kv[0];
75 } else {
9bbdcdff 76 error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
3d6189d3
SI
77 return false; // break
78 }
79 });
80
9bbdcdff
TL
81 if (error !== undefined) {
82 console.error(error);
3d6189d3
SI
83 return;
84 }
85
86 return res;
87 },
88
89 printPropertyString: function(data, defaultKey) {
6de2baee
TL
90 var stringparts = [],
91 gotDefaultKeyVal = false,
92 defaultKeyVal;
3d6189d3
SI
93
94 Ext.Object.each(data, function(key, value) {
8007aaaf 95 if (defaultKey !== undefined && key === defaultKey) {
6de2baee
TL
96 gotDefaultKeyVal = true;
97 defaultKeyVal = value;
08e38f03 98 } else if (value !== '') {
8007aaaf 99 stringparts.push(key + '=' + value);
3d6189d3 100 }
3d6189d3
SI
101 });
102
6de2baee
TL
103 stringparts = stringparts.sort();
104 if (gotDefaultKeyVal) {
105 stringparts.unshift(defaultKeyVal);
106 }
107
3d6189d3
SI
108 return stringparts.join(',');
109 },
110
fcb64fe4
DM
111 parseQemuNetwork: function(key, value) {
112 if (!(key && value)) {
113 return;
114 }
115
116 var res = {};
117
118 var errors = false;
119 Ext.Array.each(value.split(','), function(p) {
120 if (!p || p.match(/^\s*$/)) {
121 return; // continue
122 }
123
124 var match_res;
125
126 if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
127 res.model = match_res[1].toLowerCase();
128 if (match_res[3]) {
129 res.macaddr = match_res[3];
130 }
131 } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
132 res.bridge = match_res[1];
133 } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
134 res.rate = match_res[1];
135 } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
63e62a6f 136 res.tag = match_res[1];
fcb64fe4 137 } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
63e62a6f 138 res.firewall = match_res[1];
fcb64fe4 139 } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
63e62a6f 140 res.disconnect = match_res[1];
fcb64fe4 141 } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
63e62a6f 142 res.queues = match_res[1];
a2ed0697
WB
143 } else if ((match_res = p.match(/^trunks=(\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*)$/)) !== null) {
144 res.trunks = match_res[1];
fcb64fe4
DM
145 } else {
146 errors = true;
147 return false; // break
148 }
149 });
150
151 if (errors || !res.model) {
152 return;
153 }
154
155 return res;
156 },
157
158 printQemuNetwork: function(net) {
fcb64fe4
DM
159 var netstr = net.model;
160 if (net.macaddr) {
161 netstr += "=" + net.macaddr;
162 }
163 if (net.bridge) {
164 netstr += ",bridge=" + net.bridge;
165 if (net.tag) {
166 netstr += ",tag=" + net.tag;
167 }
168 if (net.firewall) {
169 netstr += ",firewall=" + net.firewall;
170 }
171 }
172 if (net.rate) {
173 netstr += ",rate=" + net.rate;
174 }
175 if (net.queues) {
176 netstr += ",queues=" + net.queues;
177 }
178 if (net.disconnect) {
179 netstr += ",link_down=" + net.disconnect;
180 }
a2ed0697
WB
181 if (net.trunks) {
182 netstr += ",trunks=" + net.trunks;
183 }
fcb64fe4
DM
184 return netstr;
185 },
186
187 parseQemuDrive: function(key, value) {
188 if (!(key && value)) {
189 return;
190 }
191
192 var res = {};
193
194 var match_res = key.match(/^([a-z]+)(\d+)$/);
195 if (!match_res) {
196 return;
197 }
399ffa76 198 res.interface = match_res[1];
fcb64fe4
DM
199 res.index = match_res[2];
200
201 var errors = false;
202 Ext.Array.each(value.split(','), function(p) {
203 if (!p || p.match(/^\s*$/)) {
204 return; // continue
205 }
206 var match_res = p.match(/^([a-z_]+)=(\S+)$/);
207 if (!match_res) {
208 if (!p.match(/\=/)) {
209 res.file = p;
210 return; // continue
211 }
212 errors = true;
213 return false; // break
214 }
215 var k = match_res[1];
216 if (k === 'volume') {
217 k = 'file';
218 }
219
220 if (Ext.isDefined(res[k])) {
221 errors = true;
222 return false; // break
223 }
224
225 var v = match_res[2];
226
227 if (k === 'cache' && v === 'off') {
228 v = 'none';
229 }
230
231 res[k] = v;
232 });
233
234 if (errors || !res.file) {
235 return;
236 }
237
238 return res;
239 },
240
241 printQemuDrive: function(drive) {
fcb64fe4
DM
242 var drivestr = drive.file;
243
244 Ext.Object.each(drive, function(key, value) {
245 if (!Ext.isDefined(value) || key === 'file' ||
246 key === 'index' || key === 'interface') {
247 return; // continue
248 }
249 drivestr += ',' + key + '=' + value;
250 });
251
252 return drivestr;
253 },
254
01e02121
DC
255 parseIPConfig: function(key, value) {
256 if (!(key && value)) {
257 return;
258 }
259
260 var res = {};
261
262 var errors = false;
263 Ext.Array.each(value.split(','), function(p) {
264 if (!p || p.match(/^\s*$/)) {
265 return; // continue
266 }
267
268 var match_res;
269 if ((match_res = p.match(/^ip=(\S+)$/)) !== null) {
270 res.ip = match_res[1];
271 } else if ((match_res = p.match(/^gw=(\S+)$/)) !== null) {
272 res.gw = match_res[1];
273 } else if ((match_res = p.match(/^ip6=(\S+)$/)) !== null) {
274 res.ip6 = match_res[1];
275 } else if ((match_res = p.match(/^gw6=(\S+)$/)) !== null) {
276 res.gw6 = match_res[1];
277 } else {
278 errors = true;
279 return false; // break
280 }
281 });
282
283 if (errors) {
284 return;
285 }
286
287 return res;
288 },
289
290 printIPConfig: function(cfg) {
291 var c = "";
292 var str = "";
293 if (cfg.ip) {
294 str += "ip=" + cfg.ip;
295 c = ",";
296 }
297 if (cfg.gw) {
298 str += c + "gw=" + cfg.gw;
299 c = ",";
300 }
301 if (cfg.ip6) {
302 str += c + "ip6=" + cfg.ip6;
303 c = ",";
304 }
305 if (cfg.gw6) {
306 str += c + "gw6=" + cfg.gw6;
307 c = ",";
308 }
309 return str;
310 },
311
fcb64fe4
DM
312 parseOpenVZNetIf: function(value) {
313 if (!value) {
314 return;
315 }
316
317 var res = {};
318
319 var errors = false;
320 Ext.Array.each(value.split(';'), function(item) {
321 if (!item || item.match(/^\s*$/)) {
322 return; // continue
323 }
324
325 var data = {};
326 Ext.Array.each(item.split(','), function(p) {
327 if (!p || p.match(/^\s*$/)) {
328 return; // continue
329 }
330 var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
331 if (!match_res) {
332 errors = true;
333 return false; // break
334 }
8058410f 335 if (match_res[1] === 'bridge') {
fcb64fe4
DM
336 var bridgevlanf = match_res[2];
337 var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
338 if (!bridge_res) {
339 errors = true;
340 return false; // break
341 }
ec0bd652
DC
342 data.bridge = bridge_res[1];
343 data.tag = bridge_res[4];
ec0bd652 344 data.firewall = bridge_res[5] ? 1 : 0;
fcb64fe4
DM
345 } else {
346 data[match_res[1]] = match_res[2];
347 }
348 });
349
350 if (errors || !data.ifname) {
351 errors = true;
352 return false; // break
353 }
354
355 data.raw = item;
356
357 res[data.ifname] = data;
358 });
359
360 return errors ? undefined: res;
361 },
362
363 printOpenVZNetIf: function(netif) {
364 var netarray = [];
365
366 Ext.Object.each(netif, function(iface, data) {
367 var tmparray = [];
f6710aac 368 Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname', 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
fcb64fe4 369 var value = data[key];
8058410f
TL
370 if (key === 'bridge') {
371 if (data.tag) {
ec0bd652 372 value = value + 'v' + data.tag;
fcb64fe4 373 }
8058410f 374 if (data.firewall) {
fcb64fe4
DM
375 value = value + 'f';
376 }
377 }
378 if (value) {
379 tmparray.push(key + '=' + value);
380 }
fcb64fe4
DM
381 });
382 netarray.push(tmparray.join(','));
383 });
384
385 return netarray.join(';');
386 },
387
388 parseLxcNetwork: function(value) {
389 if (!value) {
390 return;
391 }
392
393 var data = {};
394 Ext.Array.each(value.split(','), function(p) {
395 if (!p || p.match(/^\s*$/)) {
396 return; // continue
397 }
95e77b22
TL
398 var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|tag|rate)=(\S+)$/);
399 if (match_res) {
400 data[match_res[1]] = match_res[2];
401 } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
805a7cb8 402 data.firewall = PVE.Parser.parseBoolean(match_res[1]);
95e77b22 403 } else {
fcb64fe4
DM
404 // todo: simply ignore errors ?
405 return; // continue
406 }
fcb64fe4
DM
407 });
408
409 return data;
410 },
411
412 printLxcNetwork: function(data) {
413 var tmparray = [];
414 Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
415 'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
416 var value = data[key];
417 if (value) {
418 tmparray.push(key + '=' + value);
419 }
420 });
519ca7fa 421
6efbc4cb 422 if (data.rate > 0) {
519ca7fa
DM
423 tmparray.push('rate=' + data.rate);
424 }
fcb64fe4
DM
425 return tmparray.join(',');
426 },
427
4c1c0d5d
EK
428 parseLxcMountPoint: function(value) {
429 if (!value) {
430 return;
431 }
432
433 var res = {};
434
435 var errors = false;
436 Ext.Array.each(value.split(','), function(p) {
437 if (!p || p.match(/^\s*$/)) {
438 return; // continue
439 }
a108c35a 440 var match_res = p.match(/^([a-z_]+)=(.+)$/);
4c1c0d5d
EK
441 if (!match_res) {
442 if (!p.match(/\=/)) {
443 res.file = p;
444 return; // continue
445 }
446 errors = true;
447 return false; // break
448 }
449 var k = match_res[1];
450 if (k === 'volume') {
451 k = 'file';
452 }
453
454 if (Ext.isDefined(res[k])) {
455 errors = true;
456 return false; // break
457 }
458
459 var v = match_res[2];
460
461 res[k] = v;
462 });
463
464 if (errors || !res.file) {
465 return;
466 }
467
283b450e 468 var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
4c1c0d5d
EK
469 if (m) {
470 res.storage = m[1];
471 res.type = 'volume';
472 } else if (res.file.match(/^\/dev\//)) {
473 res.type = 'device';
474 } else {
475 res.type = 'bind';
476 }
477
478 return res;
479 },
480
481 printLxcMountPoint: function(mp) {
482 var drivestr = mp.file;
483
484 Ext.Object.each(mp, function(key, value) {
485 if (!Ext.isDefined(value) || key === 'file' ||
486 key === 'type' || key === 'storage') {
487 return; // continue
488 }
489 drivestr += ',' + key + '=' + value;
490 });
491
492 return drivestr;
493 },
494
fcb64fe4
DM
495 parseStartup: function(value) {
496 if (value === undefined) {
497 return;
498 }
499
500 var res = {};
501
502 var errors = false;
503 Ext.Array.each(value.split(','), function(p) {
504 if (!p || p.match(/^\s*$/)) {
505 return; // continue
506 }
507
508 var match_res;
509
510 if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
511 res.order = match_res[2];
512 } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
513 res.up = match_res[1];
514 } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
515 res.down = match_res[1];
516 } else {
517 errors = true;
518 return false; // break
519 }
520 });
521
522 if (errors) {
523 return;
524 }
525
526 return res;
527 },
528
529 printStartup: function(startup) {
530 var arr = [];
531 if (startup.order !== undefined && startup.order !== '') {
532 arr.push('order=' + startup.order);
533 }
534 if (startup.up !== undefined && startup.up !== '') {
535 arr.push('up=' + startup.up);
536 }
537 if (startup.down !== undefined && startup.down !== '') {
538 arr.push('down=' + startup.down);
539 }
540
541 return arr.join(',');
542 },
543
544 parseQemuSmbios1: function(value) {
8058410f 545 var res = value.split(',').reduce(function(accumulator, currentValue) {
150ad74a
CE
546 var splitted = currentValue.split(new RegExp("=(.+)"));
547 accumulator[splitted[0]] = splitted[1];
548 return accumulator;
549 }, {});
550
551 if (PVE.Parser.parseBoolean(res.base64, false)) {
552 Ext.Object.each(res, function(key, value) {
553 if (key === 'uuid') { return; }
554 res[key] = Ext.util.Base64.decode(value);
555 });
556 }
fcb64fe4
DM
557
558 return res;
559 },
560
561 printQemuSmbios1: function(data) {
fcb64fe4 562 var datastr = '';
150ad74a 563 var base64 = false;
fcb64fe4 564 Ext.Object.each(data, function(key, value) {
84de645d 565 if (value === '') { return; }
150ad74a
CE
566 if (key === 'uuid') {
567 datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
568 } else {
569 // values should be base64 encoded from now on, mark config strings correspondingly
570 if (!base64) {
571 base64 = true;
572 datastr += (datastr !== '' ? ',' : '') + 'base64=1';
573 }
574 datastr += (datastr !== '' ? ',' : '') + key + '=' + Ext.util.Base64.encode(value);
575 }
fcb64fe4
DM
576 });
577
578 return datastr;
579 },
580
581 parseTfaConfig: function(value) {
582 var res = {};
583
584 Ext.Array.each(value.split(','), function(p) {
ec0bd652 585 var kva = p.split('=', 2);
fcb64fe4
DM
586 res[kva[0]] = kva[1];
587 });
588
589 return res;
4c1c0d5d
EK
590 },
591
1cdb49c1
WB
592 parseTfaType: function(value) {
593 var match;
594 if (!value || !value.length) {
595 return undefined;
596 } else if (value === 'x!oath') {
597 return 'totp';
d2021707 598 } else if (match = value.match(/^x!(.+)$/)) {
1cdb49c1
WB
599 return match[1];
600 } else {
601 return 1;
602 }
603 },
604
4c1c0d5d
EK
605 parseQemuCpu: function(value) {
606 if (!value) {
607 return {};
608 }
609
610 var res = {};
611
612 var errors = false;
613 Ext.Array.each(value.split(','), function(p) {
614 if (!p || p.match(/^\s*$/)) {
615 return; // continue
616 }
fcb64fe4 617
ec0bd652
DC
618 if (!p.match(/\=/)) {
619 if (Ext.isDefined(res.cpu)) {
4c1c0d5d
EK
620 errors = true;
621 return false; // break
622 }
623 res.cputype = p;
624 return; // continue
625 }
626
627 var match_res = p.match(/^([a-z_]+)=(\S+)$/);
628 if (!match_res) {
629 errors = true;
630 return false; // break
631 }
632
633 var k = match_res[1];
634 if (Ext.isDefined(res[k])) {
635 errors = true;
636 return false; // break
637 }
638
639 res[k] = match_res[2];
640 });
641
642 if (errors || !res.cputype) {
643 return;
644 }
645
646 return res;
647 },
648
649 printQemuCpu: function(cpu) {
650 var cpustr = cpu.cputype;
651 var optstr = '';
652
653 Ext.Object.each(cpu, function(key, value) {
654 if (!Ext.isDefined(value) || key === 'cputype') {
655 return; // continue
656 }
657 optstr += ',' + key + '=' + value;
658 });
659
660 if (!cpustr) {
84de645d 661 if (optstr) {
4c1c0d5d 662 return 'kvm64' + optstr;
84de645d 663 }
4c1c0d5d
EK
664 return;
665 }
666
667 return cpustr + optstr;
b1339314
WB
668 },
669
670 parseSSHKey: function(key) {
671 // |--- options can have quotes--| type key comment
672 var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/;
673 var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/;
674
675 var m = key.match(keyre);
676 if (!m) {
677 return null;
678 }
679 if (m.length < 3 || !m[2]) { // [2] is always either type or key
680 return null;
681 }
682 if (m[1] && m[1].match(typere)) {
683 return {
684 type: m[1],
685 key: m[2],
f6710aac 686 comment: m[3],
b1339314
WB
687 };
688 }
689 if (m[2].match(typere)) {
690 return {
691 options: m[1],
692 type: m[2],
693 key: m[3],
f6710aac 694 comment: m[4],
b1339314
WB
695 };
696 }
697 return null;
45708891
DC
698 },
699
700 parseACMEPluginData: function(data) {
701 let res = {};
702 let extradata = [];
703 data.split('\n').forEach((line) => {
704 // capture everything after the first = as value
705 let [key, value] = line.split(/=(.+)/);
706 if (value !== undefined) {
707 res[key] = value;
708 } else {
709 extradata.push(line);
710 }
711 });
712 return [res, extradata];
713 },
8058410f
TL
714}
715});