PluginProbe
WPTerm / 1.3
WPTerm v1.3
1.3 trunk 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2
wpterm / wpterm.php

wpterm.php in WPTerm 1.3, at wpterm.php

1,102 lines 39.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: WPTerm
4 Plugin URI: https://nintechnet.com/bruandet/
5 Description: An xterm-like plugin to run non-interactive shell commands.
6 Author: Jerome Bruandet
7 Version: 1.3
8 Author URI: https://nintechnet.com/
9 Text Domain: wpterm
10 License: GPLv3 or later
11 Network: true
12 *
13 +=====================================================================+
14 | __ ______ _____ |
15 | \ \ / / _ \_ _|__ _ __ _ __ ___ |
16 | \ \ /\ / /| |_) || |/ _ \ '__| '_ ` _ \ |
17 | \ V V / | __/ | | __/ | | | | | | | |
18 | \_/\_/ |_| |_|\___|_| |_| |_| |_| |
19 | |
20 | (c) Jerome Bruandet ~ https://nintechnet.com/ |
21 +=====================================================================+
22 */
23 define('WPTERM_VERSION', '1.3');
24
25 /* ================================================================== */
26
27 if (! defined('ABSPATH') ) {
28 die('Forbidden');
29 }
30
31 /* ================================================================== */
32
33 /**
34 * Terminal AJAX action.
35 */
36 require __DIR__ .'/class-ajax.php';
37
38 /**
39 * Start a session if the user is an admin and
40 * WPTerm password protection is enabled.
41 */
42 function wpterm_session() {
43
44 if ( current_user_can('install_plugins') && defined('WPTERM_PASSWORD') && is_main_site() ) {
45
46 if (! headers_sent() ) {
47 if (! function_exists('session_status') ) {
48 if (! session_id() ) {
49 session_start();
50 }
51 } else {
52 if ( session_status() !== PHP_SESSION_ACTIVE ) {
53 session_start();
54 }
55 }
56 }
57 }
58 }
59
60 add_action('admin_init', 'wpterm_session');
61
62 /* ================================================================== */
63
64 function wpterm_activate() {
65
66 /**
67 * Make sure the user meets the requirements to run WPTerm.
68 */
69 if ( PATH_SEPARATOR == ';') {
70 wp_die(
71 esc_html__('WPTerm is not compatible with Microsoft Windows.', 'wpterm')
72 );
73 }
74
75 global $wp_version;
76 if ( version_compare( $wp_version, '5.0', '<') ) {
77 wp_die( sprintf(
78 esc_html__('WPTerm requires WordPress 5.0 or greater but your version is %s.', 'wpterm'),
79 esc_html( $wp_version )
80 ) );
81 }
82
83 if ( version_compare( PHP_VERSION, '7.0', '<') ) {
84 wp_die( sprintf(
85 esc_html__('WPTerm requires PHP 5.3 or greater but yourversion is %s.', 'wpterm'),
86 PHP_VERSION
87 ) );
88 }
89
90 }
91
92 register_activation_hook( __FILE__, 'wpterm_activate');
93
94 /* ================================================================== */
95
96 function wpterm_settings_link( $links ) {
97
98 /**
99 * Display the link in the "Plugins" page.
100 */
101 if (! current_user_can('install_plugins') || ! is_main_site() ) {
102 return $links;
103 }
104
105 $links[] = '<a href="'. get_admin_url( null, 'tools.php?page=wpterm') .
106 '">' . esc_html__('Terminal', 'wpterm') . '</a>';
107 return $links;
108 }
109
110 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'wpterm_settings_link');
111
112 /* ================================================================== */
113
114 function wpterm_js_insert() {
115
116 /**
117 * Insert our JS and CSS files in the footer for the admin...
118 */
119 if (! current_user_can('install_plugins') || ! is_main_site() ) {
120 return;
121 }
122 /**...when viewing WPTerm pages only.
123 */
124 if (! empty( $_GET['page'] ) && $_GET['page'] == 'wpterm') {
125
126 /**
127 * Load terminal JS code only if we are requesting the terminal tab.
128 */
129 if (! empty( $_GET['wptermtab'] ) && $_GET['wptermtab'] == 'terminal') {
130 wp_enqueue_script(
131 'wpterm_script2',
132 plugin_dir_url( __FILE__ ) .'wpterm-terminal.js',
133 array('jquery')
134 );
135
136 } else {
137 wp_enqueue_script(
138 'wpterm_script',
139 plugin_dir_url( __FILE__ ) .'wpterm.js',
140 array('jquery')
141 );
142 }
143
144 wp_enqueue_style(
145 'wpterm_style',
146 plugin_dir_url( __FILE__ ) . 'wpterm.css'
147 );
148 }
149 }
150
151 add_action('admin_footer', 'wpterm_js_insert');
152
153 /* ================================================================== */
154
155 function wpterm_admin_menu() {
156
157 /**
158 * Append WPTerm menu to the "Tools" menu.
159 */
160 if (! is_main_site() ) {
161 return;
162 }
163
164 global $menu_hook;
165
166 require_once( plugin_dir_path(__FILE__) . 'wpterm-help.php');
167
168 $menu_hook = add_submenu_page(
169 'tools.php',
170 'WPTerm',
171 'WPTerm',
172 /**
173 * In a multisite environment, only the superadmin will be able to access WPTerm.
174 */
175 'install_plugins',
176 'wpterm',
177 'wpterm_main_menu'
178 );
179 /**
180 * Load contextual help.
181 */
182 add_action('load-' . $menu_hook, 'wpterm_help');
183
184 }
185
186 add_action('admin_menu', 'wpterm_admin_menu');
187
188 /* ================================================================== */
189
190 function wpterm_main_menu() {
191
192 /**
193 * Show the selected tab and page.
194 */
195
196 // If the terminal is password protected,
197 // check if the user is authenticated:
198 if (! wpterm_is_allowed() ) {
199 return;
200 }
201
202 $tab = ['terminal', 'settings', 'about'];
203 // Make sure $_GET['wptermtab']'s value is okay,
204 // otherwise set it to its default 'terminal' value:
205 if (! isset( $_GET['wptermtab'] ) || ! in_array( $_GET['wptermtab'], $tab ) ) {
206 $_GET['wptermtab'] = 'terminal';
207 }
208 $wpterm_menu = "wpterm_menu_{$_GET['wptermtab']}";
209 $wpterm_menu();
210
211 }
212
213 /* ================================================================== */
214
215 function wpterm_menu_terminal() {
216
217 /**
218 * Display the terminal.
219 */
220
221 /**
222 * If DISALLOW_FILE_MODS is set, we don't allow access to the terminal.
223 */
224 if ( defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS ) {
225 wp_die(
226 esc_html__('Sorry, but DISALLOW_FILE_MODS is set, hence I refuse to run.', 'wpterminal')
227 );
228 }
229
230 // Fetch our options.
231 $wpterm_options = wpterm_menu_get_settings();
232
233 // Retrieve the current user info (name, home dir etc)
234 $userinfo = posix_getpwuid( posix_getuid() );
235
236 // Get current working directory:
237 if ( $wpterm_options['user-home'] == 'abspath') {
238 // WP current dir (a.k.a. ABSPATH):
239 $cwd = htmlspecialchars( rtrim( ABSPATH, '/') );
240 } else {
241 // Linux home dir:
242 $cwd = htmlspecialchars( rtrim( $userinfo['dir'], '/') );
243 }
244
245 $last_login = '';
246 $kernel_info = '';
247
248 // Get/set last login:
249 if (! empty( $wpterm_options['last_login'] ) ) {
250 list ( $time, $user, $ip ) = explode( ':', $wpterm_options['last_login'], 3 );
251 // Try to get hostname from its IP:
252 if (! $host = gethostbyaddr( $ip ) ) {
253 $host = $ip;
254 }
255 $date = date_i18n( 'D M d H:i:s Y', $time );
256 // We'll display this along the "welcome" message:
257 $last_login = sprintf(
258 __('Last login: %s, %s from %s', 'wpterm'),
259 esc_html( $user ),
260 $date,
261 esc_html( $host ) . '\n'
262 );
263 }
264
265 // Get the current user (system and WordPress) + his/her IP:
266 $current_user = wp_get_current_user();
267 $wpuser = esc_html( $current_user->user_login );
268 $user = esc_html( $userinfo['name'] );
269 $ip = esc_html( $_SERVER['REMOTE_ADDR'] );
270 $time = time();
271
272 // We refuse to run if we're root (unless stated otherwise):
273 if ( $user == 'root' && ! defined('THOU_SHALT_NOT_RUN_AS_ROOT') ) {
274 ?>
275 <div class="error notice is-dismissible"><p><?php
276 esc_html_e( 'Sorry, but I refuse to run as user root.', 'wpterm');
277 ?></p></div>
278 <div class="wrap"><h1>WPTerm</h1></div>
279 <?php
280 return;
281 }
282
283 // Display a one-time notice if we just installed WPTerm
284 // (this notice can be displayed again by entering `notice`
285 // at the terminal prompt):
286 $notice = esc_html__( "Thanks for using WPTerm!", "wpterm") . " ";
287 $notice.= esc_html__( "This is a one-time notice, please read it carefully:", "wpterm") . "<br />";
288 $notice.= "<ol>";
289 $notice.= "<li>" .
290 esc_html__( "Just like a terminal, WPTerm lets you do almost everything you want (e.g., changing file permissions, viewing network connections or current processes etc). That's great, but if you aren't familiar with Unix shell commands, you can also damage your blog.", "wpterm") . "<br />" .
291 esc_html__( "Therefore, each time you use WPTerm, please follow this rule of thumb: if you don't know what you're doing, don't do it!", "wpterm") . "</li>";
292 $notice.= "<li>" .
293 esc_html__( 'Take the time to password protect the access to WPTerm. Click on the contextual "Help" menu tab located in the upper right corner to get more details about how to enable this feature (or type `help` from WPTerm prompt).', "wpterm" ) . "</li>";
294 $notice.= "<li>" .
295 esc_html__( "Do not try to run interactive commands, you can't (most would not run anyway because the TERM environment variable is not set). If you run one by mistake and are stuck at the prompt, press CTRL-C.", "wpterm" ) . "</li>";
296 $notice.= "</ol>";
297 $notice.= esc_html__( "If you want to read this notice again, type `notice` from WPTerm prompt.", "wpterm" );
298
299 if ( empty( $wpterm_options['version'] ) ) {
300 $style = '';
301 } else {
302 $style = 'style="display:none" ';
303 }
304 // Display notice:
305 ?>
306 <div <?php echo $style; ?>id="wpterm-warning" class="error notice"><?php
307 echo $notice;
308 ?><p style="text-align:center">
309 <a onclick="jQuery('#wpterm-warning').slideUp();"><?php _e( "Click to hide", "wpterm" ) ?></a>
310 </p></div>
311 <?php
312
313 // Save options to the database:
314 $wpterm_options['last_login'] = "$time:$wpuser:$ip";
315 $wpterm_options['version'] = WPTERM_VERSION;
316 update_option('wpterm_options', $wpterm_options );
317
318 // Greeting + help command (in english only, no i18n):
319 $greeting['cowsay'] = ' _________________________________\n/ ';
320 $greeting['cowsay'].= " Welcome and thank you for using" . ' \x5c\n| ';
321 $greeting['cowsay'].= " WPTerm :)" . ' |\n\x5c ';
322 $greeting['cowsay'].= " If you need help, type 'help'. " . ' /\n';
323 $greeting['cowsay'].= ' ---------------------------------\n \x5c';
324 $greeting['cowsay'].= ' ^__^ v' . WPTERM_VERSION . '\n';
325 $greeting['cowsay'].= ' \x5c (oo)\x5c_______\n';
326 $greeting['cowsay'].= ' (__)\x5c )\x5c/\x5c\n';
327 $greeting['cowsay'].= ' ||----w |\n';
328 $greeting['cowsay'].= ' || ||\n';
329 $greeting['wpterm'] = ' __ ______ _____\n';
330 $greeting['wpterm'].= ' \x5c \x5c / / _ \x5c_ _|__ _ __ _ __ ___\n';
331 $greeting['wpterm'].= ' \x5c \x5c /\x5c / /| |_) || |/ _ \x5c \'__| \'_ ` _ \x5c\n';
332 $greeting['wpterm'].= ' \x5c V V / | __/ | | __/ | | | | | | |\n';
333 $greeting['wpterm'].= ' \x5c_/\x5c_/ |_| |_|\x5c___|_| |_| |_| |_| v' .
334 WPTERM_VERSION . '\n';
335 $greeting['wpterm'].= ' If you need help, type \'help\'.\n\n';
336 $greeting['tux'] = ' .--. [------------------------------]\n';
337 $greeting['tux'].= ' |o_o | WPTerm v' . WPTERM_VERSION . '\n';
338 $greeting['tux'].= ' |:_/ |\n';
339 $greeting['tux'].= ' // \x5c \x5c Welcome and thank you for\n';
340 $greeting['tux'].= ' (| | ) using WPTerm :)\n';
341 $greeting['tux'].= ' /\'\x5c_ _/`\x5c If you need help, type \'help\'.\n';
342 $greeting['tux'].= ' \x5c___)-(___/ [------------------------------]\n';
343
344 // Try to get the kernel info:
345 list( $uname, $null ) = @run_command('uname -a', $wpterm_options['php-function'] );
346 if (! empty( $uname ) ) {
347 $kernel_info = htmlspecialchars( trim( $uname ) ) . '\n';
348 } else {
349 // Maybe we are running on a shared hosting account that has
350 // PHP program execution functions disabled?
351 ?>
352 <div class="error notice is-dismissible"><p><?php
353 printf( esc_html__( "I was unable to run a shell command. Make sure that you are allowed to run %sPHP program execution functions%s, otherwise WPTerm will not function.", "wpterm" ), '<a href="http://php.net/manual/en/ref.exec.php">', '</a>' ) ?></p></div>
354 <?php
355 }
356
357 // Security nonce used for the terminal (AJAX):
358 $wpterm_ajax_nonce = wp_create_nonce('wpterm_menu_terminal');
359
360 ?>
361 <style>
362 .terminal-user {
363 <?php
364 if (! empty( $wpterm_options['bold-font'] ) ) {
365 echo "font-weight:bold;\n";
366 }
367 ?>
368 background-color:<?php echo $wpterm_options['background-color-val'] ?>;
369 color:<?php echo $wpterm_options['font-color-val'] ?>;
370 font-family:<?php echo $wpterm_options['font-family'] ?>;
371 font-size:<?php echo $wpterm_options['font-size'] ?>px;
372 }
373 </style>
374 <script>
375 var wpterm_ajax_nonce = "<?php echo $wpterm_ajax_nonce ?>";
376 var prompt = "<?php echo "$user:$cwd" ?> $ ";
377 var user = "<?php echo $user ?>";
378 var cwd = "<?php echo $cwd ?>";
379 var abspath = "<?php echo htmlspecialchars( rtrim( ABSPATH, '/' ) ) ?>";
380 var exec = "<?php echo htmlspecialchars( $wpterm_options['php-function'] ) ?>";
381 var last_login = "<?php echo $kernel_info . $greeting[$wpterm_options['welcome-message']] . $last_login ?>";
382 var in_progress = "<?php echo esc_js( __( 'Operations in progress, please wait.', 'wpterm' ) ) .'\n'.
383 esc_js( __( 'If you want to cancel, press CTRL+C.', 'wpterm' ) ) ?>";
384 var op_cancelled = "<?php echo esc_js( __( 'operation cancelled', 'wpterm' ) ) ?>";
385 var iptables = "<?php echo esc_js( __( 'if you want a good firewall, install NinjaFirewall (WP Edition):', 'wp-shell' ) );
386 echo '\n https://wordpress.org/plugins/ninjafirewall/'; ?>";
387 var emul_tab = <?php echo (int) $wpterm_options['tab-completion'] ?>;
388 var emul_tab_msg = "<?php echo esc_js( __( 'Tab completion is disabled. You can enable it from the Settings page', 'wpterm' ) ) ?>";
389 var logout_url = "<?php echo esc_url( wp_logout_url() ); ?>";
390 var logout_msg = "<?php echo esc_js( __( 'Log out of WordPress?', 'wpterm' ) ) ?>";
391 var unknown_err = "<?php echo esc_js( __( 'WPTerm: error, no data received', 'wpterm' ) ) ?>";
392 var version = "<?php echo '\nWPTerm v' . WPTERM_VERSION ?>";
393 var scrollback = <?php echo (int) $wpterm_options['scrollback'] ?>;
394 var visual_bell = <?php echo (int) $wpterm_options['visual-bell'] ?>;
395 var audible_bell = <?php echo (int) $wpterm_options['audible-bell'] ?>;
396 var wrap_on = "<?php echo esc_js( __( "Line wrapping is enabled", "wpterm" ) ) ?>";
397 var wrap_off = "<?php echo esc_js( __( "Line wrapping is disabled", "wpterm" ) ) ?>";
398 </script>
399 <?php
400
401 // If the blog is setup to use a right-to-left language and the user runs IE/Edge browser
402 // we inform them that it is not compatible:
403 if ( is_rtl() && preg_match( '/MSIE|Trident|Edge/', $_SERVER['HTTP_USER_AGENT'] ) ) {
404 echo '<div class="notice-warning notice is-dismissible"><p>' .
405 esc_html__('Because your current locale is RTL (Right To Left script), the terminal will not work well with your IE/Edge browser. Consider using another browser that is compatible (Firefox, Chrome, Opera or Safari).', 'wpterm') .'</p></div>';
406 }
407
408 ?>
409 <div class="wrap">
410 <h1>WPTerm</h1>
411
412 <h2 class="nav-tab-wrapper wp-clearfix">
413 <a href="?page=wpterm&wptermtab=terminal" class="nav-tab nav-tab-active"><?php esc_html_e( 'Terminal', 'wpterm' ) ?></a>
414 <a href="?page=wpterm&wptermtab=settings" class="nav-tab"><?php esc_html_e( 'Settings', 'wpterm' ) ?></a>
415 <a href="?page=wpterm&wptermtab=about" class="nav-tab"><?php esc_html_e( 'About', 'wpterm' ) ?></a>
416 </h2>
417
418 <table style="width:100%;padding-top:4px">
419 <tr>
420 <td width="100%">
421 <textarea dir="auto" ondragstart="return false;" id="terminal" class="terminal terminal-user" onMouseOver="this.focus();" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" wrap="soft"></textarea>
422 </td>
423 </tr>
424 </table>
425
426 <div>
427 <p class="alignleft">
428 <img id="progress_gif" style="display:none" src="<?php echo plugins_url() ?>/wpterm/images/wpterm-progress.gif" width="51" height="13" title="<?php esc_attr_e('Operations in progress, please wait.', 'wpterm') ?>">
429 </p>
430 <p class="alignright">
431 <img onClick="line_wrapping(this);" onTouchStart="line_wrapping(this);" id="wrap-line" border="0" src="<?php echo plugins_url() ?>/wpterm/images/wpterm-wrap.png" width="20" height="20" title="<?php esc_attr_e( "Line wrapping is enabled", "wpterm" ) ?>" style="cursor:pointer">
432 &nbsp;&nbsp;&nbsp;
433 <img onClick="font_size(-1);" onTouchStart="font_size(-1);" border="0" src="<?php echo plugins_url() ?>/wpterm/images/wpterm-fontminus.png" width="21" height="20" title="<?php esc_attr_e( "Decrease font size", "wpterm" ) ?>" style="cursor:pointer">
434 &nbsp;&nbsp;&nbsp;
435 <img onClick="font_size(1);" onTouchStart="font_size(1);" border="0" src="<?php echo plugins_url() ?>/wpterm/images/wpterm-fontplus.png" width="21" height="20" title="<?php esc_attr_e( "Increase font size", "wpterm" ) ?>" style="cursor:pointer">
436 </p>
437 </div>
438
439 </div>
440 <?php
441 }
442
443 /* ================================================================== */
444
445 function wpterm_menu_settings() {
446
447 // Display the settings page:
448
449 // Save settings?
450 if ( isset( $_POST['save-settings'] ) ) {
451 // Verify security nonce:
452 if ( empty( $_POST['wptermnonce'] ) ||
453 ! wp_verify_nonce( $_POST['wptermnonce'], 'save_settings' ) ) {
454
455 wp_nonce_ays( 'save_settings' );
456 }
457 wpterm_menu_save_settings();
458 echo '<div class="updated notice is-dismissible"><p>' .
459 esc_html__('Your changes have been saved.', 'wpterm') .'</p></div>';
460 }
461
462 // Fetch, verify and sanitize the current settings:
463 $wpterm_options = wpterm_menu_get_settings();
464
465 ?>
466 <div class="wrap">
467 <h1>WPTerm</h1>
468
469 <h2 class="nav-tab-wrapper wp-clearfix">
470 <a href="?page=wpterm&wptermtab=terminal" class="nav-tab">
471 <?php esc_html_e( 'Terminal', 'wpterm' ) ?></a>
472 <a href="?page=wpterm&wptermtab=settings" class="nav-tab nav-tab-active">
473 <?php esc_html_e( 'Settings', 'wpterm' ) ?></a>
474 <a href="?page=wpterm&wptermtab=about" class="nav-tab">
475 <?php esc_html_e( 'About', 'wpterm' ) ?></a>
476 </h2>
477
478 <br />
479
480 <form method="post">
481
482 <h3><?php esc_html_e('Fonts and Colors', 'wpterm') ?></h3>
483
484 <table class="form-table">
485
486 <tr>
487 <th scope="row"><?php esc_html_e('Font color', 'wpterm') ?></th>
488 <td>
489 <input type="text" name="font-color" value="<?php echo esc_attr( $wpterm_options['font-color'] ) ?>" oninput="wpterm_preview('color', 'color', this.value)" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
490 <p>
491 <span class="description">
492 <?php printf ( esc_html__( 'Hexadecimal value (e.g., %s) or CSS color name (e.g., <code>red</code>).', 'wpterm' ), '<code>ffffff</code>' ) ?>
493 </span>
494 </p>
495 </td>
496 </tr>
497
498 <tr>
499 <th scope="row"><?php esc_html_e('Background color', 'wpterm') ?></th>
500 <td>
501 <input type="text" name="background-color" value="<?php echo esc_attr( $wpterm_options['background-color'] ) ?>" oninput="wpterm_preview('color', 'background', this.value)" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
502 <p>
503 <span class="description">
504 <?php printf ( esc_html__( 'Hexadecimal value (e.g., %s) or CSS color name (e.g., <code>red</code>).', 'wpterm' ), '<code>3465A4</code>' ) ?>
505 </span>
506 </p>
507 </td>
508 </tr>
509
510 <tr>
511 <th scope="row"><?php esc_html_e('Font size', 'wpterm') ?></th>
512 <td>
513 <input type="number" class="small-text" name="font-size" step="1" min="9" max="20" value="<?php echo (int) $wpterm_options['font-size'] ?>" oninput="wpterm_preview('fontsize', 0, this.value);" /> px
514 &nbsp;&nbsp;&nbsp;&nbsp;
515 <label><input type="checkbox" id="bold_font" onchange="wpterm_preview('fontweight', 'bold_font', this.value);" name="bold-font"<?php checked( $wpterm_options['bold-font'], 1 ) ?> /><?php esc_html_e( 'Bold fonts', 'wpterm' ) ?></label>
516 <p>
517 <span class="description">
518 <?php esc_html_e('From 9 to 20px.', 'wpterm') ?>
519 </span>
520 </p>
521 </td>
522 </tr>
523
524 <tr>
525 <th scope="row"><?php esc_html_e('Font family', 'wpterm') ?></th>
526 <td>
527 <input type="text" class="regular-text" name="font-family" value="<?php echo esc_attr( $wpterm_options['font-family'] ) ?>" oninput="wpterm_preview('fontface', 0, this.value)" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
528 <p>
529 <span class="description">
530 <?php esc_html_e( 'Multiple values must be comma separated (e.g., <code>Consolas,Monaco,monospace</code>)', 'wpterm' ) ?>
531 </span>
532 </p>
533 </td>
534 </tr>
535
536 <?php
537 if (! empty( $wpterm_options['bold-font'] ) ) {
538 $font_weight = 'font-weight:bold;';
539 } else {
540 $font_weight = 'font-weight:normal;';
541 }
542 ?>
543 <tr>
544 <th scope="row"><?php esc_html_e('Test', 'wpterm') ?></th>
545 <td>
546 <textarea autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" id="textarea-test" rows="3" style="width:20em;resize:both;padding:10px;color:<?php echo esc_attr( $wpterm_options['font-color-val'] ) ?>;background-color:<?php echo esc_attr( $wpterm_options['background-color-val'] ) ?>;font-size:<?php echo (int) $wpterm_options['font-size'] ?>px;font-family:<?php echo esc_attr( $wpterm_options['font-family'] ) ?>;<?php echo $font_weight ?>"><?php echo "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789" ?></textarea>
547 </td>
548 </tr>
549
550 </table>
551
552 <br />
553
554 <h3><?php esc_html_e('Terminal', 'wpterm') ?></h3>
555
556 <table class="form-table">
557
558 <tr>
559 <th scope="row"><?php esc_html_e('Use the following PHP function for command execution', 'wpterm') ?></th>
560 <td>
561 <p>
562 <label>
563 <input type="radio" name="php-function" value="exec"<?php checked( $wpterm_options['php-function'], 'exec' ) ?> /><code>exec</code>
564 </label>
565 </p>
566 <p>
567 <label>
568 <input type="radio" name="php-function" value="shell_exec"<?php checked( $wpterm_options['php-function'], 'shell_exec' ) ?> /><code>shell_exec</code>
569 </label>
570 </p>
571 <p>
572 <label>
573 <input type="radio" name="php-function" value="system"<?php checked( $wpterm_options['php-function'], 'system' ) ?> /><code>system</code>
574 </label>
575 </p>
576 <p>
577 <label>
578 <input type="radio" name="php-function" value="passthru"<?php checked( $wpterm_options['php-function'], 'passthru' ) ?> /><code>passthru</code>
579 </label>
580 </p>
581 <p>
582 <label>
583 <input type="radio" name="php-function" value="popen"<?php checked( $wpterm_options['php-function'], 'popen' ) ?> /><code>popen</code>
584 </label>
585 </p>
586 </td>
587 </tr>
588
589
590 <tr>
591 <th scope="row"><?php esc_html_e('Emulate pseudo-Tab completion?', 'wpterm') ?></th>
592 <td>
593 <p>
594 <label>
595 <input type="radio" name="tab-completion" value="1"<?php checked( $wpterm_options['tab-completion'], 1 ) ?> /><?php _e( 'Yes', 'wpterm' ) ?>
596 </label>
597 </p>
598 <p>
599 <label>
600 <input type="radio" name="tab-completion" value="0"<?php checked( $wpterm_options['tab-completion'], 0 ) ?> /><?php _e( 'No', 'wpterm' ) ?>
601 </label>
602 </p>
603 </td>
604 </tr>
605
606 <?php
607 // Retrieve user info:
608 $userinfo = posix_getpwuid( posix_getuid() );
609 ?>
610 <tr>
611 <th scope="row"><?php esc_html_e('Default working directory', 'wpterm') ?></th>
612 <td>
613 <p>
614 <label>
615 <input type="radio" name="user-home" value="abspath"<?php checked( $wpterm_options['user-home'], 'abspath' ) ?> /><?php printf( esc_html__( 'WordPress ABSPATH (%s)', 'wpterm' ), '<code>'. esc_html( ABSPATH ) .'</code>' ) ?>
616 </label>
617 </p>
618 <span class="description"><?php printf( esc_html__( "Tip: to go back to that directory, type %s.", "wpterm" ), '<code>cd $ABSPATH</code>' ) ?></span>
619
620 <p>
621 <label>
622 <input type="radio" name="user-home" value="homedir"<?php checked( $wpterm_options['user-home'], 'homedir' ) ?> /><?php printf( esc_html__( 'User home directory (%s)', 'wpterm' ), '<code>'. esc_html( $userinfo['dir'] ) .'</code>' ) ?>
623 </label>
624 </p>
625 </td>
626 </tr>
627
628 <tr>
629 <th scope="row"><?php esc_html_e('Scrollback', 'wpterm') ?></th>
630 <td>
631 <label><?php printf( esc_html__( "Limit scrollback to %s lines", "wpterm" ) , '<input type="number" class="small-text" name="scrollback" step="1" min="1" max="3000" value="' . (int) $wpterm_options['scrollback'] .'" />' ) ?></label>
632 <br>
633 <span class="description">
634 <?php esc_html_e('Max 3,000 lines.', 'wpterm') ?>
635 </span>
636 </td>
637 </tr>
638
639 <tr>
640 <th scope="row"><?php esc_html_e('Welcome message', 'wpterm') ?></th>
641 <td>
642 <p>
643 <label>
644 <input type="radio" name="welcome-message" value="wpterm"<?php checked( $wpterm_options['welcome-message'], 'wpterm' ) ?> />WPTerm
645 </label>
646 </p>
647 <p>
648 <label>
649 <input type="radio" name="welcome-message" value="cowsay"<?php checked( $wpterm_options['welcome-message'], 'cowsay' ) ?> />Cowsay
650 </label>
651 </p>
652 <p>
653 <label>
654 <input type="radio" name="welcome-message" value="tux"<?php checked( $wpterm_options['welcome-message'], 'tux' ) ?> />Tux
655 </label>
656 </p>
657 </td>
658 </tr>
659
660 <?php
661 // IE up to 11 isn't compatible with our 'Audible bell':
662 if ( isset( $_SERVER["HTTP_USER_AGENT"] ) && strpos( $_SERVER["HTTP_USER_AGENT"], '; rv:11' ) !== false ) {
663 $disabled = ' disabled="disabled"';
664 } else {
665 $disabled = '';
666 }
667 ?>
668 <tr>
669 <th scope="row"><?php esc_html_e('Terminal bell', 'wpterm') ?></th>
670 <td>
671 <p><label id="visual-bell">
672 <input type="checkbox" onchange="bell_preview(this, 'visual');" name="visual-bell"<?php checked( $wpterm_options['visual-bell'], 1 ) ?> /><?php esc_html_e( 'Visual bell', 'wpterm' ) ?>
673 </label></p>
674 <p><label>
675 <input type="checkbox"<?php echo $disabled ?> onchange="bell_preview(this, 'beep');" name="audible-bell"<?php checked( $wpterm_options['audible-bell'], 1 ) ?> /><?php esc_html_e( 'Audible bell', 'wpterm' ) ?>
676 </label></p>
677 </td>
678 </tr>
679
680 </table>
681
682 <br />
683 <br />
684
685 <input class="button-primary" type="submit" name="save-settings" value="<?php esc_html_e('Save Settings', 'wpterm') ?>" />
686
687 <?php wp_nonce_field('save_settings', 'wptermnonce', 0); ?>
688
689 </form>
690
691 </div>
692
693 <?php
694
695 }
696
697 /* ================================================================== */
698
699 function wpterm_menu_get_settings() {
700
701 // Retrieve the current settings:
702
703 $wpterm_options = get_option( 'wpterm_options' );
704
705 // First run, not options available yet ($wpterm_options is boolean).
706 if (! is_array( $wpterm_options ) ) {
707 $wpterm_options = [];
708 }
709
710 if ( empty( $wpterm_options['font-color'] ) ) {
711 $wpterm_options['font-color'] = 'ffffff';
712 } else {
713 $wpterm_options['font-color'] = preg_replace( '/\W/', '', $wpterm_options['font-color'] );
714 }
715 if ( ctype_xdigit( $wpterm_options['font-color'] ) ) {
716 $wpterm_options['font-color-val'] = '#' . $wpterm_options['font-color'];
717 } else {
718 $wpterm_options['font-color-val'] = $wpterm_options['font-color'];
719 }
720
721 if ( empty( $wpterm_options['background-color'] ) ) {
722 $wpterm_options['background-color'] = '3465A4';
723 } else {
724 $wpterm_options['background-color'] = preg_replace( '/\W/', '', $wpterm_options['background-color'] );
725 }
726 if ( ctype_xdigit( $wpterm_options['background-color'] ) ) {
727 $wpterm_options['background-color-val'] = '#' . $wpterm_options['background-color'];
728 } else {
729 $wpterm_options['background-color-val'] = $wpterm_options['background-color'];
730 }
731
732 if (! isset( $wpterm_options['font-size'] ) || ! preg_match( '/^(?:9|1[0-9]|20)$/', $wpterm_options['font-size'] ) ) {
733 $wpterm_options['font-size'] = 13;
734 }
735
736
737 if (! empty( $wpterm_options['bold-font'] ) ) {
738 $wpterm_options['bold-font'] = 1;
739 } else {
740 $wpterm_options['bold-font'] = 0;
741 }
742
743 if (! empty( $wpterm_options['font-family'] ) ) {
744 $wpterm_options['font-family'] = preg_replace( '/[^\'" ,a-zA-Z]/', '', $wpterm_options['font-family'] );
745 $wpterm_options['font-family'] = trim( $wpterm_options['font-family'], ' ,' );
746 }
747 if ( empty( $wpterm_options['font-family'] ) ) {
748 $wpterm_options['font-family'] = 'Consolas,Monaco,monospace';
749 }
750
751 if ( empty( $wpterm_options['welcome-message'] ) || ! preg_match( '/^(?:wpterm|cowsay|tux)$/', $wpterm_options['welcome-message'] ) ) {
752 $wpterm_options['welcome-message'] = 'wpterm';
753 }
754
755 if ( empty( $wpterm_options['php-function'] ) || ! preg_match( '/^(?:exec|shell_exec|system|passthru|popen)$/', $wpterm_options['php-function'] ) ) {
756 // WPTerm <1.1.2:
757 if ( @$wpterm_options['php-function'] == 'backtick' ) {
758 $wpterm_options['php-function'] = 'shell_exec';
759 } else {
760 $wpterm_options['php-function'] = 'exec';
761 }
762 }
763
764 if (! isset( $wpterm_options['tab-completion'] ) || $wpterm_options['tab-completion'] == 1 ) {
765 // Default value:
766 $wpterm_options['tab-completion'] = 1;
767 } else {
768 $wpterm_options['tab-completion'] = 0;
769 }
770
771
772 if (! isset( $wpterm_options['user-home'] ) || $wpterm_options['user-home'] == 'abspath' ) {
773 $wpterm_options['user-home'] = 'abspath';
774 } else {
775 $wpterm_options['user-home'] = 'homedir';
776 }
777
778
779 if (! empty( $wpterm_options['scrollback'] ) ) {
780 $wpterm_options['scrollback'] = (int) $wpterm_options['scrollback'];
781 if ( $wpterm_options['scrollback'] < 1 || $wpterm_options['scrollback'] > 3000 ) {
782 $wpterm_options['scrollback'] = 512;
783 }
784 } else {
785 $wpterm_options['scrollback'] = 512;
786 }
787
788
789 if (! isset( $wpterm_options['visual-bell'] ) || $wpterm_options['visual-bell'] == 1 ) {
790 $wpterm_options['visual-bell'] = 1;
791 } else {
792 $wpterm_options['visual-bell'] = 0;
793 }
794
795 if (! empty( $wpterm_options['audible-bell'] ) ) {
796 $wpterm_options['audible-bell'] = 1;
797 } else {
798 $wpterm_options['audible-bell'] = 0;
799 }
800
801
802 return $wpterm_options;
803
804 }
805
806 /* ================================================================== */
807
808 function wpterm_menu_save_settings() {
809
810 // Check and save the terminal settings:
811
812 $wpterm_options = get_option('wpterm_options');
813
814
815 if ( empty( $_POST['font-color'] ) ) {
816 $wpterm_options['font-color'] = 'ffffff';
817 } else {
818 // Make sure $_POST['font-color'] contains only word characters:
819 $wpterm_options['font-color'] = preg_replace( '/\W/', '', $_POST['font-color'] );
820 }
821
822 if ( empty( $_POST['background-color'] ) ) {
823 $wpterm_options['background-color'] = '3465A4';
824 } else {
825 // Make sure $_POST['background-color'] contains only word characters:
826 $wpterm_options['background-color'] = preg_replace( '/\W/', '', $_POST['background-color'] );
827 }
828
829 // Make sure $_POST['font-size'] is an integer between 9 and 20,
830 // otherwise set it to 13, its default value:
831 if (! isset( $_POST['font-size'] ) || ! preg_match( '/^(?:9|1[0-9]|20)$/', $_POST['font-size'] ) ) {
832 $wpterm_options['font-size'] = 13;
833 } else {
834 $wpterm_options['font-size'] = (int)$_POST['font-size'];
835 }
836
837 if (! empty( $_POST['bold-font'] ) ) {
838 $wpterm_options['bold-font'] = 1;
839 } else {
840 $wpterm_options['bold-font'] = 0;
841 }
842
843 // Make sure $_POST['font-family'] contains only letters, commas, spaces, single and double quotes:
844 if (! empty( $_POST['font-family'] ) ) {
845 $wpterm_options['font-family'] = preg_replace( '/[^\'" ,a-zA-Z]/', '', $_POST['font-family'] );
846 $wpterm_options['font-family'] = trim( $wpterm_options['font-family'], ' ,' );
847 }
848 if ( empty( $_POST['font-family'] ) ) {
849 $wpterm_options['font-family'] = 'Consolas,Monaco,monospace';
850 }
851
852 // Make sure the value of $_POST['welcome-message'] is 'wpterm', 'cowsay' or 'tux',
853 // otherwise set it to 'wpterm', its default value:
854 if ( empty( $_POST['welcome-message'] ) || ! preg_match( '/^(?:wpterm|cowsay|tux)$/', $_POST['welcome-message'] ) ) {
855 $wpterm_options['welcome-message'] = 'wpterm';
856 } else {
857 $wpterm_options['welcome-message'] = htmlspecialchars( $_POST['welcome-message'] );
858 }
859
860 // Make sure the value of $_POST['php-function'] is 'exec', 'shell_exec', 'system', 'popen' or 'passthru',
861 // otherwise set it to 'exec', its default value:
862 if ( empty( $_POST['php-function'] ) || ! preg_match( '/^(?:exec|shell_exec|system|passthru|popen)$/', $_POST['php-function'] ) ) {
863 $wpterm_options['php-function'] = 'exec';
864 } else {
865 $wpterm_options['php-function'] = htmlspecialchars( $_POST['php-function'] );
866 }
867
868 if ( empty( $_POST['tab-completion'] ) || $_POST['tab-completion'] != 1 ) {
869 $wpterm_options['tab-completion'] = 0;
870 } else {
871 $wpterm_options['tab-completion'] = 1;
872 }
873
874 // Make sure the value of $_POST['user-home'] is 'abspath' or 'homedir',
875 // otherwise set it to 'abspath', its default value:
876 if ( empty( $_POST['user-home'] ) || ! preg_match( '/^(?:abspath|homedir)$/', $_POST['user-home'] ) ) {
877 $wpterm_options['user-home'] = 'abspath';
878 } else {
879 $wpterm_options['user-home'] = htmlspecialchars( $_POST['user-home'] );
880 }
881
882 // Make sure $_POST['scrollback'] is an integer between 1 and 3,000,
883 // otherwise set it to 512, its default value:
884 if (! empty( $_POST['scrollback'] ) ) {
885 $wpterm_options['scrollback'] = (int) $_POST['scrollback'];
886 if ( $wpterm_options['scrollback'] < 1 || $wpterm_options['scrollback'] > 3000 ) {
887 $wpterm_options['scrollback'] = 512;
888 }
889 } else {
890 $wpterm_options['scrollback'] = 512;
891 }
892
893
894 if (! empty( $_POST['audible-bell'] ) ) {
895 $wpterm_options['audible-bell'] = 1;
896 } else {
897 $wpterm_options['audible-bell'] = 0;
898 }
899 if (! empty( $_POST['visual-bell'] ) ) {
900 $wpterm_options['visual-bell'] = 1;
901 } else {
902 $wpterm_options['visual-bell'] = 0;
903 }
904
905
906 // Save current version too (we'll likely need it when updating the plugin):
907 $wpterm_options['version'] = WPTERM_VERSION;
908
909 update_option( 'wpterm_options', $wpterm_options );
910
911 }
912
913 /* ================================================================== */
914
915 function wpterm_menu_about() {
916
917 if ( file_exists( plugin_dir_path(__FILE__) . 'LICENSE.TXT' ) ) {
918 $gpl3 = file_get_contents( plugin_dir_path(__FILE__) . 'LICENSE.TXT' );
919 } else {
920 $gpl3 = esc_html__( 'Error: cannot open LICENSE.TXT!', 'wpterm' );
921 }
922 ?>
923 <div class="wrap">
924 <h1>WPTerm</h1>
925
926 <h2 class="nav-tab-wrapper wp-clearfix">
927 <a href="?page=wpterm&wptermtab=terminal" class="nav-tab"><?php esc_html_e( 'Terminal', 'wpterm' ) ?></a>
928 <a href="?page=wpterm&wptermtab=settings" class="nav-tab"><?php esc_html_e( 'Settings', 'wpterm' ) ?></a>
929 <a href="?page=wpterm&wptermtab=about" class="nav-tab nav-tab-active"><?php esc_html_e( 'About', 'wpterm' ) ?></a>
930 </h2>
931
932 <div class="card">
933 <h1>WPTerm v<?php echo WPTERM_VERSION ?></h1>
934 <h3>&copy; <?php echo date( 'Y' ) ?> Jerome Bruandet</h3>
935 <hr />
936 <strong><?php esc_html_e('From the same author:', 'wpterm' ) ?></strong>
937 <ul>
938 <li><a href="https://wordpress.org/plugins/ninjafirewall/"><strong>NinjaFirewall (WP Edition)</strong></a>: <?php esc_html_e('A true Web Application Firewall to protect and secure WordPress.', 'wpterm' ) ?></li>
939 <li><a href="https://wordpress.org/plugins/code-profiler/"><strong>Code Profiler</strong></a>: <?php esc_html_e('WordPress Performance Profiling and Debugging Made Easy.', 'wpterm' ) ?></li>
940 <li><a href="https://wordpress.org/plugins/safercheckout-lite/"><strong>SaferCheckout</strong></a>: <?php esc_html_e('Fraud prevention for WooCommerce stores.', 'wpterm' ) ?></li>
941 <li><a href="https://wordpress.org/plugins/ninjascanner/"><strong>NinjaScanner</strong></a>: <?php esc_html_e('A lightweight, fast and powerful antivirus scanner for WordPress.', 'wpterm' ) ?></li>
942 <li><a href="https://wordpress.org/plugins/dashboard-cleaner/"><strong>Dashboard Cleaner</strong></a>: <?php esc_html_e('Reclaim your admin dashboard: Get rid of annoying banners, unwanted ads and other nuisances.', 'wpterm' ) ?></li>
943 </ul>
944 <hr />
945 <h3><?php _e('Rate it', 'wpterm' ) ?></h3>
946 <a href="https://wordpress.org/support/view/plugin-reviews/wpterm?rate=5#postform"><img title="<?php _e('Rate it', 'wpterm' ) ?>" border="0" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAAcCAIAAAA/XwxHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3woMCgQevC7e8gAAActJREFUaN7tmb9LAmEYx9/XM1OLNDMCB8MLQRCHoKGprbW1pcWh/yKabHVsjIj+gKgGh1q1oMEIIoIup8Ph0lOvO7F7720QuZI6fd9q6X2+2/G+H57j88D7gxdTShHkb+IDBSAX5EJ+LJfS5p7RbHGVE4tll0sV82G383BIODZCwVgfcxsbBaPtoHah02gB+6tyqWI+HjoIIaRZj4zNFI1llNtv4+CLrZmisaxy3Tb2w9JM0ViEEEL42xsa1W3ttGc82ZZCTMW2FGLVv5iLp30h2R+SpbAshWT/9NpkPOdDgrGYVS7qEXVTuztxGFoVC+ZuookUFo5lXhYCUuI4ll7F41YKBNIXg0qisTxr7tRE6mw2uTROKX/yfDa1jMVlOTY0HJ/MXEYX5kZsiwtHscz68NIjGstzWsCLoexB0GOitBHJbkkYWL6jGKkTj3WeqI7HsGgsq1xqXRGv8ec3qwssn1ziGLeenXp5MxrA8sntEr3mApH8zMr9/EoxHIm6v6M/U2C/uj+PilN7LSO1hOqVvKHVHHfAtLWiXomqJaSW920H2OGMIde+ble3P5f5GNPWinp1p2cDOxwMr79/F3hDA7kgFwJyQe6/yDsZhxXHUCuqgQAAAABJRU5ErkJggg==" width="116" height="28"><br /><?php _e('Rate it on WordPress.org', 'wpterm' ) ?></a>
947 <p><?php _e('Thanks!', 'wpterm' ) ?></p>
948 <hr />
949 <br />
950 <textarea id="wpterm-license" class="small-text code" style="display:none;width:100%" rows="8" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"><?php echo esc_textarea( $gpl3 ) ?></textarea>
951 <input id="wpterm-license-button" type="button" class="button-secondary" value="<?php echo esc_attr__('View license', 'wpterm' ) ?>" onClick="show_license();" />
952 <br />&nbsp;
953 </div>
954 </div>
955 <?php
956 }
957
958 /* ================================================================== */
959 function run_command( $command, $function ) {
960
961 $ret_var = '';
962 $res = '';
963
964 $wpterm_options = wpterm_menu_get_settings();
965 $function = $wpterm_options['php-function'];
966 if (! preg_match('/^(?:exec|shell_exec|system|passthru|popen)$/', $function ) ) {
967 echo( "\n". esc_html__('Invalid execution method.', 'wpterm') );
968 exit;
969 }
970
971 // Select which method to use to run the command:
972 if ( $function == 'shell_exec') {
973 $res = shell_exec( $command );
974
975 } elseif ( $function == 'system') {
976 ob_start();
977 system( $command, $ret_var );
978 $res = ob_get_contents();
979 ob_end_clean();
980
981 } elseif ( $function == 'passthru') {
982 ob_start();
983 passthru( $command, $ret_var );
984 $res = ob_get_contents();
985 ob_end_clean();
986
987 } elseif ( $function == 'popen') {
988 if ( ( $handle = popen( $command , 'r') ) !== false ) {
989 while (! feof( $handle ) ) {
990 $res .= fgets( $handle );
991 }
992 pclose( $handle );
993 }
994
995 } else {
996 if ( exec( $command, $res, $ret_var ) ) {
997 $res = implode( "\n", $res );
998 }
999 }
1000
1001 return [ $res, $ret_var ];
1002
1003 }
1004
1005 /* ================================================================== */
1006
1007 function wpterm_is_allowed( $is_ajax = null ) {
1008
1009 // Check if a password was set:
1010 if (! defined( 'WPTERM_PASSWORD' ) ) {
1011 // No, let it go:
1012 return true;
1013 }
1014
1015 // Check if the user session exists:
1016 if ( empty( $_SESSION['wptermpwd'] ) ) {
1017 // Return if this is an AJAX call (a warning
1018 // will be displayed from the terminal prompt):
1019 if ( isset( $is_ajax ) ) { return false; }
1020 // Display the password form:
1021 if( ! wpterm_password_prompt(1) ) {
1022 return false;
1023 }
1024 }
1025 // Check if passwords match:
1026 if ( $_SESSION['wptermpwd'] != WPTERM_PASSWORD ) {
1027 // Password does not match, clear it:
1028 unset( $_SESSION['wptermpwd'] );
1029 if ( isset( $is_ajax ) ) { return false; }
1030 // Display the password form:
1031 if (! wpterm_password_prompt(2) ) {
1032 return false;
1033 }
1034 }
1035
1036 // Okay, go ahead!
1037 return true;
1038
1039 }
1040
1041 /* ================================================================== */
1042
1043 function wpterm_password_prompt( $err = 0 ) {
1044
1045 // Display the password form:
1046
1047 // Password form submitted?
1048 if ( isset( $_POST['wptermpwd'] ) ) {
1049 // Verify security nonce:
1050 if ( empty( $_POST['wptermnonce'] ) || ! wp_verify_nonce( $_POST['wptermnonce'], 'wpterm_password' ) ) {
1051 wp_nonce_ays( 'wpterm_password' );
1052 }
1053 // Verify password:
1054 if ( sha1( $_POST['wptermpwd'] ) === WPTERM_PASSWORD ) {
1055 $_SESSION['wptermpwd'] = sha1( $_POST['wptermpwd'] );
1056 return true;
1057 } else {
1058 $err = 3;
1059 }
1060 }
1061
1062 if ( $err == 3 ) {
1063 ?>
1064 <div class="error notice is-dismissible"><p><?php esc_html_e( 'Wrong password, please try again.', 'wpterm' ) ?></p></div>
1065 <?php
1066 } else {
1067 ?>
1068 <div class="notice-info notice is-dismissible"><p><?php printf( esc_html__( 'A password is required to access WPTerm (#%s).', 'wpterm' ), (int) $err ) ?></p></div>
1069 <?php
1070 }
1071 ?>
1072
1073 <div class="wrap">
1074 <h1>WPTerm</h1>
1075
1076 <h2 class="nav-tab-wrapper wp-clearfix" style="cursor:not-allowed">
1077 <a class="nav-tab"><?php esc_html_e( 'Terminal', 'wpterm' ) ?></a>
1078 <a class="nav-tab"><?php esc_html_e( 'Settings', 'wpterm' ) ?></a>
1079 <a class="nav-tab"><?php esc_html_e( 'About', 'wpterm' ) ?></a>
1080 <a class="nav-tab"><?php esc_html_e( 'Info', 'wpterm' ) ?></a>
1081 </h2>
1082
1083 <div class="card">
1084
1085 <form method="post">
1086 <h3><?php esc_html_e( 'Enter your WPTerm password:', 'wpterm' ) ?></h3>
1087 <p><input class="input" type="password" name="wptermpwd" placeholder="Password" autofocus /></p>
1088 <p><input type="submit" class="button-secondary" /></p>
1089 <?php wp_nonce_field('wpterm_password', 'wptermnonce', 0); ?>
1090 </form>
1091
1092 </div>
1093 </div>
1094 <?php
1095
1096 return false;
1097
1098 }
1099
1100 /* ================================================================== */
1101 // EOF
1102