From: Valerie Pond Date: Sun, 25 Jun 2023 09:39:48 +0000 (+0100) Subject: Make the plugins page actually work (to a degree) X-Git-Tag: 0.9~21 X-Git-Url: https://jfr.im/git/irc/unrealircd/unrealircd-webpanel.git/commitdiff_plain/fae5cd150c35b3f9669372e87da8d13415a4bf19?hp=1815dd1e24dcbb3507f5605a6d181999b1b094be Make the plugins page actually work (to a degree) --- diff --git a/Classes/class-paneluser.php b/Classes/class-paneluser.php index e4c5a7c..0a3cf8a 100644 --- a/Classes/class-paneluser.php +++ b/Classes/class-paneluser.php @@ -27,6 +27,8 @@ define('PERMISSION_SPAMFILTER_ADD', 'sf_add'); define('PERMISSION_SPAMFILTER_DEL', 'sf_del'); /** Can rehash servers */ define('PERMISSION_REHASH', 'rhs'); +/** Can install and uninstall plugins */ +define('PERMISSION_MANAGE_PLUGINS', 'mng_plg'); /** * PanelUser * This is the User class for the SQL_Auth plugin @@ -340,6 +342,7 @@ function get_panel_user_permission_list() { $list = [ "Can add/delete/edit Admin Panel users" => PERMISSION_MANAGE_USERS, + "Can add/delete/manage plugins" => PERMISSION_MANAGE_PLUGINS, "Can ban/kill IRC users" => PERMISSION_BAN_USERS, "Can change properties of a user, i.e. vhost, modes and more" => PERMISSION_EDIT_USER, "Can change properties of a channel, i.e. topic, modes and more" => PERMISSION_EDIT_CHANNEL, @@ -352,6 +355,7 @@ function get_panel_user_permission_list() "Can remove server ban exceptions" => PERMISSION_BAN_EXCEPTION_DEL, "Can add Spamfilter entries" => PERMISSION_SPAMFILTER_ADD, "Can remove Spamfilter entries" => PERMISSION_SPAMFILTER_DEL + ]; Hook::run(HOOKTYPE_USER_PERMISSION_LIST, $list); // so plugin writers can add their own permissions return $list; diff --git a/Classes/class-plugin-git.php b/Classes/class-plugin-git.php index 4f09161..232fc20 100644 --- a/Classes/class-plugin-git.php +++ b/Classes/class-plugin-git.php @@ -3,28 +3,43 @@ class PluginRepo { - public $plugins; + public $plugins ; public $data; public $err; function __construct($url = DEFAULT_PLUGINS_DIR) { + global $config; + if (!isset($config['third-party-plugins'])) + { + $config['third-party-plugins']['data'] = NULL; + $config['third-party-plugins']['timestamp'] = 0; + } + if (time() - $config['third-party-plugins']['timestamp'] > 200) // Cache for 3.333 minutes lol + { + // come simba it is taem + $curl = curl_init($url); - - // Initialize curl - $curl = curl_init($url); - - // Set the options - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // Return the response instead of printing it - curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); // Set the content type to JSON - curl_setopt($curl, CURLOPT_USERAGENT, "UnrealIRCd Admin Panel"); - // Execute the request - $response = curl_exec($curl); - - // Check for errors - if ($response === false) - $this->err = curl_error($curl); - else - $this->data = json_decode($response, false); + // Set the options + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // Return the response instead of printing it + curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); // Set the content type to JSON + curl_setopt($curl, CURLOPT_USERAGENT, "UnrealIRCd Admin Panel"); // This is Secret Agent UnrealIRCd Admin Panel reporting for doody + // Execute the request + $response = curl_exec($curl); + + // Check for errors + if ($response === false) + $this->err = curl_error($curl); + else + { + $this->data = json_decode($response, false); + $config['third-party-plugins']['data'] = $this->data; + $config['third-party-plugins']['timestamp'] = time(); + write_config('third-party-plugins'); + } + } + else + $this->data = $config['third-party-plugins']['data']; + } @@ -33,12 +48,12 @@ { if ($installed) { ?> -
Installed ✅
+
✔ Installed
-
Installed ✅
+
✔ Installed
-
- err) + die("Could not fetch list.\n"); + global $config; + ?> +
+ data as $p) { - $installed = Plugins::plugin_exists($p->name) ? true : false; + $installed = in_array($p->name, $config['plugins']) ? true : false; if (is_string($p)) continue; @@ -63,41 +82,57 @@ // use a default image if there was none $p->icon = $p->icon ?? get_config("base_url")."img/no-image-available.jpg"; ?> - -
card text-dark bg-light ml-4 mb-3 w-25"> -
-
-
- title; $this->ifInstalledLabel($p->name); ?>
+ +
plugin-card card text-dark bg-light ml-4 mb-3 w-25" style="min-width:300px"> + + +
+
+ +
+
ifInstalledLabel($p->name); ?>
+

title ?>

+ By email" ?>" target="_blank">author ?> +
+
-
-
-
title ?> vversion ?>
-

description ?>

-
- - -
- = 3) // only do three per row. WARNING: untested due to not having more than 2 plugins atm... - { - ?> + + +
+
title ?> vversion ?>
+

description ?>

-
+ +
+ = 3) + { + ?> +
+
+
+ } + ?> +
+ Want to see your plugin listed here? Make a pull request to our GitHub Repository! "Access denied"])); +if (empty($_GET)) + die(json_encode($config['third-party-plugins']['data'])); + +elseif(isset($_GET['install'])) +{ + install_plugin($_GET['install']); +} +elseif (isset($_GET['uninstall'])) +{ + uninstall_plugin($_GET['uninstall']); +} + +function uninstall_plugin($name) +{ + global $config; + if (!Plugins::plugin_exists($name)) + die(json_encode(['error' => "Plugin not loaded"])); + + foreach($config['plugins'] as $k => $v) + if ($v == $name) + unset($config['plugins'][$k]); + write_config(); + + deleteDirectory(UPATH."/plugins/$name"); + die(json_encode(["success" => "Plugin was deleted successfully"])); +} + +/**Attempt to install the plugin + * @param string $name name of the plugin + * @return void + */ +function install_plugin($name) +{ + global $config; + if (in_array($name, $config['plugins'])) + die(json_encode(["error" => "Plugin already installed"])); + $url = get_plugin_install_path_from_name($name); + $pluginfile = file_get_contents($url); + if (!is_dir(UPATH."/data/tmp")) + mkdir(UPATH."/data/tmp"); + + $path = UPATH."/data/tmp/"; + $file = $path.md5(time()).".tmp"; + if (!file_put_contents($file, $pluginfile)) + die(json_encode(["error" => "Cannot write to directory: Need write permission"])); + + unset($pluginfile); + + $zip = new ZipArchive; + $res = $zip->open($file); + if ($res !== true) { + unlink($file); + die(json_encode(["error" => "Could not open file we just wrote lol"])); + } + + // ensure we have no conflicts + $extractPath = UPATH."/plugins/$name"; + // lazy upgrade for now. + if (is_dir($extractPath)) + { + deleteDirectory($extractPath); + } + mkdir($extractPath); + $zip->extractTo($extractPath); + $zip->close(); + + //clear up our temp shit + unset($zip); + unlink($file); + unset($res); + + // load it in the config + $config['plugins'][] = $name; + write_config(); + + // wahey + die(json_encode(['success' => "Installation was complete"])); +} + +/** + * @param string $name Name of plugin + * @return NULL|string Path or NULL + */ +function get_plugin_install_path_from_name($name) +{ + global $config; + foreach($config['third-party-plugins']['data'] as $p) + { + if (!strcmp($p->name,$name)) + return $p->download_link; + } + return NULL; +} + +function deleteDirectory($dir) { + if (!file_exists($dir)) { + return true; + } + + if (!is_dir($dir)) { + return unlink($dir); + } + + foreach (scandir($dir) as $item) { + if ($item == '.' || $item == '..') { + continue; + } + + if (!deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) { + return false; + } + + } + + return rmdir($dir); +} \ No newline at end of file diff --git a/inc/defines.php b/inc/defines.php index 2639e1a..622804a 100644 --- a/inc/defines.php +++ b/inc/defines.php @@ -17,4 +17,4 @@ define('DEFAULT_CHAN_DETAIL_QUICK_BAN_REASON', "You have been removed from this /** * The version of our webpanel */ -define('WEBPANEL_VERSION', "1.0-git"); +define('WEBPANEL_VERSION', "0.9-git"); diff --git a/settings/add-plugin.php b/settings/add-plugin.php index 21ecf90..4ca6df2 100644 --- a/settings/add-plugin.php +++ b/settings/add-plugin.php @@ -4,6 +4,9 @@ require_once "../inc/common.php"; require_once "../inc/header.php"; require_once "../Classes/class-plugin-git.php"; +if (!current_user_can(PERMISSION_MANAGE_PLUGINS)) + die("Access denied"); + $p = new PluginRepo(); ?> @@ -26,8 +29,128 @@ $p = new PluginRepo(); ?> - \ No newline at end of file + + const ibtns = document.querySelectorAll(".btn-install-plugin"); + ibtns.forEach((ib) => { + ib.addEventListener('click', (e) => { + console.log("Button clicked! " +ib.innerHTML); + if (ib.innerHTML !== "Install" && ib.innerHTML !== "Uninstall") // some point between, don't do anything + {} + else if (ib.innerHTML == "Install") // install button pressed! + { + let req = requestInstall(ib.id.slice(0,-7)) + if (req == true) + { + ib.classList.replace("btn-primary", "btn-secondary"); + ib.innerHTML = "Installing..."; + } + else + { + let uhoh = new bsModal("Error", "Could not install: "+req, "", null, false, true); + } + } + else if (ib.innerHTML == "Uninstall") + { + let req = requestInstall(ib.id.slice(0,-7), true); // true = uninstall + if (req == true) + { + ib.classList.replace("btn-outline-danger", "btn-secondary"); + ib.innerHTML = "Uninstalling..."; + } + else + { + let uhoh = new bsModal("Error", "Could not uninstall: "+req, "", null, false, true); + } + } + }); + }) + const installed = document.querySelectorAll(".installed"); + installed.forEach((el) => { + let btn = document.getElementById(el.id + 'install'); + btn.classList.replace("btn-primary", "btn-outline-danger"); + btn.innerHTML = "Uninstall"; + }); + + function requestInstall(name, uninstall = false) + { + let inst = (uninstall) ? "uninstall" : "install"; + var xhr = new XMLHttpRequest(); + + xhr.onload = function() { + if (xhr.status === 200) { + var response = JSON.parse(xhr.responseText); + console.log(response.success); + let install_button = document.getElementById(name+'install'); + if (response.success !== undefined) + { + if (install_button) + { + install_button.innerHTML = (inst == "uninstall") ? "Install" : "Uninstall"; + install_button.classList.replace('btn-secondary', (inst == "uninstall") ? 'btn-primary' : 'btn-outline-danger'); + let icomplete = bsModal(((inst == "uninstall") ? "Uninstall" : "Install") + " Plugin", response.success,"
Close
", null, true, true, false); + let closebtn = document.getElementById(name+"closebtn"); + closebtn.addEventListener('click', e => { + location.reload(); + }); + } + } + else + { + if (install_button) + { + install_button.innerHTML = (inst == "uninstall") ? "Uninstall" : "Install"; + install_button.classList.replace('btn-secondary', (inst == "uninstall") ? 'btn-outline-danger' : 'btn-primary'); + let icomplete = bsModal(((inst == "uninstall") ? "Uninstall" : "Install") + " Plugin", response.error,"", null, false, true); + let closebtn = document.getElementById(name+"closebtn"); + closebtn.addEventListener('click', e => { + location.reload(); + }); + } + } + } + }; + + xhr.open('GET', BASE_URL + 'api/plugin.php?'+inst+'=' + name, true); + xhr.send(); + return true; + } + + function create_info_modal(modname) + { + fetch('https://api.dalek.services/plugins.list') + .then(response => response.json()) // Parse the response as JSON + .then(data => { + for (let i = 0; data[i]; i++) + { + if (data[i].name == modname) + { + const modal = bsModal( + "Information about " + data[i].title + "", // title + "
", + "
Close
", null, true, true, false + ); + let modalclose = document.getElementById(modal); + modalclose.addEventListener('click', (e) => { + $("#"+modal).modal('hide'); + }); + console.log(modal + '-body'); + boobs = document.getElementById(modal + '-body'); + boobs.innerHTML = data[i].description; + } + } + }) + .catch(error => { + // Handle any errors that occur during the request + console.error('Error:', error); + }); + } + + const infoButtons = document.querySelectorAll('.more-info'); + infoButtons.forEach((el) => { + el.addEventListener('click', (event) => { + create_info_modal(el.id); + + }); + }); +