PluginProbe
WPTerm / 1.1.5
WPTerm v1.1.5
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.1.5, at wpterm.php

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