-
-
Save austinginder/783802bd617fb9d18fd0ac0c716304ea to your computer and use it in GitHub Desktop.
Concept using Phpseclib to run Rclone from WordPress backend. See https://anchor.host/using-phpseclib-instead-of-disallowed-php-exec/.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: Rclone Concept | |
* Plugin URI: https://anchor.host/using-phpseclib-instead-of-disallowed-php-exec/ | |
* Description: Concept using Phpseclib to run Rclone from WordPress backend. | |
* Author: Austin Ginder | |
* Author URI: https://austinginder.com | |
* Text Domain: rclone-concept | |
* Domain Path: /languages | |
* Version: 0.1.0 | |
* | |
* @package Rclone_Concept | |
*/ | |
require __DIR__ . '/vendor/autoload.php'; | |
use phpseclib\Net\SSH2; | |
function run_rclone_command( $command, $username, $password ) { | |
$ssh = new SSH2( '127.0.0.1' ); | |
if ( !$ssh->login( $username, $password ) ) { | |
exit( "Login Failed" ); | |
} | |
return $ssh->exec( "cd private/rclone-v*/; ./rclone $command --config rclone.conf" ); | |
} | |
// Process ajax events | |
add_action( 'wp_ajax_rclone_concept_ajax', 'rclone_concept_ajax' ); | |
function rclone_concept_ajax() { | |
global $wpdb; // this is how you get access to the database | |
// Only proceed if logged in user is an administrator | |
if ( ! current_user_can('administrator') ) { | |
return true; | |
wp_die(); | |
} | |
$request = (object) $_POST['value']; | |
$response = run_rclone_command( $request->command, $request->username, $request->password ); | |
echo json_encode( $response ); | |
wp_die(); // this is required to terminate immediately and return a proper response | |
} | |
add_action( 'admin_menu', 'rclone_concept_add_admin_menu' ); | |
function rclone_concept_add_admin_menu() { | |
add_options_page( 'Rclone Concept', 'Rclone Concept', 'manage_options', 'rclone_concept', 'rclone_concept_options_page' ); | |
} | |
function rclone_concept_options_page() { ?> | |
<script src="https://unpkg.com/qs@6.5.2/dist/qs.js"></script> | |
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> | |
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.2.23/dist/vuetify.css" rel="stylesheet"> | |
<style> | |
/* WordPress Admin Vuetify Reset */ | |
input[type="color"], input[type="date"], input[type="datetime-local"], input[type="datetime"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"], select, textarea { | |
border: 0px; | |
background-color: transparent; | |
} | |
input[type="checkbox"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime-local"]:focus, input[type="datetime"]:focus, input[type="email"]:focus, input[type="month"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="radio"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="week"]:focus, select:focus, textarea:focus { | |
box-shadow: none; | |
} | |
input.readonly, input[readonly], textarea.readonly, textarea[readonly] { | |
background-color: transparent; | |
} | |
.v-textarea textarea { | |
font-size:13px; | |
line-height:1.1em; | |
font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;' | |
} | |
</style> | |
<h2>Rclone Concept</h2> | |
<div id="app"> | |
<v-app style="background:transparent;"> | |
<v-content class="mr-6"> | |
<v-row> | |
<v-col cols="12" md="6"> | |
<v-text-field label="Rclone Subcommand" v-model="command"></v-text-field> | |
</v-col> | |
<v-col cols="12" md="3"> | |
<v-text-field label="SSH Username" v-model="username" type="password"></v-text-field> | |
</v-col> | |
<v-col cols="12" md="3"> | |
<v-text-field label="SSH Password" v-model="password" type="password"></v-text-field> | |
</v-col> | |
</v-row> | |
<v-btn color="primary" @click="runCommand()">Run Command</v-btn> | |
<v-textarea label="Response" auto-grow solo readonly v-model="response" class="mt-5"></v-textarea> | |
</v-content> | |
</v-app> | |
</div> | |
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.2.23/dist/vuetify.js"></script> | |
<script> | |
new Vue({ | |
el: '#app', | |
vuetify: new Vuetify(), | |
data: { | |
username: "", | |
password: "", | |
command: "", | |
response: "" | |
}, | |
methods: { | |
runCommand() { | |
// Prep AJAX request | |
var data = { | |
'action': 'rclone_concept_ajax', | |
'command': "toggle-rclone-remote", | |
'value': { | |
'command': this.command, | |
'username': this.username, | |
'password': this.password, | |
} | |
} | |
// update server | |
axios.post( '/wp-admin/admin-ajax.php', Qs.stringify( data ) ) | |
.then( response => { | |
this.command = "" | |
this.response = response.data | |
}) | |
.catch(error => { | |
console.log(error.response) | |
}); | |
} | |
} | |
}) | |
</script> | |
<?php | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment