Passed
Push — develop ( 49e3f5...56ecd0 )
by Nikolay
04:35
created

ConsoleMenu.php$6 ➔ resetPassword()   B

Complexity

Conditions 6

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 36
rs 8.7217
c 0
b 0
f 0
cc 6

1 Method

Rating   Name   Duplication   Size   Complexity  
A ConsoleMenu.php$6 ➔ validate() 0 3 2
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright © 2017-2023 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
namespace MikoPBX\Core\System;
20
21
use MikoPBX\Common\Models\PbxSettings;
22
use MikoPBX\Common\Models\PbxSettingsConstants;
23
use MikoPBX\Common\Providers\TranslationProvider;
24
use MikoPBX\Core\Config\RegisterDIServices;
25
use Phalcon\Di;
26
use PhpSchool\CliMenu\CliMenu;
27
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
28
use PhpSchool\CliMenu\Action\GoBackAction;
29
use LucidFrame\Console\ConsoleTable;
30
use PhpSchool\CliMenu\MenuStyle;
31
use PhpSchool\CliMenu\Input\Text;
32
use PhpSchool\CliMenu\Input\InputIO;
33
use PhpSchool\CliMenu\Style\SelectableStyle;
34
use Exception;
35
use Closure;
36
use MikoPBX\Common\Models\Storage as StorageModel;
37
use MikoPBX\Core\System\{Configs\IptablesConf, Configs\NginxConf};
38
use MikoPBX\Service\Main;
39
40
class ConsoleMenu
41
{
42
43
    private bool $isLiveCd;
44
    private bool $isDocker;
45
46
    public function __construct()
47
    {
48
        $this->isLiveCd = file_exists('/offload/livecd');
49
        $this->isDocker = Util::isDocker();
50
    }
51
52
    /**
53
     * Function to get the banner text
54
     */
55
    private function getBannerText():string
56
    {
57
        $network = new Network();
58
59
        $liveCdText = '';
60
        if ($this->isLiveCd) {
61
            $liveCdText = Util::translate('PBX is running in Live or Recovery mode');
62
        }
63
64
        // Determine version and build time
65
        if (file_exists('/offload/version')) {
66
            $version_file = '/offload/version';
67
        } else {
68
            $version_file = '/etc/version';
69
        }
70
71
        $version        = trim(file_get_contents($version_file));
72
        $buildtime      = trim(file_get_contents('/etc/version.buildtime'));
73
74
        // Copyright information
75
        $copyright_info = 'MikoPBX is Copyright © 2017-2024. All rights reserved.' . PHP_EOL .
76
            "   \033[01;31m" . $liveCdText . "\033[39m";
77
78
79
        // Get enabled LAN interfaces
80
        $networks = $network->getEnabledLanInterfaces();
81
        $id_text  = 0;
82
83
        $countSpaceIP = 1;
84
        $ipTable = [];
85
        $externAddress = '';
86
        foreach ($networks as $if_data) {
87
            $if_data['interface_orign'] = $if_data['interface'];
88
            $if_data['interface']       = ($if_data['vlanid'] > 0) ? "vlan{$if_data['vlanid']}" : $if_data['interface'];
89
            $interface                  = $network->getInterface($if_data['interface']);
90
91
            // Determine the IP line
92
            if ($if_data['dhcp'] === '1') {
93
                $ip_line = 'IP via DHCP';
94
            } elseif ($if_data['vlanid'] > 0) {
95
                $ip_line = "VLAN via {$if_data['interface_orign']}";
96
                $countSpaceIP = Max($countSpaceIP -11, strlen($ip_line));
97
            } else {
98
                $ip_line = 'Static IP  ';
99
            }
100
101
            // Determine the IP info
102
            $ip_info = 'unassigned';
103
            if ( ! empty($interface['ipaddr'])) {
104
                $ip_info = "\033[01;33m{$interface['ipaddr']}\033[39m";
105
            }
106
107
            if ( ! empty($interface['mac']) && $id_text < 4) {
108
                $ipTable[] = ["{$if_data['interface']}:", $ip_line, $ip_info];
109
                $id_text++;
110
            }
111
112
            if($if_data['internet'] === '1'){
113
                if(!empty($if_data['exthostname'])){
114
                    $externAddress = $if_data['exthostname'];
115
                }elseif(!empty($if_data['extipaddr'])){
116
                    $externAddress = $if_data['extipaddr'];
117
                }
118
            }
119
120
        }
121
122
        // Check for system integrity
123
        $broken = static function () {
124
            if ( Util::isT2SdeLinux()) {
125
                $files = Main::checkForCorruptedFiles();
126
                if (count($files) !== 0) {
127
                    return "   \033[01;31m" . Util::translate('The integrity of the system is broken') . "\033[39m";
128
                }
129
            } elseif(php_uname('m') === 'x86_64' && Util::isDocker()) {
130
                $files  = Main::checkForCorruptedFiles();
131
                $result = '    Is Docker';
132
                if (count($files) !== 0) {
133
                    $result.= ": \033[01;31m" . Util::translate('The integrity of the system is broken') . "\033[39m";
134
                }
135
                return $result;
136
            } elseif(Util::isDocker()) {
137
                // ARM and other platform...
138
                return '    Is Docker';
139
            } else {
140
                return '    Is Debian';
141
            }
142
            return '';
143
        };
144
145
        // Generate the banner text
146
        $result =   "*** ".Util::translate('this_is')."\033[01;32mMikoPBX v.$version\033[39m".PHP_EOL.
147
            "   built on $buildtime for Generic (x64)".PHP_EOL.
148
            "   ".$copyright_info. PHP_EOL;
149
150
151
        // Create and populate the IP table
152
        $table = new ConsoleTable();
153
        foreach ($ipTable as $row){
154
            $table->addRow($row);
155
        }
156
157
        // Add external address if available
158
        if(!empty($externAddress)){
159
            $table->addRow(['external:', '', $externAddress]);
160
            $id_text++;
161
        }
162
163
        // Add empty rows if needed
164
        while ($id_text < 4){
165
            $table->addRow([' ', ' ']);
166
            $id_text++;
167
        }
168
169
        // Append the IP table to the result
170
        $result.= $table->hideBorder()->getTable().PHP_EOL;
171
172
        // Append system integrity information
173
        $result.= $broken();
174
        return $result;
175
    }
176
177
    /**
178
     * Returns the firewall status text
179
     * @return string
180
     */
181
    public function firewallWarning():string
182
    {
183
        // Check if firewall is disabled
184
        if (PbxSettings::getValueByKey(PbxSettingsConstants::PBX_FIREWALL_ENABLED) === '0') {
185
            return "\033[01;34m (" . Util::translate('Firewall disabled') . ") \033[39m";
186
        }
187
        return '';
188
    }
189
190
    /**
191
     * Returns the text of the storage status
192
     * @return string
193
     */
194
    public function storageWarning():string
195
    {
196
        // Check if storage disk is unmounted and not in livecd mode
197
        if ( !$this->isLiveCd && !Storage::isStorageDiskMounted()) {
198
            return "    \033[01;31m (" . Util::translate('Storage unmounted') . ") \033[39m";
199
        }
200
        return '';
201
    }
202
203
    /**
204
     * Building a network connection setup menu
205
     * @param CliMenuBuilder $menuBuilder
206
     * @return void
207
     */
208
    public function setupLan(CliMenuBuilder $menuBuilder):void
209
    {
210
        $menuBuilder->setTitle(Util::translate('Choose action'))
211
            ->addItem(
212
                '[1] ' . Util::translate('Configuring using DHCP'),
213
                function (CliMenu $menu) {
214
                    // Action for DHCP configuration
215
                    echo Util::translate('The LAN interface will now be configured via DHCP...');
216
                    $network      = new Network();
217
                    $data['dhcp'] = 1;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
218
                    $network->updateNetSettings($data);
219
                    $network->lanConfigure();
220
                    $nginxConf = new NginxConf();
221
                    $nginxConf->reStart();
222
                    sleep(1);
223
                    if ($parent = $menu->getParent()) {
224
                        $menu->closeThis();
225
                        $parent->open();
226
                    }
227
                }
228
            )
229
            ->addItem(
230
                '[2] ' . Util::translate('Manual setting'),
231
                function (CliMenu $menu) {
232
                    // Action for manual LAN setting
233
                    $network = new Network();
234
235
                    // Set style for input menu
236
                    $style = (new MenuStyle())
237
                        ->setBg('white')
238
                        ->setFg('black');
239
240
                    // Validate IP address input
241
                    $input_ip = new class (new InputIO($menu, $menu->getTerminal()), $style) extends Text {
242
                        public function validate(string $input): bool
243
                        {
244
                            return Verify::isIpAddress($input);
245
                        }
246
                    };
247
248
                    // Prompt for new LAN IP address
249
                    $elDialog = $input_ip
250
                        ->setPromptText(Util::translate('Enter the new LAN IP address: '))
251
                        ->setValidationFailedText(Util::translate('WARNING'))
252
                        ->ask();
253
                    $lanIp    = $elDialog->fetch();
254
255
                    // Prompt for subnet mask
256
                    $helloText = Util::translate('Subnet masks are to be entered as bit counts (as in CIDR notation).');
257
                    $input_bits = new class (new InputIO($menu, $menu->getTerminal()), $style) extends Text {
258
                        public function validate(string $input): bool
259
                        {
260
                            echo $input;
261
                            return (is_numeric($input) && ($input >= 1) && ($input <= 32));
262
                        }
263
                    };
264
                    $elDialog   = $input_bits
265
                        ->setPromptText($helloText)
266
                        ->setValidationFailedText('e.g. 32 = 255.255.255.255, 24 = 255.255.255.0')
267
                        ->ask();
268
                    $lanBits    = $elDialog->fetch();
269
270
                    // Prompt for LAN gateway IP address
271
                    $elDialog = $input_ip
272
                        ->setPromptText(Util::translate('Enter the LAN gateway IP address: '))
273
                        ->setValidationFailedText(Util::translate('WARNING'))
274
                        ->ask();
275
                    $gwIp     = $elDialog->fetch();
276
277
                    // Prompt for LAN DNS IP address
278
                    $elDialog = $input_ip
279
                        ->setPromptText(Util::translate('Enter the LAN DNS IP address: '))
280
                        ->setValidationFailedText(Util::translate('WARNING'))
281
                        ->ask();
282
                    $dnsip    = $elDialog->fetch();
283
284
                    // Update network settings and configure LAN
285
                    $data               = [];
286
                    $data['ipaddr']     = $lanIp;
287
                    $data['subnet']     = $lanBits;
288
                    $data['gateway']    = $gwIp;
289
                    $data['primarydns'] = $dnsip;
290
                    $data['dhcp']       = '0';
291
292
                    echo Util::translate('The LAN interface will now be configured ...');
293
                    $network->updateNetSettings($data);
294
                    $network->resolvConfGenerate();
295
                    $network->lanConfigure();
296
                    $nginxConf = new NginxConf();
297
                    $nginxConf->reStart();
298
299
                    sleep(1);
300
                    if ($parent = $menu->getParent()) {
301
                        $menu->closeThis();
302
                        $parent->open();
303
                    }
304
                }
305
            )
306
            ->setWidth(75)
307
            ->setBackgroundColour('black', 'black')
308
            ->enableAutoShortcuts()
309
            ->disableDefaultItems()
310
            ->addItem('[3] ' . Util::translate('Cancel'), new GoBackAction());
311
    }
312
313
    /**
314
     * Menu Language Settings
315
     * @param CliMenuBuilder $menuBuilder
316
     * @return void
317
     */
318
    public function setupLanguage(CliMenuBuilder $menuBuilder):void
319
    {
320
        $languages = [
321
            'en' => Util::translate('ex_English'),
322
            'ru' => Util::translate('ex_Russian'),
323
            'de' => Util::translate('ex_Deutsch'),
324
            'es' => Util::translate('ex_Spanish'),
325
            'fr' => Util::translate('ex_French'),
326
            'pt' => Util::translate('ex_Portuguese'),
327
            'uk' => Util::translate('ex_Ukrainian'),
328
            'it' => Util::translate('ex_Italian'),
329
            'da' => Util::translate('ex_Danish'),
330
            'nl' => Util::translate('ex_Dutch'),
331
            'pl' => Util::translate('ex_Polish'),
332
            'sv' => Util::translate('ex_Swedish'),
333
            'az' => Util::translate('ex_Azərbaycan'),
334
            'ro' => Util::translate('ex_Romanian'),
335
            // not able to show in console without additional shell fonts, maybe later we add it
336
            // 'th' => Util::translate('ex_Thai'),
337
            // 'el'      => Util::translate('ex_Greek'),
338
            // 'ka'      => Util::translate('ex_Georgian'),
339
            // 'cs'      => Util::translate('ex_Czech'),
340
            // 'tr'      => Util::translate('ex_Turkish'),
341
            // 'ja'      => Util::translate('ex_Japanese'),
342
            // 'vi'      => Util::translate('ex_Vietnamese'),
343
            // 'zh_Hans' => Util::translate('ex_Chinese'),
344
        ];
345
346
        $menuBuilder->setTitle('Choose shell language')
347
            ->setWidth(75)
348
            ->setBackgroundColour('black', 'black')
349
            ->enableAutoShortcuts()
350
            ->disableDefaultItems();
351
352
        // Apply language selection
353
        $index = 1;
354
        foreach ($languages as $language => $name) {
355
            $menuBuilder->addItem(
356
                "[$index] $name",
357
                function () use ($language) {
358
                    $mikoPBXConfig = new MikoPBXConfig();
359
                    $mikoPBXConfig->setGeneralSettings(PbxSettingsConstants::SSH_LANGUAGE, $language);
360
                    $di = Di::getDefault();
361
                    if($di){
362
                        $di->remove(TranslationProvider::SERVICE_NAME);
363
                    }
364
                    $this->start();
365
                }
366
            );
367
            $index++;
368
        }
369
        $menuBuilder->addItem("[$index] Cancel", new GoBackAction());
370
    }
371
372
    /**
373
     * Reboot and Shutdown Settings
374
     * @param CliMenuBuilder $b
375
     * @return void
376
     */
377
    public function setupReboot(CliMenuBuilder $b):void
378
    {
379
        $b->setTitle(Util::translate('Choose action'))
380
            ->enableAutoShortcuts()
381
            ->addItem(
382
                '[1] ' . Util::translate('Reboot'),
383
                function (CliMenu $menu) {
384
                    try {
385
                        $menu->close();
386
                    }catch (Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
387
                    }
388
                    file_put_contents('/tmp/rebooting', '1');
389
                    exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
390
                }
391
            )
392
            ->addItem(
393
                '[2] ' . Util::translate('Power off'),
394
                function (CliMenu $menu) {
395
                    try{
396
                        $menu->close();
397
                    }catch (Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
398
                    }
399
                    file_put_contents('/tmp/shutdown', '1');
400
                    exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
401
                }
402
            )
403
            ->setWidth(75)
404
            ->setForegroundColour('white', 'white')
405
            ->setBackgroundColour('black', 'black')
406
            ->disableDefaultItems()
407
            ->addItem('[3] ' . Util::translate('Cancel'), new GoBackAction());
408
    }
409
410
    /**
411
     * Ping Command Handler
412
     * @param CliMenu $menu
413
     * @return void
414
     */
415
    public function pingAction(CliMenu $menu):void
416
    {
417
        $style = new MenuStyle();
418
        $style->setBg('white')
419
            ->setFg('black');
420
        $input_ip = new class (new InputIO($menu, $menu->getTerminal()), $style) extends Text {
421
        };
422
        $elLanIp = $input_ip
423
            ->setPromptText(Util::translate('Enter a host name or IP address: (Press ESC to exit)'))
424
            ->setValidationFailedText(Util::translate('WARNING'))
425
            ->ask();
426
        $pingHost = $elLanIp->fetch();
427
        $pingPath    = Util::which('ping');
428
        $timeoutPath = Util::which('timeout');
429
        passthru("$timeoutPath 4 $pingPath -c3 " . escapeshellarg($pingHost));
430
        sleep(2);
431
        $this->start();
432
    }
433
434
    /**
435
     * Configuring firewall
436
     * @param CliMenu $menu
437
     * @return void
438
     */
439
    public function setupFirewall(CliMenu $menu):void
440
    {
441
        // Code for firewall optionn
442
        $mikoPBXConfig   = new MikoPBXConfig();
443
        $firewall_enable = $mikoPBXConfig->getGeneralSettings(PbxSettingsConstants::PBX_FIREWALL_ENABLED);
444
445
        if ($firewall_enable === '1') {
446
            $action = 'disable';
447
        } else {
448
            $action = 'enable';
449
        }
450
451
        $helloText = Util::translate("Do you want $action firewall now? (y/n): ");
452
        $style      = (new MenuStyle())
453
            ->setBg('white')
454
            ->setFg('black');
455
456
        $inputDialog = new class (new InputIO($menu, $menu->getTerminal()), $style) extends Text {
457
            public function validate(string $input): bool
458
            {
459
                return ($input === 'y' || $input === 'n');
460
            }
461
        };
462
        $elDialog = $inputDialog
463
            ->setPromptText($helloText)
464
            ->setValidationFailedText(Util::translate('WARNING') . ': y/n')
465
            ->ask();
466
        $result   = $elDialog->fetch();
467
468
        if ($result === 'y') {
469
            $enable = '0';
470
            if ('enable' === $action) {
471
                $enable = '1';
472
            }
473
            $mikoPBXConfig->setGeneralSettings(PbxSettingsConstants::PBX_FIREWALL_ENABLED, $enable);
474
            $mikoPBXConfig->setGeneralSettings(PbxSettingsConstants::PBX_FAIL2BAN_ENABLED, $enable);
475
            IptablesConf::reloadFirewall();
476
            echo "Firewall is {$action}d...";
477
        }
478
        $this->start();
479
    }
480
481
    /**
482
     * Setting up a disk for data storage
483
     * @param CliMenuBuilder $b
484
     * @return void
485
     */
486
    public function setupStorage(CliMenuBuilder $b):void
487
    {
488
        $b->setTitle(Util::translate('Choose action'))
489
            ->addItem(
490
                '[1] ' . Util::translate('Connect storage'),
491
                function (CliMenu $menu) {
492
                    // Code for connecting storage
493
                    $menu->close();
494
                    Storage::selectAndConfigureStorageDisk('0');
495
                    sleep(1);
496
                    exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
497
                }
498
            )
499
            ->addItem(
500
                '[2] ' . Util::translate('Check storage'),
501
                function (CliMenu $menu) {
502
                    // Code for checking storage
503
                    /** @var StorageModel $data */
504
                    $data = StorageModel::findFirst();
505
                    if (!$data) {
0 ignored issues
show
introduced by
$data is of type MikoPBX\Common\Models\Storage, thus it always evaluated to true.
Loading history...
506
                        echo "\n " . Util::translate('Valid disks not found...') . " \n";
507
                        return;
508
                    }
509
                    $style = (new MenuStyle())
510
                        ->setBg('white')
511
                        ->setFg('black');
512
                    $input_ip = new class (new InputIO($menu, $menu->getTerminal()), $style) extends Text {
513
                        public function validate(string $input): bool
514
                        {
515
                            return ($input === 'y' || $input === 'n');
516
                        }
517
                    };
518
                    $elDialog = $input_ip
519
                        ->setPromptText(Util::translate('All processes will be completed. Continue? (y/n):'))
520
                        ->setValidationFailedText(Util::translate('WARNING') . ': y/n')
521
                        ->ask();
522
                    $result   = $elDialog->fetch();
523
                    $menu->close();
524
                    if ($result !== 'y') {
525
                        sleep(2);
526
                        exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
527
                    }
528
                    $dev_name = file_exists("{$data->device}4") ? "{$data->device}4" : "{$data->device}1";
529
530
                    passthru('/sbin/freestorage');
531
                    passthru('e2fsck -f -p ' . escapeshellarg($dev_name), $return_var);
532
                    echo "check return $return_var";
533
                    sleep(2);
534
                    system('/sbin/pbx_reboot');
535
                }
536
            )
537
            ->addItem(
538
                '[3] ' . Util::translate('Resize storage'),
539
                function (CliMenu $menu) {
540
                    // Code for resizing storage
541
                    /** @var StorageModel $data */
542
                    $data = StorageModel::findFirst();
543
                    if ($data === null) {
544
                        echo "\n " . Util::translate('Valid disks not found...') . " \n";
545
                        return;
546
                    }
547
                    $style = (new MenuStyle())
548
                        ->setBg('white')
549
                        ->setFg('black');
550
551
                    $input_ip = new class (new InputIO($menu, $menu->getTerminal()), $style) extends Text {
552
                        public function validate(string $input): bool
553
                        {
554
                            return ($input === 'y' || $input === 'n');
555
                        }
556
                    };
557
                    $elDialog = $input_ip
558
                        ->setPromptText(Util::translate('All processes will be completed. Continue? (y/n):'))
559
                        ->setValidationFailedText(Util::translate('WARNING') . ': y/n')
560
                        ->ask();
561
                    $result   = $elDialog->fetch();
562
                    $menu->close();
563
                    if ($result !== 'y') {
564
                        sleep(2);
565
                        exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
566
                    }
567
568
                    passthru('/sbin/freestorage');
569
                    passthru('/etc/rc/resize_storage_part ' . escapeshellarg($data->device), $return_var);
0 ignored issues
show
Bug introduced by
It seems like $data->device can also be of type null; however, parameter $arg of escapeshellarg() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

569
                    passthru('/etc/rc/resize_storage_part ' . escapeshellarg(/** @scrutinizer ignore-type */ $data->device), $return_var);
Loading history...
570
                    echo "resize storage return $return_var";
571
                    sleep(2);
572
                    if ($return_var === 0) {
573
                        $pbx_rebootPath = Util::which('pbx_reboot');
574
                        Processes::mwExecBg($pbx_rebootPath);
575
                    }
576
                }
577
            )
578
            ->setWidth(75)
579
            ->enableAutoShortcuts()
580
            ->setForegroundColour('white', 'white')
581
            ->setBackgroundColour('black', 'black')
582
            ->disableDefaultItems()
583
            ->addItem('[4] ' . Util::translate('Cancel'), new GoBackAction());
584
    }
585
586
    /**
587
     * Reset web password
588
     * @param CliMenu $menu
589
     * @return void
590
     */
591
    public function resetPassword(CliMenu $menu):void
592
    {
593
        // Code for resetting admin password
594
        $style = (new MenuStyle())
595
            ->setBg('white')
596
            ->setFg('black');
597
598
        $input_ip = new class (new InputIO($menu, $menu->getTerminal()), $style) extends Text {
599
            public function validate(string $input): bool
600
            {
601
                return ($input === 'y' || $input === 'n');
602
            }
603
        };
604
        $elResetPassword = $input_ip
605
            ->setPromptText('Do you want reset password? (y/n):')
606
            ->setValidationFailedText(Util::translate('WARNING') . ': y/n')
607
            ->ask();
608
        $result   = $elResetPassword->fetch();
609
        if ($result !== 'y') {
610
            return;
611
        }
612
        try {
613
            $menu->close();
614
        }catch (Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
615
        }
616
        $mikoPBXConfig = new MikoPBXConfig();
617
        $res_login     = $mikoPBXConfig->resetGeneralSettings('WebAdminLogin');
618
        $res_password  = $mikoPBXConfig->resetGeneralSettings('WebAdminPassword');
619
620
        if ($res_login === true && $res_password === true) {
621
            echo Util::translate('Password successfully reset. New login: admin. New password: admin.');
622
        } else {
623
            echo Util::translate('Error resetting password.');
624
        }
625
        sleep(2);
626
        $this->start();
627
    }
628
629
    /**
630
     * System Installation or Recovery action
631
     * @param CliMenu $menu
632
     * @return void
633
     */
634
    public function installRecoveryAction(CliMenu $menu):void
635
    {
636
        echo "\e[?25h";
637
        try {
638
            $menu->close();
639
        }catch (Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
640
        }
641
        file_put_contents('/tmp/ejectcd', '');
642
        $installer = new PBXRecovery();
643
        $installer->run();
644
        exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
645
    }
646
647
    /**
648
     * System Installation
649
     * @param CliMenu $menu
650
     * @return void
651
     */
652
    public function installAction(CliMenu $menu):void
653
    {
654
        echo "\e[?25h";
655
        try {
656
            $menu->close();
657
        }catch (Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
658
        }
659
        file_put_contents('/tmp/ejectcd', '');
660
        $installer = new PBXInstaller();
661
        $installer->run();
662
        exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
663
    }
664
665
    /**
666
     * Console Opening Action
667
     * @param CliMenu $menu
668
     * @return void
669
     */
670
    public function consoleAction(CliMenu $menu):void {
671
        // Enable cursor
672
        echo "\e[?25h";
673
        try {
674
            $menu->close();
675
        }catch (Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
676
        }
677
        file_put_contents('/tmp/start_sh', '');
678
        exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
679
    }
680
681
    /**
682
     * Launching the console menu
683
     * @return void
684
     */
685
    public function start():void
686
    {
687
        RegisterDIServices::init();
688
689
        // Set Cyrillic font for display
690
        Util::setCyrillicFont();
691
        $separator      = '-';
692
        $titleWidth     = 75;
693
        $title          = str_repeat($separator, 2) . '  ' . Util::translate("PBX console setup") . '  ';
694
        $titleSeparator = mb_substr($title . str_repeat($separator, $titleWidth - mb_strlen($title)), 0, $titleWidth);
695
696
        $menu = new CliMenuBuilder();
697
        $menu->setTitle($this->getBannerText())
698
            ->setTitleSeparator($titleSeparator)
699
            ->enableAutoShortcuts()
700
            ->setPadding(0)
701
            ->setMarginAuto()
702
            ->setForegroundColour('white', 'white')
703
            ->setBackgroundColour('black', 'black')
704
            ->modifySelectableStyle(
705
                function (SelectableStyle $style) {
706
                    $style->setSelectedMarker(' ')
707
                        ->setUnselectedMarker(' ');
708
                }
709
            )
710
            ->setWidth($titleWidth)
711
            ->addItem(' ', static function (CliMenu $menu) {})
0 ignored issues
show
Unused Code introduced by
The parameter $menu is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

711
            ->addItem(' ', static function (/** @scrutinizer ignore-unused */ CliMenu $menu) {})

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
712
            ->addSubMenu('[1] Change language', Closure::fromCallable([$this, 'setupLanguage']));
713
714
        if($this->isDocker){
715
            $menu->addSubMenu('[3] ' . Util::translate('Reboot system'),Closure::fromCallable([$this, 'setupReboot']))
716
                ->addItem('[4] ' . Util::translate('Ping host'),Closure::fromCallable([$this, 'pingAction']))
717
                ->addItem('[5] ' . Util::translate('Firewall').$this->firewallWarning(), Closure::fromCallable([$this, 'setupFirewall']))
718
                ->addItem( '[7] ' . Util::translate('Reset admin password'), Closure::fromCallable([$this, 'resetPassword']) );
719
        }elseif ($this->isLiveCd){
720
            $menu->addSubMenu('[2] ' . Util::translate('Set up LAN IP address'), Closure::fromCallable([$this, 'setupLan']))
721
                ->addSubMenu('[3] ' . Util::translate('Reboot system'),Closure::fromCallable([$this, 'setupReboot']))
722
                ->addItem('[4] ' . Util::translate('Ping host'),Closure::fromCallable([$this, 'pingAction']));
723
            // Add items for live CD options
724
            if (file_exists('/conf.recover/conf')) {
725
                $menu->addItem('[8] ' . Util::translate('Install or recover'), Closure::fromCallable([$this, 'installRecoveryAction']));
726
            } else {
727
                $menu->addItem('[8] ' . Util::translate('Install on Hard Drive'), Closure::fromCallable([$this, 'installAction']));
728
            }
729
        }else{
730
            $menu->addSubMenu('[2] ' . Util::translate('Set up LAN IP address'), Closure::fromCallable([$this, 'setupLan']))
731
                ->addSubMenu('[3] ' . Util::translate('Reboot system'),Closure::fromCallable([$this, 'setupReboot']))
732
                ->addItem('[4] ' . Util::translate('Ping host'),Closure::fromCallable([$this, 'pingAction']))
733
                ->addItem('[5] ' . Util::translate('Firewall').$this->firewallWarning(), Closure::fromCallable([$this, 'setupFirewall']))
734
                ->addSubMenu('[6] ' . Util::translate('Storage').$this->storageWarning(), Closure::fromCallable([$this, 'setupStorage']))
735
                ->addItem( '[7] ' . Util::translate('Reset admin password'), Closure::fromCallable([$this, 'resetPassword']) );
736
        }
737
        $menu->addItem('[9] ' . Util::translate('Console'),Closure::fromCallable([$this, 'consoleAction']))
738
            ->disableDefaultItems();
739
740
        $menuBuilder = $menu->build();
741
        if ($menuBuilder->getTerminal()->isInteractive()) {
742
            echo(str_repeat(PHP_EOL, $menu->getTerminal()->getHeight()));
743
            try {
744
                $menuBuilder->open();
745
            } catch (\Throwable $e){
746
                Util::sysLogMsg('ConsoleMenu', $e->getMessage());
747
                sleep(1);
748
            }
749
        }
750
    }
751
}