mirror of
https://github.com/unraid/webgui.git
synced 2026-01-06 01:29:54 -06:00
banish dynamix.my.servers from webGUI repo
This commit is contained in:
@@ -1,154 +0,0 @@
|
||||
Menu="About:20"
|
||||
Title="Downgrade OS"
|
||||
Icon="icon-update"
|
||||
Tag="upload"
|
||||
---
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* @note icon-update is rotated via CSS in myservers1.php
|
||||
*/
|
||||
require_once "$docroot/plugins/dynamix/include/ReplaceKey.php";
|
||||
$replaceKey = new ReplaceKey();
|
||||
$replaceKey->check();
|
||||
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
$rebootDetails = new RebootDetails();
|
||||
$rebootDetails->setPrevious();
|
||||
|
||||
$serverNameEscaped = htmlspecialchars(str_replace(' ', '_', strtolower($var['NAME'])));
|
||||
?>
|
||||
|
||||
<script>
|
||||
const nchan_diagnostics = new NchanSubscriber('/sub/diagnostics', { subscriber: 'websocket' });
|
||||
const reportUrl = new URL('https://forums.unraid.net/bug-reports/');
|
||||
let diagnosticsFile = '';
|
||||
|
||||
nchan_diagnostics.on('message', function(data) {
|
||||
if (data == '_DONE_') {
|
||||
nchan_diagnostics.stop();
|
||||
$('.sweet-alert').hide('fast').removeClass('nchan');
|
||||
swal.close();
|
||||
$('div.spinner').show('slow');
|
||||
location = diagnosticsFile;
|
||||
|
||||
setTimeout(() => {
|
||||
cleanupDiagnostics();
|
||||
reportAfterDiagnosticsDownload();
|
||||
}, 2000);
|
||||
} else if (data) {
|
||||
let box = $('pre#swaltext');
|
||||
box.html(box.html() + '<br>' + data).scrollTop(box[0].scrollHeight);
|
||||
}
|
||||
});
|
||||
|
||||
function downloadDiagnostics() {
|
||||
const tzoffset = (new Date()).getTimezoneOffset() * 60000; // offset in milliseconds
|
||||
const localISOTime = (new Date(Date.now() - tzoffset));
|
||||
const year = localISOTime.getFullYear();
|
||||
const month = String(localISOTime.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(localISOTime.getDate()).padStart(2, '0');
|
||||
const hours = String(localISOTime.getHours()).padStart(2, '0');
|
||||
const minutes = String(localISOTime.getMinutes()).padStart(2, '0');
|
||||
const dateOutput = `${year}${month}${day}_${hours}${minutes}`;
|
||||
const zipName = '<?=$serverNameEscaped?>-diagnostics-' + dateOutput + '.zip';
|
||||
|
||||
nchan_diagnostics.start();
|
||||
|
||||
$.post(
|
||||
'/webGui/include/Download.php',
|
||||
{
|
||||
cmd: 'diag',
|
||||
file: zipName,
|
||||
anonymize: '',
|
||||
},
|
||||
function(zip) {
|
||||
if (!zip) {
|
||||
return nchan_diagnostics.stop();
|
||||
}
|
||||
|
||||
diagnosticsFile = zip;
|
||||
swal({
|
||||
title: "_(Downloading)_...",
|
||||
text: "/boot/logs" + zip + "<hr><pre id='swaltext'></pre>",
|
||||
html: true,
|
||||
animation: 'none',
|
||||
showConfirmButton: false,
|
||||
});
|
||||
$('.sweet-alert').addClass('nchan');
|
||||
$('button.confirm').prop('disabled', true);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function reportAfterDiagnosticsDownload() {
|
||||
$('div.spinner').hide('fast');
|
||||
swal({
|
||||
title: "_(Open a bug report)_",
|
||||
text: "_(Create a bug report on our forums with a description of the issue along with your diagsnotics)_",
|
||||
html: true,
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "<?= _('Create Bug Report') ?>",
|
||||
cancelButtonText: "<?= _('Close') ?>",
|
||||
}, function(confirm) {
|
||||
if (!confirm) {
|
||||
return false;
|
||||
}
|
||||
window.open(reportUrl, '_blank');
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupDiagnostics() {
|
||||
if (document.hasFocus()) {
|
||||
return $.post('/webGui/include/Download.php', { cmd: 'delete', file: diagnosticsFile });
|
||||
}
|
||||
setTimeout(cleanupDiagnostics, 2000);
|
||||
}
|
||||
|
||||
function startDowngrade() {
|
||||
$('div.spinner').show('slow');
|
||||
|
||||
$.get(
|
||||
'/plugins/dynamix.plugin.manager/include/Downgrade.php',
|
||||
{
|
||||
version: '<?= $rebootDetails->previousVersion ?>',
|
||||
},
|
||||
function() {
|
||||
refresh();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function confirmDowngrade() {
|
||||
swal({
|
||||
title: "_(Confirm Downgrade)_",
|
||||
text: "<?= $rebootDetails->previousVersion ?><br>_(A reboot will be required)_",
|
||||
html: true,
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "<?= _('Confirm') ?>",
|
||||
cancelButtonText: "<?= _('Cancel') ?>",
|
||||
}, function(confirm) {
|
||||
if (!confirm) {
|
||||
return false;
|
||||
}
|
||||
startDowngrade();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-downgrade-os
|
||||
reboot-version="<?= $rebootDetails->rebootVersion ?>"
|
||||
restore-version="<?= $rebootDetails->previousVersion ?>"
|
||||
restore-release-date="<?= $rebootDetails->previousReleaseDate ?>"></unraid-downgrade-os>
|
||||
</unraid-i18n-host>
|
||||
@@ -1,54 +0,0 @@
|
||||
Menu="About:10"
|
||||
Title="Update OS"
|
||||
Icon="icon-update"
|
||||
Tag="upload"
|
||||
---
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
require_once "$docroot/plugins/dynamix/include/ReplaceKey.php";
|
||||
$replaceKey = new ReplaceKey();
|
||||
$replaceKey->check();
|
||||
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
$rebootDetails = new RebootDetails();
|
||||
?>
|
||||
<script>
|
||||
function cleanUpFlashBackup(zip) {
|
||||
if (document.hasFocus()) {
|
||||
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_").prop('disabled',false);
|
||||
$('div.spinner').hide('slow');
|
||||
$('#pleaseWait').hide('slow');
|
||||
$.post('/webGui/include/Download.php',{cmd:'unlink',file:zip});
|
||||
} else {
|
||||
setTimeout(function(){cleanUpFlashBackup(zip);},2000);
|
||||
}
|
||||
}
|
||||
function flashBackup() {
|
||||
$('input[value="_(Flash backup)_"]').val('_(Creating Flash backup)_...').prop('disabled',true);
|
||||
$('div.spinner').show('slow');
|
||||
$('#pleaseWait').show('slow');
|
||||
$.post('/webGui/include/Download.php',{cmd:'backup'},function(zip) {
|
||||
if (zip) {
|
||||
location = '/'+zip;
|
||||
setTimeout(function(){cleanUpFlashBackup(zip);},6000);
|
||||
} else {
|
||||
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_");
|
||||
$('div.spinner').hide('slow');
|
||||
$('#pleaseWait').hide('slow');
|
||||
swal({title:"_(Creation error)_",text:"_(Insufficient free disk space available)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-update-os reboot-version="<?= $rebootDetails->rebootVersion ?>"></unraid-update-os>
|
||||
</unraid-i18n-host>
|
||||
@@ -1,271 +0,0 @@
|
||||
<?php
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* Abstracting this code into a separate file allows us to use it in multiple places without duplicating code.
|
||||
* 1. unraidcheck script can call this
|
||||
* require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
* $unraidOsCheck = new UnraidOsCheck();
|
||||
* $unraidOsCheck->checkForUpdate();
|
||||
*
|
||||
* 2. Unraid webgui web components can GET this file with action params to get updates, ignore updates, etc.
|
||||
* - EX: Unraid webgui web components can check for updates via a GET request and receive a response with the json file directly
|
||||
* - this is useful for the UPC to check for updates and display a model based on the value
|
||||
* - `/plugins/dynamix.plugin.manager/scripts/unraidcheck.php?json=true`
|
||||
* - note the json=true query param to receive a json response
|
||||
*
|
||||
* @param action {'check'|'removeAllIgnored'|'removeIgnoredVersion'|'ignoreVersion'} - the action to perform
|
||||
* @param version {string} - the version to ignore or remove
|
||||
* @param json {string} - if set to true, will return the json response from the external request
|
||||
* @param altUrl {URL} - if set, will use this url instead of the default
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
class UnraidOsCheck
|
||||
{
|
||||
private const BASE_RELEASES_URL = 'https://releases.unraid.net/os';
|
||||
private const JSON_FILE_IGNORED = '/tmp/unraidcheck/ignored.json';
|
||||
private const JSON_FILE_IGNORED_KEY = 'updateOsIgnoredReleases';
|
||||
private const JSON_FILE_RESULT = '/tmp/unraidcheck/result.json';
|
||||
private const PLG_PATH = '/usr/local/emhttp/plugins/unRAIDServer/unRAIDServer.plg';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
|
||||
|
||||
if ($isGetRequest && $getHasAction) {
|
||||
$this->handleGetRequestWithActions();
|
||||
}
|
||||
}
|
||||
|
||||
private function handleGetRequestWithActions()
|
||||
{
|
||||
switch ($_GET['action']) {
|
||||
case 'check':
|
||||
$this->checkForUpdate();
|
||||
break;
|
||||
|
||||
case 'removeAllIgnored':
|
||||
$this->removeAllIgnored();
|
||||
break;
|
||||
|
||||
case 'removeIgnoredVersion':
|
||||
if (isset($_GET['version'])) {
|
||||
$this->removeIgnoredVersion($_GET['version']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ignoreVersion':
|
||||
if (isset($_GET['version'])) {
|
||||
$this->ignoreVersion($_GET['version']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->respondWithError(400, "Unhandled action");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function getUnraidOSCheckResult()
|
||||
{
|
||||
if (file_exists(self::JSON_FILE_RESULT)) {
|
||||
return $this->readJsonFile(self::JSON_FILE_RESULT);
|
||||
}
|
||||
}
|
||||
|
||||
public function getIgnoredReleases()
|
||||
{
|
||||
if (!file_exists(self::JSON_FILE_IGNORED)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$ignoredData = $this->readJsonFile(self::JSON_FILE_IGNORED);
|
||||
|
||||
if (is_array($ignoredData) && array_key_exists(self::JSON_FILE_IGNORED_KEY, $ignoredData)) {
|
||||
return $ignoredData[self::JSON_FILE_IGNORED_KEY];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/** @todo clean up this method to be more extensible */
|
||||
public function checkForUpdate()
|
||||
{
|
||||
// Multi-language support
|
||||
if (!function_exists('_')) {
|
||||
function _($text) {return $text;}
|
||||
}
|
||||
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
|
||||
$params = [];
|
||||
$params['branch'] = plugin('category', self::PLG_PATH, 'stable');
|
||||
// Get current version from patches.json if it exists, otherwise fall back to plugin version or var.ini
|
||||
$patcherVersion = null;
|
||||
if (file_exists('/tmp/Patcher/patches.json')) {
|
||||
$patcherData = @json_decode(file_get_contents('/tmp/Patcher/patches.json'), true);
|
||||
$unraidVersionInfo = parse_ini_file('/etc/unraid-version');
|
||||
if ($patcherData['unraidVersion'] === $unraidVersionInfo['version']) {
|
||||
$patcherVersion = $patcherData['combinedVersion'] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
$params['current_version'] = $patcherVersion ?: plugin('version', self::PLG_PATH) ?: _var($var, 'version');
|
||||
if (_var($var,'regExp')) $params['update_exp'] = date('Y-m-d', _var($var,'regExp')*1);
|
||||
$defaultUrl = self::BASE_RELEASES_URL;
|
||||
// pass a param of altUrl to use the provided url instead of the default
|
||||
$parsedAltUrl = (array_key_exists('altUrl',$_GET) && $_GET['altUrl']) ? $_GET['altUrl'] : null;
|
||||
// if $parsedAltUrl pass to params
|
||||
if ($parsedAltUrl) $params['altUrl'] = $parsedAltUrl;
|
||||
|
||||
$urlbase = $parsedAltUrl ?? $defaultUrl;
|
||||
$url = $urlbase.'?'.http_build_query($params);
|
||||
$curlinfo = [];
|
||||
$response = http_get_contents($url,[],$curlinfo);
|
||||
if (array_key_exists('error', $curlinfo)) {
|
||||
$response = json_encode(array('error' => $curlinfo['error']), JSON_PRETTY_PRINT);
|
||||
}
|
||||
$responseMutated = json_decode($response, true);
|
||||
if (!$responseMutated) {
|
||||
$response = json_encode(array('error' => 'Invalid response from '.$urlbase), JSON_PRETTY_PRINT);
|
||||
$responseMutated = json_decode($response, true);
|
||||
}
|
||||
|
||||
// add params that were used for debugging
|
||||
$responseMutated['params'] = $params;
|
||||
|
||||
// store locally for UPC to access
|
||||
$this->writeJsonFile(self::JSON_FILE_RESULT, $responseMutated);
|
||||
|
||||
// if we have a query param of json=true then just output the json
|
||||
if (array_key_exists('json',$_GET) && $_GET['json']) {
|
||||
header('Content-Type: application/json');
|
||||
echo $response;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// send notification if a newer version is available and not ignored
|
||||
$isNewerVersion = array_key_exists('isNewer',$responseMutated) ? $responseMutated['isNewer'] : false;
|
||||
$isReleaseIgnored = array_key_exists('version',$responseMutated) ? in_array($responseMutated['version'], $this->getIgnoredReleases()) : false;
|
||||
|
||||
if ($responseMutated && $isNewerVersion && !$isReleaseIgnored) {
|
||||
$output = _var($notify,'plugin');
|
||||
$server = strtoupper(_var($var,'NAME','server'));
|
||||
$newver = (array_key_exists('version',$responseMutated) && $responseMutated['version']) ? $responseMutated['version'] : 'unknown';
|
||||
$script = '/usr/local/emhttp/webGui/scripts/notify';
|
||||
$event = "System - Unraid [$newver]";
|
||||
$subject = "Notice [$server] - Version update $newver";
|
||||
$description = "A new version of Unraid is available";
|
||||
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
private function removeAllIgnored()
|
||||
{
|
||||
if (file_exists(self::JSON_FILE_IGNORED)) {
|
||||
$this->deleteJsonFile(self::JSON_FILE_IGNORED);
|
||||
$this->respondWithSuccess([]);
|
||||
}
|
||||
// fail silently if file doesn't exist
|
||||
}
|
||||
|
||||
private function removeIgnoredVersion($removeVersion)
|
||||
{
|
||||
if ($this->isValidSemVerFormat($removeVersion)) {
|
||||
if (file_exists(self::JSON_FILE_IGNORED)) {
|
||||
$existingData = $this->readJsonFile(self::JSON_FILE_IGNORED);
|
||||
|
||||
if (isset($existingData[self::JSON_FILE_IGNORED_KEY])) {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY] = array_diff($existingData[self::JSON_FILE_IGNORED_KEY], [$removeVersion]);
|
||||
$this->writeJsonFile(self::JSON_FILE_IGNORED, $existingData);
|
||||
$this->respondWithSuccess($existingData);
|
||||
} else {
|
||||
$this->respondWithError(400, "No versions to remove in the JSON file");
|
||||
}
|
||||
} else {
|
||||
$this->respondWithError(400, "No JSON file found");
|
||||
}
|
||||
} else {
|
||||
$this->respondWithError(400, "Invalid removeVersion format");
|
||||
}
|
||||
}
|
||||
|
||||
private function ignoreVersion($version)
|
||||
{
|
||||
if ($this->isValidSemVerFormat($version)) {
|
||||
$newData = [$this::JSON_FILE_IGNORED_KEY => [$version]];
|
||||
$existingData = file_exists(self::JSON_FILE_IGNORED) ? $this->readJsonFile(self::JSON_FILE_IGNORED) : [];
|
||||
|
||||
if (isset($existingData[self::JSON_FILE_IGNORED_KEY])) {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY][] = $version;
|
||||
} else {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY] = [$version];
|
||||
}
|
||||
|
||||
$this->writeJsonFile(self::JSON_FILE_IGNORED, $existingData);
|
||||
$this->respondWithSuccess($existingData);
|
||||
} else {
|
||||
$this->respondWithError(400, "Invalid version format");
|
||||
}
|
||||
}
|
||||
|
||||
private function isValidSemVerFormat($version)
|
||||
{
|
||||
return preg_match('/^\d+\.\d+(\.\d+)?(-.+)?$/', $version);
|
||||
}
|
||||
|
||||
private function readJsonFile($file)
|
||||
{
|
||||
return @json_decode(@file_get_contents($file), true) ?? [];
|
||||
}
|
||||
|
||||
private function writeJsonFile($file, $data)
|
||||
{
|
||||
if (!is_dir(dirname($file))) { // prevents errors when directory doesn't exist
|
||||
mkdir(dirname($file));
|
||||
}
|
||||
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
private function deleteJsonFile($file)
|
||||
{
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
private function respondWithError($statusCode, $message)
|
||||
{
|
||||
http_response_code($statusCode);
|
||||
echo $message;
|
||||
}
|
||||
|
||||
private function respondWithSuccess($data)
|
||||
{
|
||||
http_response_code(200);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data, JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate and handle the request for GET requests with actions – vars are duplicated here for multi-use of this file
|
||||
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
|
||||
if ($isGetRequest && $getHasAction) {
|
||||
new UnraidOsCheck();
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This file exists to maintain separation of concerns between UnraidCheck and ReplaceKey.
|
||||
* Instead of combining both classes directly, we utilize the unraidcheck script which already
|
||||
* handles both operations in a simplified manner.
|
||||
*
|
||||
* It's called via the WebguiCheckForUpdate function in composables/services/webgui.ts of the web components.
|
||||
* Handles WebguiUnraidCheckExecPayload interface parameters:
|
||||
* - altUrl?: string
|
||||
* - json?: boolean
|
||||
*/
|
||||
class UnraidCheckExec
|
||||
{
|
||||
private const SCRIPT_PATH = '/usr/local/emhttp/plugins/dynamix.plugin.manager/scripts/unraidcheck';
|
||||
private const ALLOWED_DOMAIN = 'releases.unraid.net';
|
||||
|
||||
private function setupEnvironment(): void
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
header('X-Frame-Options: DENY');
|
||||
header('Content-Security-Policy: default-src \'none\'');
|
||||
|
||||
$params = [
|
||||
'json' => 'true',
|
||||
];
|
||||
|
||||
if (isset($_GET['altUrl'])) {
|
||||
$url = filter_var($_GET['altUrl'], FILTER_VALIDATE_URL);
|
||||
if ($url !== false) {
|
||||
$host = parse_url($url, PHP_URL_HOST);
|
||||
$scheme = parse_url($url, PHP_URL_SCHEME);
|
||||
|
||||
if ($host && $scheme === 'https' && (
|
||||
$host === self::ALLOWED_DOMAIN ||
|
||||
str_ends_with($host, '.' . self::ALLOWED_DOMAIN)
|
||||
)) {
|
||||
$params['altUrl'] = $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
putenv('QUERY_STRING=' . http_build_query($params));
|
||||
}
|
||||
|
||||
public function execute(): string
|
||||
{
|
||||
// Validate script with all necessary permissions
|
||||
if (!is_file(self::SCRIPT_PATH) ||
|
||||
!is_readable(self::SCRIPT_PATH) ||
|
||||
!is_executable(self::SCRIPT_PATH)) {
|
||||
throw new RuntimeException('Script not found or not executable');
|
||||
}
|
||||
|
||||
$this->setupEnvironment();
|
||||
$output = [];
|
||||
$command = escapeshellcmd(self::SCRIPT_PATH);
|
||||
if (exec($command, $output) === false) {
|
||||
throw new RuntimeException('Script execution failed');
|
||||
}
|
||||
|
||||
return implode("\n", $output);
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
$checker = new UnraidCheckExec();
|
||||
echo $checker->execute();
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
class UnraidUpdateCancel
|
||||
{
|
||||
private $PLG_FILENAME;
|
||||
private $PLG_BOOT;
|
||||
private $PLG_VAR;
|
||||
private $USR_LOCAL_PLUGIN_UNRAID_PATH;
|
||||
|
||||
public function __construct() {
|
||||
$this->PLG_FILENAME = "unRAIDServer.plg";
|
||||
$this->PLG_BOOT = "/boot/config/plugins/{$this->PLG_FILENAME}";
|
||||
$this->PLG_VAR = "/var/log/plugins/{$this->PLG_FILENAME}";
|
||||
$this->USR_LOCAL_PLUGIN_UNRAID_PATH = "/usr/local/emhttp/plugins/unRAIDServer";
|
||||
|
||||
// Handle the cancellation
|
||||
$revertResult = $this->revertFiles();
|
||||
// Return JSON response for front-end client
|
||||
$statusCode = $revertResult['success'] ? 200 : 500;
|
||||
http_response_code($statusCode);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($revertResult);
|
||||
}
|
||||
|
||||
public function revertFiles() {
|
||||
try {
|
||||
$command = '/sbin/mount | grep -q "/boot/previous/bz"';
|
||||
exec($command, $output, $returnCode);
|
||||
|
||||
if ($returnCode !== 0) {
|
||||
return ['success' => true]; // Nothing to revert
|
||||
}
|
||||
|
||||
// Clear the results of previous unraidcheck run
|
||||
@unlink("/tmp/unraidcheck/result.json");
|
||||
|
||||
// Revert changes made by unRAIDServer.plg
|
||||
shell_exec("mv -f /boot/previous/* /boot");
|
||||
unlink($this->PLG_BOOT);
|
||||
unlink($this->PLG_VAR);
|
||||
symlink("{$this->USR_LOCAL_PLUGIN_UNRAID_PATH}/{$this->PLG_FILENAME}", $this->PLG_VAR);
|
||||
|
||||
// Restore README.md by echoing the content into the file
|
||||
$readmeFile = "{$this->USR_LOCAL_PLUGIN_UNRAID_PATH}/README.md";
|
||||
$readmeContent = "**Unraid OS**\n\n";
|
||||
$readmeContent .= "Unraid OS by [Lime Technology, Inc.](https://lime-technology.com).\n";
|
||||
file_put_contents($readmeFile, $readmeContent);
|
||||
|
||||
return ['success' => true]; // Upgrade handled successfully
|
||||
} catch (\Throwable $th) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $th->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Self instantiate the class and handle the cancellation
|
||||
new UnraidUpdateCancel();
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
|
||||
require_once "$docroot/plugins/dynamix/include/ReplaceKey.php";
|
||||
$replaceKey = new ReplaceKey();
|
||||
$replaceKey->check();
|
||||
|
||||
// utilized by UnraidCheckExec.php to have UnraidCheck.php return a json response when this script is called directly
|
||||
parse_str(getenv('QUERY_STRING') ?? '', $_GET);
|
||||
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
$unraidOsCheck = new UnraidOsCheck();
|
||||
$unraidOsCheck->checkForUpdate();
|
||||
@@ -1,237 +0,0 @@
|
||||
<?php
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
class ReplaceKey
|
||||
{
|
||||
private const KEY_SERVER_URL = 'https://keys.lime-technology.com';
|
||||
|
||||
private $docroot;
|
||||
private $var;
|
||||
private $guid;
|
||||
private $keyfile;
|
||||
private $regExp;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->docroot = $GLOBALS['docroot'] ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$this->var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
$this->guid = @$this->var['regGUID'] ?? null;
|
||||
|
||||
$keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
|
||||
if ($keyfileBase64 !== false) {
|
||||
$keyfileBase64 = @base64_encode($keyfileBase64);
|
||||
$this->keyfile = str_replace(['+', '/', '='], ['-', '_', ''], trim($keyfileBase64));
|
||||
}
|
||||
|
||||
$this->regExp = @$this->var['regExp'] ?? null;
|
||||
}
|
||||
|
||||
private function request($url, $method, $payload = null, $headers = null)
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
|
||||
// Set the request method
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
// store the response in a variable instead of printing it
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
// Set the payload if present
|
||||
if ($payload !== null) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
}
|
||||
|
||||
if ($headers !== null) {
|
||||
// Set the headers
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
}
|
||||
|
||||
// Set additional options as needed
|
||||
|
||||
// Execute the request
|
||||
$response = curl_exec($ch);
|
||||
|
||||
// Check for errors
|
||||
if (curl_errno($ch)) {
|
||||
$error = [
|
||||
'heading' => 'CurlError',
|
||||
'message' => curl_error($ch),
|
||||
'level' => 'error',
|
||||
'ref' => 'curlError',
|
||||
'type' => 'request',
|
||||
];
|
||||
// @todo store error
|
||||
}
|
||||
|
||||
// Close the cURL session
|
||||
curl_close($ch);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function validateGuid()
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
|
||||
$params = [
|
||||
'guid' => $this->guid,
|
||||
'keyfile' => $this->keyfile,
|
||||
];
|
||||
|
||||
/**
|
||||
* returns {JSON}
|
||||
* hasNewerKeyfile : boolean;
|
||||
* purchaseable: true;
|
||||
* registered: false;
|
||||
* replaceable: false;
|
||||
* upgradeable: false;
|
||||
* upgradeAllowed: string[];
|
||||
* updatesRenewable: false;
|
||||
*/
|
||||
$response = $this->request(
|
||||
self::KEY_SERVER_URL . '/validate/guid',
|
||||
'POST',
|
||||
http_build_query($params),
|
||||
$headers,
|
||||
);
|
||||
|
||||
// Handle the response as needed (parsing JSON, etc.)
|
||||
$decodedResponse = json_decode($response, true);
|
||||
|
||||
if (!empty($decodedResponse)) {
|
||||
return $decodedResponse;
|
||||
}
|
||||
|
||||
// @todo save error response somewhere
|
||||
return [];
|
||||
}
|
||||
|
||||
private function getLatestKey()
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
|
||||
$params = [
|
||||
'keyfile' => $this->keyfile,
|
||||
];
|
||||
|
||||
/**
|
||||
* returns {JSON}
|
||||
* license: string;
|
||||
*/
|
||||
$response = $this->request(
|
||||
self::KEY_SERVER_URL . '/key/latest',
|
||||
'POST',
|
||||
http_build_query($params),
|
||||
$headers,
|
||||
);
|
||||
|
||||
// Handle the response as needed (parsing JSON, etc.)
|
||||
$decodedResponse = json_decode($response, true);
|
||||
|
||||
if (!empty($decodedResponse) && !empty($decodedResponse['license'])) {
|
||||
return $decodedResponse['license'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function installNewKey($key)
|
||||
{
|
||||
require_once "$this->docroot/webGui/include/InstallKey.php";
|
||||
|
||||
$KeyInstaller = new KeyInstaller();
|
||||
$installResponse = $KeyInstaller->installKey($key);
|
||||
|
||||
$installSuccess = false;
|
||||
|
||||
if (!empty($installResponse)) {
|
||||
$decodedResponse = json_decode($installResponse, true);
|
||||
if (isset($decodedResponse['error'])) {
|
||||
$this->writeJsonFile(
|
||||
'/tmp/ReplaceKey/error.json',
|
||||
[
|
||||
'error' => $decodedResponse['error'],
|
||||
'ts' => time(),
|
||||
]
|
||||
);
|
||||
$installSuccess = false;
|
||||
} else {
|
||||
$installSuccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
$keyType = basename($key, '.key');
|
||||
$output = isset($GLOBALS['notify']) ? _var($GLOBALS['notify'],'plugin') : '';
|
||||
$script = '/usr/local/emhttp/webGui/scripts/notify';
|
||||
|
||||
if ($installSuccess) {
|
||||
$event = "Installed New $keyType License";
|
||||
$subject = "Your new $keyType license key has been automatically installed";
|
||||
$description = "";
|
||||
$importance = "normal $output";
|
||||
} else {
|
||||
$event = "Failed to Install New $keyType License";
|
||||
$subject = "Failed to automatically install your new $keyType license key";
|
||||
$description = isset($decodedResponse['error']) ? $decodedResponse['error'] : "Unknown error occurred";
|
||||
$importance = "alert $output";
|
||||
}
|
||||
|
||||
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg($importance)." -l '/Tools/Registration' -x");
|
||||
|
||||
return $installSuccess;
|
||||
}
|
||||
|
||||
private function writeJsonFile($file, $data)
|
||||
{
|
||||
if (!is_dir(dirname($file))) {
|
||||
mkdir(dirname($file));
|
||||
}
|
||||
|
||||
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
public function check(bool $forceCheck = false)
|
||||
{
|
||||
// we don't need to check
|
||||
if (empty($this->guid) || empty($this->keyfile) || empty($this->regExp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're within the 7-day window before and after regExp
|
||||
$now = time();
|
||||
$sevenDaysBefore = strtotime('-7 days', $this->regExp);
|
||||
$sevenDaysAfter = strtotime('+7 days', $this->regExp);
|
||||
|
||||
$isWithinWindow = ($now >= $sevenDaysBefore && $now <= $sevenDaysAfter);
|
||||
|
||||
if (!$forceCheck && !$isWithinWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// see if we have a new key
|
||||
$validateGuidResponse = $this->validateGuid();
|
||||
|
||||
$hasNewerKeyfile = @$validateGuidResponse['hasNewerKeyfile'] ?? false;
|
||||
if (!$hasNewerKeyfile) {
|
||||
return; // if there is no newer keyfile, we don't need to do anything
|
||||
}
|
||||
|
||||
$latestKey = $this->getLatestKey();
|
||||
if (!$latestKey) {
|
||||
// we supposedly have a new key, but didn't get it back…
|
||||
$this->writeJsonFile(
|
||||
'/tmp/ReplaceKey/error.json',
|
||||
[
|
||||
'error' => 'Failed to retrieve latest key after getting a `hasNewerKeyfile` in the validation response.',
|
||||
'ts' => time(),
|
||||
]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->installNewKey($latestKey);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
// This is a stub, does nothing but return success
|
||||
$cli = php_sapi_name()=='cli';
|
||||
if ($cli) {
|
||||
exit("success".PHP_EOL);
|
||||
}
|
||||
header('Content-Type: application/json');
|
||||
http_response_code(204);
|
||||
exit(0);
|
||||
?>
|
||||
Reference in New Issue
Block a user