mirror of
https://github.com/unraid/webgui.git
synced 2026-01-04 08:29:51 -06:00
Merge remote-tracking branch 'upstream/master' into New-VM-interface
This commit is contained in:
@@ -1203,7 +1203,7 @@ SSL certificate. Use this URL to access your server:
|
||||
Note that use of a self-signed SSL certificate will generate a browser
|
||||
warning.
|
||||
|
||||
Select **Strict** to enable *exclusive* use of an Unraid.net SSL
|
||||
Select **Strict** to enable *exclusive* use of a myunraid.net SSL
|
||||
certificate for https access (see **Provision** below). Note that a DNS
|
||||
server must be reachable.
|
||||
|
||||
@@ -1267,10 +1267,10 @@ To adjust URLs or redirects, see the help text for "Use SSL/TLS".
|
||||
:end
|
||||
|
||||
:mgmt_certificate_expiration_help:
|
||||
**Provision** may be used to install a *free* Unraid.net SSL Certificate from
|
||||
**Provision** may be used to install a *free* myunraid.net SSL Certificate from
|
||||
[Let's Encrypt](https://letsencrypt.org/).
|
||||
|
||||
The Unraid.net SSL certificate can be used in two ways. First,
|
||||
The myunraid.net SSL certificate can be used in two ways. First,
|
||||
having the certificate present enables your server to respond to an
|
||||
alternate URL of the form:
|
||||
|
||||
@@ -1284,24 +1284,20 @@ set to `*.<hash>.myunraid.net` thus validating the https connection.
|
||||
You may enable this URL exclusively on your LAN by setting **Use
|
||||
SSL/TLS** to **Strict**.
|
||||
|
||||
The second use for an Unraid.net certificate is to enable secure
|
||||
remote access available through the My Servers plugin feature. Note
|
||||
The second use for a myunraid.net certificate is to enable secure
|
||||
remote access available through the Unraid Connect plugin feature. Note
|
||||
that it is possible to use secure remote access in conjunction with
|
||||
insecure local access.
|
||||
|
||||
After an Unraid.net SSL Certificate has been installed, two
|
||||
background services are activated while the server is signed in to unraid.net:
|
||||
|
||||
- *updatedns* - This starts 30 seconds after server reboot has completed and contacts the Lime Technology
|
||||
DNS service to register the servers local IP address. Thereafter it wakes up every 10 minutes in case
|
||||
the local IP address has changed.
|
||||
After a myunraid.net SSL Certificate has been installed, a
|
||||
background service is activated:
|
||||
|
||||
- *renewcert* - This starts 60 seconds after server reboot has completed and contacts the Lime Technology
|
||||
certificate renewal service to determine if your Unraid.net SSL certificate needs to be renewed.
|
||||
certificate renewal service to determine if your myunraid.net SSL certificate needs to be renewed.
|
||||
Thereafter it wakes up every 24 hours. If within 30 days of expiration, a new certificate is automatically
|
||||
provisioned and downloaded to your server.
|
||||
|
||||
**Delete** may be used to delete the Unraid.net certificate file.
|
||||
**Delete** may be used to delete the myunraid.net certificate file.
|
||||
|
||||
**nginx certificate handling details**
|
||||
|
||||
@@ -1309,7 +1305,7 @@ nginx makes use of two certificate files stored on the USB flash boot device:<br
|
||||
|
||||
- a self-signed certificate: `config/ssl/certs/<server-name>_unraid_bundle.pem`
|
||||
|
||||
- an Unraid.net certificate: `config/ssl/certs/certificate_bundle.pem`
|
||||
- a myunraid.net certificate: `config/ssl/certs/certificate_bundle.pem`
|
||||
|
||||
The self-signed SSL certificate file is automatically created when nginx
|
||||
starts; and re-created if the server hostname or local TLD is changed.
|
||||
@@ -1493,7 +1489,7 @@ This will increase write performance but might possibly decrease read performanc
|
||||
Let the server act as a central syslog server and collect syslog messages from other systems.
|
||||
The server can listen on UDP, TCP or both with a selectable port number.
|
||||
|
||||
Syslog information is stored per IP address. That is every system gets its own syslog file.
|
||||
Syslog information is stored either per IP address or per hostname. That is every system gets its own syslog file.
|
||||
:end
|
||||
|
||||
:syslog_local_folder_help:
|
||||
@@ -1501,6 +1497,15 @@ Select the share folder where the syslogs will be stored.
|
||||
It is recommended that you use a share located on the cache drive to prevent array disk spinups.
|
||||
:end
|
||||
|
||||
:syslog_remote_system_identifier_help:
|
||||
Select the identifier for the remote system (used in the logfile name).
|
||||
|
||||
* "IP Address" uses the IP address (IPv4 or IPv6) of the sending system.
|
||||
* "Hostname (from syslog message)" uses the hostname included in each syslog message.
|
||||
* "Hostname (from DNS reverse lookup)" performs a DNS reverse lookup for the sending IP and uses the result.
|
||||
|
||||
:end
|
||||
|
||||
:syslog_local_rotation_help:
|
||||
By default LOG rotation is disabled and will create a single LOG file of unlimited size.
|
||||
|
||||
@@ -2493,7 +2498,7 @@ If set to 'Yes' the bash history will persist reboots, set to 'No' to disable.
|
||||
:WOL_intro_help:
|
||||
This page allows the setup to start/resume and stop VMs, Containters(Docker and LXC) using WOL magic packets
|
||||
|
||||
It does setup wake up of the Unraid server.
|
||||
It does not setup wake up of the Unraid server.
|
||||
|
||||
The process will look for the defined mac address defined within the service(VM or container) with the exception of dockers. Dockers do not have a mac address until they are running so you will need to define a user mac address to allow you to start them
|
||||
|
||||
@@ -2502,14 +2507,13 @@ If the service is paused a WOL Packet will resume.
|
||||
For each service you can set: enable, disable or enable and shutdown
|
||||
|
||||
When the enable and shutdown is set if the service is running when the next WOL packet is recieved a shutdown will be performed.
|
||||
|
||||
:end:
|
||||
:end
|
||||
|
||||
:WOL_enable_help:
|
||||
If set to yes Unraidwold daemon is set to run.
|
||||
:end
|
||||
|
||||
:WOL_docker_help:
|
||||
:WOL_run_docker_help:
|
||||
If set to yes when wake on lan packets are received checks are carrried out for dockers otherwise dockers will be ignored.
|
||||
:end
|
||||
|
||||
@@ -2535,4 +2539,4 @@ Enable to set the NIC not to filer packets.
|
||||
|
||||
:WOL_log_file_help:
|
||||
Default is to log to syslog but if you want a different log location set the file name.
|
||||
:end
|
||||
:end
|
||||
|
||||
@@ -111,6 +111,7 @@ function LockButton() {
|
||||
}
|
||||
function loadlist(init) {
|
||||
timers.docker = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
|
||||
docker = [];
|
||||
$.get('/plugins/dynamix.docker.manager/include/DockerContainers.php',function(d) {
|
||||
clearTimeout(timers.docker);
|
||||
var data = d.split(/\0/);
|
||||
|
||||
@@ -748,6 +748,7 @@ _(Categories)_:
|
||||
: <input type="hidden" name="contCategory">
|
||||
<select id="catSelect" size="1" multiple="multiple" style="display:none" onchange="prepareCategory();">
|
||||
<optgroup label="_(Categories)_">
|
||||
<option value="AI:">_(AI)_</option>
|
||||
<option value="Backup:">_(Backup)_</option>
|
||||
<option value="Cloud:">_(Cloud)_</option>
|
||||
<option value="Crypto:">_(Crypto Currency)_</option>
|
||||
|
||||
@@ -176,7 +176,7 @@ class DockerTemplates {
|
||||
}
|
||||
// if after above we don't have a valid url, check for GitLab
|
||||
if (empty($github_api['url'])) {
|
||||
$source = file_get_contents($url);
|
||||
$source = $this->download_url($url);
|
||||
// the following should always exist for GitLab Community Edition or GitLab Enterprise Edition
|
||||
if (preg_match("/<meta content='GitLab (Community|Enterprise) Edition' name='description'>/", $source) > 0) {
|
||||
$parse = parse_url($url);
|
||||
@@ -721,7 +721,7 @@ class DockerClient {
|
||||
$fp = stream_socket_client('unix:///var/run/docker.sock', $errno, $errstr);
|
||||
if ($fp === false) {
|
||||
echo "Couldn't create socket: [$errno] $errstr";
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
$protocol = $unchunk ? 'HTTP/1.0' : 'HTTP/1.1';
|
||||
$out = "$method {$api}{$url} $protocol\r\nHost:127.0.0.1\r\nConnection:Close\r\n";
|
||||
@@ -915,6 +915,7 @@ class DockerClient {
|
||||
$c['Volumes'] = $info['HostConfig']['Binds'];
|
||||
$c['Created'] = $this->humanTiming($ct['Created']);
|
||||
$c['NetworkMode'] = $ct['HostConfig']['NetworkMode'];
|
||||
$c['Manager'] = $info['Config']['Labels']['net.unraid.docker.managed'] ?? false;
|
||||
[$net, $id] = array_pad(explode(':',$c['NetworkMode']),2,'');
|
||||
$c['CPUset'] = $info['HostConfig']['CpusetCpus'];
|
||||
$c['BaseImage'] = $ct['Labels']['BASEIMAGE'] ?? false;
|
||||
@@ -978,7 +979,7 @@ class DockerClient {
|
||||
$c['Id'] = $this->extractID($ct['Id']);
|
||||
$c['ParentId'] = $this->extractID($ct['ParentId']);
|
||||
$c['Size'] = $this->formatBytes($ct['Size']);
|
||||
$c['VirtualSize'] = $this->formatBytes($ct['VirtualSize']);
|
||||
$c['VirtualSize'] = $this->formatBytes($ct['VirtualSize'] ?? null);
|
||||
$c['Tags'] = array_map('htmlspecialchars', $ct['RepoTags'] ?? []);
|
||||
$c['Repository'] = DockerUtil::parseImageTag($ct['RepoTags'][0]??'')['strRepo'];
|
||||
$c['usedBy'] = $this->usedBy($c['Id']);
|
||||
|
||||
@@ -120,20 +120,25 @@ foreach ($containers as $ct) {
|
||||
switch ($updateStatus) {
|
||||
case 0:
|
||||
echo "<span class='green-text' style='white-space:nowrap;'><i class='fa fa-check fa-fw'></i> "._('up-to-date')."</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
|
||||
break;
|
||||
case 1:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('update ready')."</span></div>";
|
||||
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('apply update')."</span></a>";
|
||||
break;
|
||||
case 2:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('rebuild ready')."</span></div>";
|
||||
echo "<a class='exec'><span style='white-space:nowrap;'><i class='fa fa-recycle fa-fw'></i> "._('rebuilding')."</span></a>";
|
||||
break;
|
||||
default:
|
||||
echo "<span class='orange-text' style='white-space:nowrap;'><i class='fa fa-unlink'></i> "._('not available')."</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
|
||||
if ($ct['Manager'] == "dockerman")
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
|
||||
break;
|
||||
case 1:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('update ready')."</span></div>";
|
||||
if ($ct['Manager'] == "dockerman")
|
||||
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('apply update')."</span></a>";
|
||||
else
|
||||
echo "<span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('update available')."</span>";
|
||||
break;
|
||||
case 2:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('rebuild ready')."</span></div>";
|
||||
echo "<a class='exec'><span style='white-space:nowrap;'><i class='fa fa-recycle fa-fw'></i> "._('rebuilding')."</span></a>";
|
||||
break;
|
||||
default:
|
||||
echo "<span class='orange-text' style='white-space:nowrap;'><i class='fa fa-unlink'></i> "._('not available')."</span>";
|
||||
if ($ct['Manager'] == "dockerman")
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
|
||||
break;
|
||||
}
|
||||
echo "<div class='advanced'><i class='fa fa-info-circle fa-fw'></i> ".compress(_($version),12,0)."</div></td>";
|
||||
echo "<td>{$ct['NetworkMode']}</td>";
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
<?
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
$ncsi = exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -o 'OK'")=='OK';
|
||||
$ncsi = check_network_connectivity();
|
||||
$DockerTemplates = new DockerTemplates();
|
||||
if ($ncsi) $DockerTemplates->downloadTemplates();
|
||||
$DockerTemplates->getAllInfo($ncsi,$ncsi);
|
||||
|
||||
@@ -270,6 +270,8 @@ function xmlToCommand($xml, $create_paths=false) {
|
||||
$Mode = strval($config['Mode']);
|
||||
if ($confType != "device" && !strlen($containerConfig)) continue;
|
||||
if ($confType == "path") {
|
||||
if ( ! trim($hostConfig) || ! trim($containerConfig) )
|
||||
continue;
|
||||
$Volumes[] = escapeshellarg($hostConfig).':'.escapeshellarg($containerConfig).':'.escapeshellarg($Mode);
|
||||
if (!file_exists($hostConfig) && $create_paths) {
|
||||
@mkdir($hostConfig, 0777, true);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -16,6 +16,7 @@
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
// Multi-language support
|
||||
@@ -43,7 +44,7 @@ if (!isset($check)) {
|
||||
$DockerTemplates->getAllInfo(true);
|
||||
echo " Done.";
|
||||
} else {
|
||||
$notify = "$docroot/webGui/scripts/notify";
|
||||
$script = "$docroot/webGui/scripts/notify";
|
||||
$var = (array)@parse_ini_file("/var/local/emhttp/var.ini");
|
||||
$server = strtoupper(_var($var,'NAME','tower'));
|
||||
$output = _var($notify,'docker_notify');
|
||||
@@ -59,7 +60,7 @@ if (!isset($check)) {
|
||||
$event = str_replace("'","'",_("Docker")." - $name [$new]");
|
||||
$subject = str_replace("'","'",sprintf(_("Notice [%s] - Version update %s"),$server,$new));
|
||||
$description = str_replace("'","'",sprintf(_("A new version of %s is available"),$name));
|
||||
exec("$notify -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Docker' -x");
|
||||
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Docker' -x");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,7 @@ if (!document.getElementsByTagName(modalsWebComponent).length) {
|
||||
$i18nHost.appendChild($modals);
|
||||
}
|
||||
</script>
|
||||
<?
|
||||
echo "
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-user-profile server='" . $serverState->getServerStateJson() . "'></unraid-user-profile>
|
||||
</unraid-i18n-host>";
|
||||
<unraid-user-profile server="<?= $serverState->getServerStateJsonForHtmlAttr() ?>"></unraid-user-profile>
|
||||
</unraid-i18n-host>
|
||||
|
||||
@@ -34,11 +34,20 @@ class ServerState
|
||||
protected $webguiGlobals;
|
||||
|
||||
private $var;
|
||||
private $flashbackupCfg;
|
||||
private $apiKey = '';
|
||||
private $apiVersion = '';
|
||||
private $avatar = '';
|
||||
private $email = '';
|
||||
private $extraOrigins = [];
|
||||
private $flashBackupActivated = '';
|
||||
private $hasRemoteApikey = false;
|
||||
private $registeredTime = '';
|
||||
private $username = '';
|
||||
private $connectPluginInstalled = '';
|
||||
private $connectPluginVersion;
|
||||
private $configErrorEnum = [
|
||||
"error" => 'UNKNOWN_ERROR',
|
||||
"ineligible" => 'INELIGIBLE',
|
||||
"invalid" => 'INVALID',
|
||||
"nokeyserver" => 'NO_KEY_SERVER',
|
||||
"withdrawn" => 'WITHDRAWN',
|
||||
@@ -58,9 +67,9 @@ class ServerState
|
||||
public $host = 'unknown';
|
||||
public $combinedKnownOrigins = [];
|
||||
|
||||
public $nginxCfg;
|
||||
public $flashbackupStatus;
|
||||
public $registered;
|
||||
public $nginxCfg = [];
|
||||
public $flashbackupStatus = [];
|
||||
public $registered = false;
|
||||
public $myServersMiniGraphConnected = false;
|
||||
public $keyfileBase64 = '';
|
||||
|
||||
@@ -78,11 +87,42 @@ class ServerState
|
||||
// echo "<pre>" . json_encode($this->webguiGlobals, JSON_PRETTY_PRINT) . "</pre>";
|
||||
|
||||
$this->var = (array)parse_ini_file('state/var.ini');
|
||||
$this->nginxCfg = parse_ini_file('/var/local/emhttp/nginx.ini');
|
||||
$this->nginxCfg = @parse_ini_file('/var/local/emhttp/nginx.ini') ?? [];
|
||||
|
||||
$this->flashbackupCfg = '/var/local/emhttp/flashbackup.ini';
|
||||
$this->flashbackupStatus = (file_exists($this->flashbackupCfg)) ? @parse_ini_file($this->flashbackupCfg) : [];
|
||||
$this->osVersion = $this->var['version'];
|
||||
$this->osVersionBranch = trim(@exec('plugin category /var/log/plugins/unRAIDServer.plg') ?? 'stable');
|
||||
|
||||
$caseModelFile = '/boot/config/plugins/dynamix/case-model.cfg';
|
||||
$this->caseModel = file_exists($caseModelFile) ? file_get_contents($caseModelFile) : '';
|
||||
|
||||
$this->rebootDetails = new RebootDetails();
|
||||
|
||||
$this->keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
|
||||
if ($this->keyfileBase64 !== false) {
|
||||
$this->keyfileBase64 = @base64_encode($this->keyfileBase64);
|
||||
$this->keyfileBase64UrlSafe = str_replace(['+', '/', '='], ['-', '_', ''], trim($this->keyfileBase64));
|
||||
}
|
||||
|
||||
$this->updateOsCheck = new UnraidOsCheck();
|
||||
$this->updateOsIgnoredReleases = $this->updateOsCheck->getIgnoredReleases();
|
||||
$this->updateOsNotificationsEnabled = !empty(@$this->getWebguiGlobal('notify', 'unraidos'));
|
||||
$this->updateOsResponse = $this->updateOsCheck->getUnraidOSCheckResult();
|
||||
|
||||
$this->setConnectValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value of a webgui global setting.
|
||||
*/
|
||||
public function getWebguiGlobal(string $key, string $subkey = null) {
|
||||
if (!$subkey) {
|
||||
return _var($this->webguiGlobals, $key, '');
|
||||
}
|
||||
$keyArray = _var($this->webguiGlobals, $key, []);
|
||||
return _var($keyArray, $subkey, '');
|
||||
}
|
||||
|
||||
private function setConnectValues() {
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) {
|
||||
$this->connectPluginInstalled = 'dynamix.unraid.net.plg';
|
||||
}
|
||||
@@ -93,11 +133,29 @@ class ServerState
|
||||
$this->connectPluginInstalled .= '_installFailed';
|
||||
}
|
||||
|
||||
// exit early if the plugin is not installed
|
||||
if (!$this->connectPluginInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->connectPluginVersion = file_exists('/var/log/plugins/dynamix.unraid.net.plg')
|
||||
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
|
||||
: (file_exists('/var/log/plugins/dynamix.unraid.net.staging.plg')
|
||||
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
|
||||
: 'base-' . $this->var['version']);
|
||||
|
||||
$this->getMyServersCfgValues();
|
||||
$this->getConnectKnownOrigins();
|
||||
$this->getFlashBackupStatus();
|
||||
}
|
||||
|
||||
private function getFlashBackupStatus() {
|
||||
$flashbackupCfg = '/var/local/emhttp/flashbackup.ini';
|
||||
$this->flashbackupStatus = (file_exists($flashbackupCfg)) ? @parse_ini_file($flashbackupCfg) : [];
|
||||
$this->flashBackupActivated = empty($this->flashbackupStatus['activated']) ? '' : 'true';
|
||||
}
|
||||
|
||||
private function getMyServersCfgValues() {
|
||||
/**
|
||||
* @todo can we read this from somewhere other than the flash? Connect page uses this path and /boot/config/plugins/dynamix.my.servers/myservers.cfg…
|
||||
* - $myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg';
|
||||
@@ -122,15 +180,17 @@ class ServerState
|
||||
$this->myServersFlashCfg['remote']['dynamicRemoteAccessType'] = "DISABLED";
|
||||
}
|
||||
|
||||
$this->osVersion = $this->var['version'];
|
||||
$this->osVersionBranch = trim(@exec('plugin category /var/log/plugins/unRAIDServer.plg') ?? 'stable');
|
||||
$this->apiKey = $this->myServersFlashCfg['upc']['apikey'] ?? '';
|
||||
$this->apiVersion = $this->myServersFlashCfg['api']['version'] ?? '';
|
||||
$this->avatar = (!empty($this->myServersFlashCfg['remote']['avatar']) && $this->connectPluginInstalled) ? $this->myServersFlashCfg['remote']['avatar'] : '';
|
||||
$this->email = $this->myServersFlashCfg['remote']['email'] ?? '';
|
||||
$this->hasRemoteApikey = !empty($this->myServersFlashCfg['remote']['apikey']);
|
||||
$this->registered = !empty($this->myServersFlashCfg['remote']['apikey']) && $this->connectPluginInstalled;
|
||||
$this->registeredTime = $this->myServersFlashCfg['remote']['regWizTime'] ?? '';
|
||||
$this->username = $this->myServersFlashCfg['remote']['username'] ?? '';
|
||||
}
|
||||
|
||||
$caseModelFile = '/boot/config/plugins/dynamix/case-model.cfg';
|
||||
$this->caseModel = file_exists($caseModelFile) ? file_get_contents($caseModelFile) : '';
|
||||
|
||||
$this->rebootDetails = new RebootDetails();
|
||||
|
||||
private function getConnectKnownOrigins() {
|
||||
/**
|
||||
* Allowed origins warning displayed when the current webGUI URL is NOT included in the known lists of allowed origins.
|
||||
* Include localhost in the test, but only display HTTP(S) URLs that do not include localhost.
|
||||
@@ -145,6 +205,11 @@ class ServerState
|
||||
$combinedOrigins = $allowedOrigins . "," . $extraOrigins; // combine the two strings for easier searching
|
||||
$combinedOrigins = str_replace(" ", "", $combinedOrigins); // replace any spaces with nothing
|
||||
$hostNotKnown = stripos($combinedOrigins, $this->host) === false; // check if the current host is in the combined list of origins
|
||||
|
||||
if ($extraOrigins) {
|
||||
$this->extraOrigins = explode(",", $extraOrigins);
|
||||
}
|
||||
|
||||
if ($hostNotKnown) {
|
||||
$this->combinedKnownOrigins = explode(",", $combinedOrigins);
|
||||
|
||||
@@ -161,29 +226,8 @@ class ServerState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
|
||||
if ($this->keyfileBase64 !== false) {
|
||||
$this->keyfileBase64 = @base64_encode($this->keyfileBase64);
|
||||
$this->keyfileBase64UrlSafe = str_replace(['+', '/', '='], ['-', '_', ''], trim($this->keyfileBase64));
|
||||
}
|
||||
|
||||
$this->updateOsCheck = new UnraidOsCheck();
|
||||
$this->updateOsIgnoredReleases = $this->updateOsCheck->getIgnoredReleases();
|
||||
$this->updateOsNotificationsEnabled = !empty(@$this->getWebguiGlobal('notify', 'unraidos'));
|
||||
$this->updateOsResponse = $this->updateOsCheck->getUnraidOSCheckResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value of a webgui global setting.
|
||||
*/
|
||||
public function getWebguiGlobal(string $key, string $subkey = null) {
|
||||
if (!$subkey) {
|
||||
return _var($this->webguiGlobals, $key, '');
|
||||
}
|
||||
$keyArray = _var($this->webguiGlobals, $key, []);
|
||||
return _var($keyArray, $subkey, '');
|
||||
}
|
||||
/**
|
||||
* Retrieve the server information as an associative array
|
||||
*
|
||||
@@ -192,13 +236,13 @@ class ServerState
|
||||
public function getServerState()
|
||||
{
|
||||
$serverState = [
|
||||
"apiKey" => $this->myServersFlashCfg['upc']['apikey'] ?? '',
|
||||
"apiVersion" => $this->myServersFlashCfg['api']['version'] ?? '',
|
||||
"avatar" => (!empty($this->myServersFlashCfg['remote']['avatar']) && $this->connectPluginInstalled) ? $this->myServersFlashCfg['remote']['avatar'] : '',
|
||||
"apiKey" => $this->apiKey,
|
||||
"apiVersion" => $this->apiVersion,
|
||||
"avatar" => $this->avatar,
|
||||
"caseModel" => $this->caseModel,
|
||||
"config" => [
|
||||
'valid' => ($this->var['configValid'] === 'yes'),
|
||||
'error' => isset($this->configErrorEnum[$this->var['configValid']]) ? $this->configErrorEnum[$this->var['configValid']] : 'UNKNOWN_ERROR',
|
||||
'error' => isset($this->configErrorEnum[$this->var['configValid']]) ? $this->configErrorEnum[$this->var['configValid']] : null,
|
||||
],
|
||||
"connectPluginInstalled" => $this->connectPluginInstalled,
|
||||
"connectPluginVersion" => $this->connectPluginVersion,
|
||||
@@ -207,35 +251,35 @@ class ServerState
|
||||
"date" => @$this->getWebguiGlobal('display', 'date') ?? '',
|
||||
"time" => @$this->getWebguiGlobal('display', 'time') ?? '',
|
||||
],
|
||||
"description" => $this->var['COMMENT'] ? htmlspecialchars($this->var['COMMENT']) : '',
|
||||
"description" => $this->var['COMMENT'] ? htmlspecialchars($this->var['COMMENT'], ENT_HTML5, 'UTF-8') : '',
|
||||
"deviceCount" => $this->var['deviceCount'],
|
||||
"email" => $this->myServersFlashCfg['remote']['email'] ?? '',
|
||||
"email" => $this->email,
|
||||
"expireTime" => 1000 * (($this->var['regTy'] === 'Trial' || strstr($this->var['regTy'], 'expired')) ? $this->var['regTm2'] : 0),
|
||||
"extraOrigins" => explode(',', $this->myServersFlashCfg['api']['extraOrigins'] ?? ''),
|
||||
"extraOrigins" => $this->extraOrigins,
|
||||
"flashProduct" => $this->var['flashProduct'],
|
||||
"flashVendor" => $this->var['flashVendor'],
|
||||
"flashBackupActivated" => empty($this->flashbackupStatus['activated']) ? '' : 'true',
|
||||
"flashBackupActivated" => $this->flashBackupActivated,
|
||||
"guid" => $this->var['flashGUID'],
|
||||
"hasRemoteApikey" => !empty($this->myServersFlashCfg['remote']['apikey']),
|
||||
"hasRemoteApikey" => $this->hasRemoteApikey,
|
||||
"internalPort" => _var($_SERVER, 'SERVER_PORT'),
|
||||
"keyfile" => $this->keyfileBase64UrlSafe,
|
||||
"lanIp" => ipaddr(),
|
||||
"locale" => (!empty($_SESSION) && $_SESSION['locale']) ? $_SESSION['locale'] : 'en_US',
|
||||
"model" => $this->var['SYS_MODEL'],
|
||||
"name" => htmlspecialchars($this->var['NAME']),
|
||||
"model" => $this->var['SYS_MODEL'] ? htmlspecialchars($this->var['SYS_MODEL'], ENT_HTML5, 'UTF-8') : '',
|
||||
"name" => htmlspecialchars($this->var['NAME'], ENT_HTML5, 'UTF-8'),
|
||||
"osVersion" => $this->osVersion,
|
||||
"osVersionBranch" => $this->osVersionBranch,
|
||||
"protocol" => _var($_SERVER, 'REQUEST_SCHEME'),
|
||||
"rebootType" => $this->rebootDetails->getRebootType(),
|
||||
"regDev" => @(int)$this->var['regDev'] ?? 0,
|
||||
"regDevs" => @(int)$this->var['regDevs'] ?? 0,
|
||||
"regGen" => @(int)$this->var['regGen'],
|
||||
"regGuid" => @$this->var['regGUID'] ?? '',
|
||||
"regTo" => @htmlspecialchars($this->var['regTo']) ?? '',
|
||||
"regTo" => @htmlspecialchars($this->var['regTo'], ENT_HTML5, 'UTF-8') ?? '',
|
||||
"regTm" => $this->var['regTm'] ? @$this->var['regTm'] * 1000 : '', // JS expects milliseconds
|
||||
"regTy" => @$this->var['regTy'] ?? '',
|
||||
"regExp" => $this->var['regExp'] ? @$this->var['regExp'] * 1000 : '', // JS expects milliseconds
|
||||
"registered" => $this->registered,
|
||||
"registeredTime" => $this->myServersFlashCfg['remote']['regWizTime'] ?? '',
|
||||
"registeredTime" => $this->registeredTime,
|
||||
"site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'),
|
||||
"state" => strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']),
|
||||
"theme" => [
|
||||
@@ -249,8 +293,8 @@ class ServerState
|
||||
],
|
||||
"ts" => time(),
|
||||
"uptime" => 1000 * (time() - round(strtok(exec("cat /proc/uptime"), ' '))),
|
||||
"username" => $this->myServersFlashCfg['remote']['username'] ?? '',
|
||||
"wanFQDN" => $this->nginxCfg['NGINX_WANFQDN'] ?? '',
|
||||
"username" => $this->username,
|
||||
"wanFQDN" => @$this->nginxCfg['NGINX_WANFQDN'] ?? '',
|
||||
];
|
||||
|
||||
if ($this->combinedKnownOrigins) {
|
||||
@@ -273,11 +317,21 @@ class ServerState
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information as a JSON string
|
||||
* Retrieve the server information as JSON
|
||||
*
|
||||
* @return string A JSON string containing server information.
|
||||
* @return string
|
||||
*/
|
||||
public function getServerStateJson() {
|
||||
return json_encode($this->getServerState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information as JSON string with converted special characters to HTML entities
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerStateJsonForHtmlAttr() {
|
||||
$json = json_encode($this->getServerState());
|
||||
return htmlspecialchars($json, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,13 +72,13 @@ class WebComponentTranslations
|
||||
'<p>To continue using Unraid OS you may purchase a license key. Alternately, you may request a Trial extension.</p>' => '<p>' . _('To continue using Unraid OS you may purchase a license key.') . ' ' . _('Alternately, you may request a Trial extension.') . '</p>',
|
||||
'<p>To support more storage devices as your server grows, click Upgrade Key.</p>' => '<p>' . _('To support more storage devices as your server grows, click Upgrade Key.') . '</p>',
|
||||
'<p>You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.</p>' => '<p>' . _('You have used all your Trial extensions.') . ' ' . _('To continue using Unraid OS you may purchase a license key.') . '</p>',
|
||||
'<p>Your <em>Trial</em> key includes all the functionality and device support of a <em>Pro</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>' => '<p>' . _('Your **Trial** key includes all the functionality and device support of a **Pro** key') . '</p><p>' . _('After your **Trial** has reached expiration, your server *still functions normally* until the next time you Stop the array or reboot your server') . '</p><p>' . _('At that point you may either purchase a license key or request a *Trial* extension.') . '</p>',
|
||||
'<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>' => '<p>' . _('Your **Trial** key includes all the functionality and device support of an **Unleashed** key') . '</p><p>' . _('After your **Trial** has reached expiration, your server *still functions normally* until the next time you Stop the array or reboot your server') . '</p><p>' . _('At that point you may either purchase a license key or request a *Trial* extension.') . '</p>',
|
||||
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>If you do not have a backup copy of your license key file you may attempt to recover your key.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
|
||||
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>You may attempt to recover your key with your Unraid.net account.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
|
||||
'<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of a Pro Registration key.</p><p>Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class="list-disc pl-16px"><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>' => '<p>' . _('Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key.') . ' ' . _('A <em>Trial</em> key provides all the functionality of a Pro Registration key.') . '</p><p>' . _('Registration keys are bound to your USB Flash boot device serial number (GUID).') . ' ' . _('Please use a high quality name brand device at least 1GB in size.') . '</p><p>' . _('Note: USB memory card readers are generally not supported because most do not present unique serial numbers.') . '</p><p>' . _('*Important:*') . '</p><ul class="list-disc pl-16px"><li>' . _('Please make sure your server time is accurate to within 5 minutes') . '</li><li>' . _('Please make sure there is a DNS server specified') . '</li>>' . '</ul>',
|
||||
'<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.</p><p>Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class="list-disc pl-16px"><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>' => '<p>' . _('Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key.') . ' ' . _('A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.') . '</p><p>' . _('Registration keys are bound to your USB Flash boot device serial number (GUID).') . ' ' . _('Please use a high quality name brand device at least 1GB in size.') . '</p><p>' . _('Note: USB memory card readers are generally not supported because most do not present unique serial numbers.') . '</p><p>' . _('*Important:*') . '</p><ul class="list-disc pl-16px"><li>' . _('Please make sure your server time is accurate to within 5 minutes') . '</li><li>' . _('Please make sure there is a DNS server specified') . '</li>>' . '</ul>',
|
||||
'<p>Your Trial key requires an internet connection.</p><p><a href="/Settings/NetworkSettings" class="underline">Please check Settings > Network</a></p>' => '<p>' . _('Your Trial key requires an internet connection') . '</p><p><a href="/Settings/NetworkSettings" class="underline">' . _('Please check Settings > Network') . '</a></p>',
|
||||
'<p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
|
||||
'A Trial key provides all the functionality of a Pro Registration key' => _('A Trial key provides all the functionality of a Pro Registration key'),
|
||||
'A Trial key provides all the functionality of an Unleashed Registration key' => _('A Trial key provides all the functionality of an Unleashed Registration key'),
|
||||
'Acklowledge that you have made a Flash Backup to enable this action' => _('Acklowledge that you have made a Flash Backup to enable this action'),
|
||||
'ago' => _('ago'),
|
||||
'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin.') . ' ' . _('Get started by installing the plugin.'),
|
||||
@@ -339,7 +339,7 @@ class WebComponentTranslations
|
||||
'You may still update to releases dated prior to your update expiration date.' => _('You may still update to releases dated prior to your update expiration date.'),
|
||||
'You\'re one step closer to enhancing your Unraid experience' => _('You\'re one step closer to enhancing your Unraid experience'),
|
||||
'Your {0} Key has been replaced!' => sprintf(_('Your %s Key has been replaced!'), '{0}'),
|
||||
'Your free Trial key provides all the functionality of a Pro Registration key' => _('Your free Trial key provides all the functionality of a Pro Registration key'),
|
||||
'Your free Trial key provides all the functionality of an Unleashed Registration key' => _('Your free Trial key provides all the functionality of an Unleashed Registration key'),
|
||||
'Your Trial has expired' => _('Your Trial has expired'),
|
||||
'Your Trial key has been extended!' => _('Your Trial key has been extended!'),
|
||||
];
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -7,7 +7,7 @@
|
||||
"css": [
|
||||
"_nuxt/unraid-components.client-fad7c220.css"
|
||||
],
|
||||
"file": "_nuxt/unraid-components.client-437ee6ff.js",
|
||||
"file": "_nuxt/unraid-components.client-cd1b3939.js",
|
||||
"isEntry": true,
|
||||
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs"
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
// Invoke the plugin command with indicated method
|
||||
function plugin($method, $arg = '') {
|
||||
global $docroot;
|
||||
@@ -27,7 +30,7 @@ function language($method, $arg = '') {
|
||||
|
||||
function check_plugin($arg, &$ncsi) {
|
||||
// Get network connection status indicator (NCSI)
|
||||
if ($ncsi===null) $ncsi = exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -o 'OK'");
|
||||
if ($ncsi===null) $ncsi = check_network_connectivity();
|
||||
return $ncsi ? plugin('check',$arg) : false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* 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,
|
||||
@@ -108,6 +108,7 @@ class UnraidOsCheck
|
||||
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');
|
||||
@@ -115,7 +116,7 @@ class UnraidOsCheck
|
||||
$params = [];
|
||||
$params['branch'] = plugin('category', self::PLG_PATH, 'stable');
|
||||
$params['current_version'] = plugin('version', self::PLG_PATH) ?: _var($var,'version');
|
||||
if (_var($var,'regExp')) $params['update_exp'] = date('m-d-Y', _var($var,'regExp')*1);
|
||||
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;
|
||||
@@ -123,21 +124,12 @@ class UnraidOsCheck
|
||||
if ($parsedAltUrl) $params['altUrl'] = $parsedAltUrl;
|
||||
|
||||
$urlbase = $parsedAltUrl ?? $defaultUrl;
|
||||
$url = $urlbase.'?'.http_build_query($params);
|
||||
|
||||
$response = "";
|
||||
// use error handler to convert warnings from file_get_contents to errors so they can be captured
|
||||
function warning_as_error($severity, $message, $filename, $lineno) {
|
||||
throw new ErrorException($message, 0, $severity, $filename, $lineno);
|
||||
$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);
|
||||
}
|
||||
set_error_handler("warning_as_error");
|
||||
try {
|
||||
$response = file_get_contents($url);
|
||||
} catch (Exception $e) {
|
||||
$response = json_encode(array('error' => $e->getMessage()), JSON_PRETTY_PRINT);
|
||||
}
|
||||
restore_error_handler();
|
||||
|
||||
$responseMutated = json_decode($response, true);
|
||||
if (!$responseMutated) {
|
||||
$response = json_encode(array('error' => 'Invalid response from '.$urlbase), JSON_PRETTY_PRINT);
|
||||
@@ -159,14 +151,17 @@ class UnraidOsCheck
|
||||
|
||||
// send notification if a newer version is available and not ignored
|
||||
$isNewerVersion = array_key_exists('isNewer',$responseMutated) ? $responseMutated['isNewer'] : false;
|
||||
$isReleaseIgnored = in_array($responseMutated['version'], $this->getIgnoredReleases());
|
||||
$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';
|
||||
exec("$script -e ".escapeshellarg("System - Unraid [$newver]")." -s ".escapeshellarg("Notice [$server] - Version update $newver")." -d ".escapeshellarg("A new version of Unraid is available")." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
|
||||
$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);
|
||||
|
||||
@@ -44,7 +44,7 @@ function write(...$messages){
|
||||
}
|
||||
|
||||
write(_("Checking connectivity")." ...\n");
|
||||
if (exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -om1 'OK'")) {
|
||||
if (check_network_connectivity()) {
|
||||
$check = popen('plugin checkall','r');
|
||||
while (!feof($check)) write(fgets($check));
|
||||
pclose($check);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* 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,
|
||||
@@ -15,6 +15,7 @@
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
// Multi-language support
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* 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,
|
||||
@@ -15,6 +15,7 @@
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
|
||||
// Multi-language support
|
||||
|
||||
@@ -49,7 +49,7 @@ function showCPUs($uuid) {
|
||||
function vsize($size,$expand=true) {
|
||||
$units = ['','K','M','G','T','P','E','Z','Y'];
|
||||
if ($expand) {
|
||||
$size = str_replace(['B',' ',',', '.'],'',strtoupper($size));
|
||||
$size = str_replace(['B',' ',','],'',strtoupper($size));
|
||||
[$c1,$c2] = my_preg_split('/(?<=[0-9])(?=[A-Z])/',$size);
|
||||
return $c1 * pow(1024,array_search($c2,$units)?:0);
|
||||
} else {
|
||||
|
||||
@@ -52,7 +52,7 @@ foreach ($vms as $vm) {
|
||||
$image = substr($icon,-4)=='.png' ? "<img src='$icon' class='img'>" : (substr($icon,0,5)=='icon-' ? "<i class='$icon img'></i>" : "<i class='fa fa-$icon img'></i>");
|
||||
$arrConfig = domain_to_config($uuid);
|
||||
$snapshots = getvmsnapshots($vm) ;
|
||||
$cdroms = $lv->get_cdrom_stats($res) ;
|
||||
$cdroms = $lv->get_cdrom_stats($res,true,true) ;
|
||||
if ($state == 'running') {
|
||||
$mem = $dom['memory']/1024;
|
||||
} else {
|
||||
@@ -214,7 +214,7 @@ foreach ($vms as $vm) {
|
||||
$boot= $arrDisk["boot order"];
|
||||
$serial = $arrDisk["serial"];
|
||||
if ($boot < 1) $boot = _('Not set');
|
||||
$reallocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($disk)." 2>/dev/null"));
|
||||
$reallocation = trim(get_realvolume($disk));
|
||||
if (!empty($reallocation)) $reallocationstr = "($reallocation)"; else $reallocationstr = "";
|
||||
echo "<tr><td>$disk $reallocationstr</td><td>$serial</td><td>$bus</td>";
|
||||
if ($state == 'shutoff') {
|
||||
@@ -236,8 +236,10 @@ foreach ($vms as $vm) {
|
||||
|
||||
/* Display VM cdroms */
|
||||
foreach ($cdroms as $arrCD) {
|
||||
$tooltip = "";
|
||||
$capacity = $lv->format_size($arrCD['capacity'], 0);
|
||||
$allocation = $lv->format_size($arrCD['allocation'], 0);
|
||||
if ($arrCD['spundown']) {$capacity = $allocation = "*"; $tooltip = "Drive spun down ISO volume is ".$arrCD['reallocation'];} else $tooltip = "ISO volume is ".$arrCD['reallocation'];
|
||||
$disk = $arrCD['file'] ?? $arrCD['partition'] ?? "" ;
|
||||
$dev = $arrCD['device'];
|
||||
$bus = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
|
||||
@@ -246,7 +248,7 @@ foreach ($vms as $vm) {
|
||||
if ($disk != "" ) {
|
||||
$title = _('Eject CD Drive');
|
||||
$changemedia = "changemedia(\"{$uuid}\",\"{$dev}\",\"{$bus}\", \"--eject\")";
|
||||
echo "<tr><td>$disk <a title='$title' href='#' onclick='$changemedia'> <i class='fa fa-eject'></i></a></td><td></td><td>$bus</td><td>$capacity</td><td>$allocation</td><td>$boot</td></tr>";
|
||||
echo "<tr><td>$disk <a title='$title' href='#' onclick='$changemedia'> <i class='fa fa-eject'></i></a></td><td></td><td>$bus</td><td><span title='$tooltip' data-toggle='tooltip'>$capacity</span></td><td>$allocation</td><td>$boot</td></tr>";
|
||||
} else {
|
||||
$title = _('Insert CD');
|
||||
$changemedia = "changemedia(\"{$uuid}\",\"{$dev}\",\"{$bus}\",\"--select\")";
|
||||
|
||||
@@ -1250,33 +1250,44 @@
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
function get_cdrom_stats($domain, $sort=true) {
|
||||
function get_cdrom_stats($domain, $sort=true,$spincheck = false) {
|
||||
$unraiddisks = array_merge_recursive(@parse_ini_file('state/disks.ini',true)?:[], @parse_ini_file('state/devs.ini',true)?:[]);
|
||||
$dom = $this->get_domain_object($domain);
|
||||
|
||||
$tmp = false;
|
||||
$buses = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/target/@bus', false);
|
||||
$disks = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/target/@dev', false);
|
||||
$cds = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/target/@dev', false);
|
||||
$files = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/source/@file', false);
|
||||
$boot = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/boot/@*', false);
|
||||
|
||||
$ret = [];
|
||||
for ($i = 0; $i < $disks['num']; $i++) {
|
||||
$tmp = libvirt_domain_get_block_info($dom, $disks[$i]);
|
||||
for ($i = 0; $i < $cds['num']; $i++) {
|
||||
$spundown = 0;
|
||||
$reallocation = null;
|
||||
if (isset($files[$i])) $reallocation = trim(get_realvolume($files[$i]));
|
||||
if ($spincheck) {
|
||||
if (isset($unraiddisks[$reallocation]['spundown']) && $unraiddisks[$reallocation]['spundown'] == 1) $spundown = 1; else $tmp = libvirt_domain_get_block_info($dom, $cds[$i]);
|
||||
} else $tmp = libvirt_domain_get_block_info($dom, $cds[$i]);
|
||||
|
||||
if ($tmp) {
|
||||
$tmp['bus'] = $buses[$i];
|
||||
$tmp["boot order"] = $boot[$i] ?? "";
|
||||
$tmp['reallocation'] = $reallocation;
|
||||
$tmp['spundown'] = $spundown;
|
||||
$ret[] = $tmp;
|
||||
}
|
||||
else {
|
||||
$this->_set_last_error();
|
||||
|
||||
$ret[] = [
|
||||
'device' => $disks[$i],
|
||||
'device' => $cds[$i],
|
||||
'file' => $files[$i],
|
||||
'type' => '-',
|
||||
'capacity' => '-',
|
||||
'allocation' => '-',
|
||||
'physical' => '-',
|
||||
'bus' => $buses[$i]
|
||||
'bus' => $buses[$i],
|
||||
'reallocation' => $reallocation,
|
||||
'spundown' => $spundown
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1294,7 +1305,7 @@
|
||||
}
|
||||
|
||||
unset($buses);
|
||||
unset($disks);
|
||||
unset($cds);
|
||||
unset($files);
|
||||
|
||||
return $ret;
|
||||
@@ -1462,7 +1473,7 @@
|
||||
$unit = strtoupper($unit);
|
||||
|
||||
switch ($unit) {
|
||||
case 'T': return number_format($value / (float)1099511627776, $decimals).'T';
|
||||
case 'T': return number_format($value / (float)1099511627776, $decimals +2).'T';
|
||||
case 'G': return number_format($value / (float)(1 << 30), $decimals).'G';
|
||||
case 'M': return number_format($value / (float)(1 << 20), $decimals).'M';
|
||||
case 'K': return number_format($value / (float)(1 << 10), $decimals).'K';
|
||||
|
||||
@@ -2527,6 +2527,7 @@ function addtemplatexml($post) {
|
||||
'os' => $usertemplate['template']['os'],
|
||||
'overrides' => $usertemplate
|
||||
];
|
||||
if (!is_dir(dirname($templateslocation))) mkdir(dirname($templateslocation));
|
||||
file_put_contents($templateslocation,json_encode($savedtemplates,JSON_PRETTY_PRINT));
|
||||
$reply = ['success' => true];
|
||||
|
||||
|
||||
58
emhttp/plugins/dynamix.vm.manager/scripts/virtiofsd.php
Executable file
58
emhttp/plugins/dynamix.vm.manager/scripts/virtiofsd.php
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2024, Simon Fairweather
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
# Command for bash script /usr/libexec/virtiofsd
|
||||
# eval exec /usr/bin/virtiofsd $(/usr/local/emhttp/plugins/dynamix.vm.manager/scripts/virtiofsd.php "$@")
|
||||
|
||||
$file = "/etc/libvirt/virtiofsd.opt";
|
||||
$whole_cmd = '';
|
||||
$long_options = ["fd:","print-capabilities","syslog","daemonize","rlimit-nofile","thread-pool-size:","socket-path:","socket-group:","help","version","source:"];
|
||||
$short_options = "o:dfV";
|
||||
$argoptions = getopt($short_options,$long_options);
|
||||
|
||||
array_shift($argv);
|
||||
foreach ($argv as $i=>$arg) {
|
||||
if (strpos($arg, "--fd") !== false) unset($argv[$i]) ;
|
||||
if ($arg == "-o") { unset($argv[$i]);unset($argv[$i+1]); }
|
||||
}
|
||||
# Check if options file exists. Each option should be on a new line.
|
||||
if (is_file($file)) $options = explode("\n",file_get_contents($file)) ; else $options = ['--syslog','--inode-file-handles=mandatory','--announce-submounts'];
|
||||
$options[] = "--fd=".$argoptions['fd'];
|
||||
|
||||
if (isset($argoptions['o'])) {
|
||||
$virtiofsoptions = explode(',',$argoptions["o"]);
|
||||
foreach ($virtiofsoptions as $opt) {
|
||||
$optsplit = explode('=',$opt);
|
||||
switch ($optsplit[0]) {
|
||||
case "source":
|
||||
$options[] = "--shared-dir={$optsplit[1]}";
|
||||
break;
|
||||
case "cache":
|
||||
$options[] = "--cache=never";
|
||||
break;
|
||||
case "xattr":
|
||||
$options[] = "--xattr";
|
||||
break;
|
||||
case "sandbox":
|
||||
$options[] = "--sandbox={$optsplit[1]}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$newargs = array_merge($options,$argv);
|
||||
foreach($newargs as $arg) {
|
||||
if ($arg != "") $whole_cmd.= escapeshellarg($arg).' ';
|
||||
}
|
||||
echo trim($whole_cmd);
|
||||
?>
|
||||
@@ -545,6 +545,9 @@ window.onunload = function(){
|
||||
<? elseif (_var($var,'configValid')=="invalid"):?>
|
||||
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
|
||||
<td>_(Too many attached devices. Please consider upgrading your)_ <a href="/Tools/Registration">_(registration key)_</a>.</td></tr>
|
||||
<? elseif (_var($var,'configValid')=="ineligible"):?>
|
||||
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
|
||||
<td>_(Ineligible to run this version of Unraid OS. Please consider extending your)_ <a href="/Tools/Registration">_(registration key)_</a>.</td></tr>
|
||||
<? elseif (_var($var,'configValid')=="nokeyserver"):?>
|
||||
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
|
||||
<td>_(Cannot contact key-server. Please check your)_ <a href="/Settings/NetworkSettings">_(network settings)_</a>.</td></tr>
|
||||
|
||||
@@ -279,10 +279,10 @@ foreach ($cpus as $pair) {
|
||||
<a href='/Dashboard/Tools/Processes' title="_(View Running Processes)_"><i class='fa fa-fw fa-info-circle control'></i></a>
|
||||
</td></tr><tr><td>
|
||||
<span class='w26'><i class='ups fa fa-compress'></i>_(Usable size)_: <?=$ramsize?><br><i class='ups fa fa-expand'></i>_(Maximum size)_: <?="$memory_maximum $unit"?><?=$low?'*':''?></span>
|
||||
<span class='w18 center'><a class='info hand none'>_(RAM usage)_<span>_(Percent of total used memory)_ (<?=$ramsize?>)</span></a></span>
|
||||
<span class='w18 center'><a class='info hand none'>_(Flash device)_<span>_(Percent usage of flash usb device)_ (<?=$flashsize?>)</span></a></span>
|
||||
<span class='w18 center'><a class='info hand none'>_(Log filesystem)_<span>_(Percent usage of LOG file system)_ (<?=$logsize?>)</span></a></span>
|
||||
<span class='w18 center'><a class='info hand none'><?=$vdisk?><span><?=_("Percent usage of $vdisk")?> (<?=$dockersize?>)</span></a></span>
|
||||
<span class='w18 center static'><a class='info hand none'>_(RAM usage)_<span>_(Percent of total used memory)_ (<?=$ramsize?>)</span></a></span>
|
||||
<span class='w18 center static'><a class='info hand none'>_(Flash device)_<span>_(Percent usage of flash usb device)_ (<?=$flashsize?>)</span></a></span>
|
||||
<span class='w18 center static'><a class='info hand none'>_(Log filesystem)_<span>_(Percent usage of LOG file system)_ (<?=$logsize?>)</span></a></span>
|
||||
<span class='w18 center static'><a class='info hand none'><?=$vdisk?><span><?=_("Percent usage of $vdisk")?> (<?=$dockersize?>)</span></a></span>
|
||||
</td></tr><tr><td>
|
||||
<span class='w26'><legend>_(Legend)_</legend><span id='dynamic'></span></span>
|
||||
<span class='w18 center'><div class='pie' id='sys0'><span class='sys0'></span><span class='var0'></span></div></span>
|
||||
@@ -1223,7 +1223,7 @@ function addProperties() {
|
||||
$('div#sys3').hover(function(){$('.sys3').hide();$('.var3').show();},function(){$('.sys3').show();$('.var3').hide();});
|
||||
$('#current_time').hover(function(){$.post('/webGui/include/DashboardApps.php',{ntp:'ntp'},function(ntp){$('#current_time').prop('title',ntp+"\n_(Go to date and time settings)_");});});
|
||||
// make truncated descriptions fully visible when hovering over them
|
||||
$('span.w18').hover(
|
||||
$('span.w18').not('.static').hover(
|
||||
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall = $(this).next(); recover=recall.html(); recall.html(' ');}},
|
||||
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall.html(recover); recall=null;}}
|
||||
);
|
||||
|
||||
@@ -313,7 +313,14 @@ function setGlue(form,reset) {
|
||||
{glue:'/',more:3,dev:1,type:'',min1:1,max1:4,min2:1,max2:128,min3:1,max3:4}, // highpoint
|
||||
{glue:'' ,more:1,dev:1,type:'',min1:0,max1:15}, // hp cciss
|
||||
{glue:'' ,more:0,dev:0,type:''}, // marvell
|
||||
{glue:',',more:1,dev:1,type:'',min1:0,max1:127} // megaraid
|
||||
{glue:',',more:1,dev:1,type:'',min1:0,max1:127}, // megaraid
|
||||
{glue:',',more:1,dev:0,type:'input',min1:'',max1:'0xffffffff'}, // cypress
|
||||
{glue:',',more:3,dev:0,type:'select',min1:'',max1:'p',min2:'',max2:'x',min3:1,max3:128},// jmicron ata
|
||||
{glue:'' ,more:0,dev:0,type:''}, // prolific
|
||||
{glue:'' ,more:0,dev:0,type:''}, // sunplus
|
||||
{glue:'' ,more:0,dev:0,type:''}, // asmedia
|
||||
{glue:'' ,more:0,dev:0,type:''}, // jmicron nvme
|
||||
{glue:'' ,more:0,dev:0,type:''}, // realtek
|
||||
];
|
||||
var n = form.smType.selectedIndex>0 ? form.smType.selectedIndex-1 : <?=_var($var,'smIndex',0)?>;
|
||||
var x = data[n]['more'];
|
||||
@@ -603,7 +610,7 @@ _(Spin down delay)_:
|
||||
_(File system status)_:
|
||||
: <?=_(_var($disk,'fsStatus'))?>
|
||||
|
||||
<?$disabled = (_var($var,'fsState')=="Stopped" && !empty(_var($disk,'uuid'))) || (_var($var,'fsState')=="Started" && _var($disk,'fsStatus')=='Mounted') ? "disabled" : ""?>
|
||||
<?$disabled = (_var($var,'fsState')=="Stopped" && !empty(_var($disk,'uuid'))) || (_var($var,'fsState')=="Started" && _var($disk,'fsType')!='auto') ? "disabled" : ""?>
|
||||
<?if (diskType('Data') || (!isSubpool($name) && _var($disk,'slots',0)==1)):?>
|
||||
_(File system type)_:
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="changeFsType()" <?=$disabled?>>
|
||||
@@ -1246,6 +1253,13 @@ _(SMART controller type)_:
|
||||
<?=mk_option(_var($disk,'smType'), "-d cciss", "HP cciss")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d marvell", "Marvell")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d megaraid", "MegaRAID")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d usbcypress", "Cypress ATACB")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d usbjmicron", "JMicron ATA pass-through")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d usbprolific", "Prolific ATA pass-through")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d usbsunplus", "Sunplus ATA pass-through")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d sntasmedia", "ASMedia NVMe pass-through")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d sntjmicron", "JMicron NVMe pass-through")?>
|
||||
<?=mk_option(_var($disk,'smType'), "-d sntrealtek", "Realtek NVMe pass-through")?>
|
||||
</select>
|
||||
<input type="text" name="smPort1" value="<?=_var($disk,'smPort1')?>" class="option"><select name="smPort1" class="narrow option" disabled></select>
|
||||
<input type="text" name="smPort2" value="<?=_var($disk,'smPort2')?>" class="option"><select name="smPort2" class="narrow option" disabled></select>
|
||||
|
||||
@@ -364,6 +364,13 @@ _(Default SMART controller type)_:
|
||||
<?=mk_option(_var($var,'smType'), "-d cciss", "HP cciss")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d marvell", "Marvell")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d megaraid", "MegaRAID")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d usbcypress", "Cypress ATACB")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d usbjmicron", "JMicron ATA pass-through")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d usbprolific", "Prolific ATA pass-through")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d usbsunplus", "Sunplus ATA pass-through")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d sntasmedia", "ASMedia NVMe pass-through")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d sntjmicron", "JMicron NVMe pass-through")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d sntrealtek", "Realtek NVMe pass-through")?>
|
||||
</select>
|
||||
|
||||
:disk_default_smart_controller_help:
|
||||
|
||||
@@ -5,8 +5,8 @@ Icon="icon-key"
|
||||
Tag="expeditedssl"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* 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,
|
||||
@@ -75,7 +75,7 @@ if ($cert1Present) {
|
||||
$cert1SelfSigned = ($cert1Subject == $cert1Issuer);
|
||||
}
|
||||
|
||||
// unraid.net, myunraid.net LE cert. could potentially be user provided as well
|
||||
// myunraid.net LE cert. could potentially be user provided as well
|
||||
$cert2File = "/boot/config/ssl/certs/certificate_bundle.pem";
|
||||
$cert2Present = file_exists("$cert2File");
|
||||
if ($cert2Present) {
|
||||
@@ -84,6 +84,8 @@ if ($cert2Present) {
|
||||
$cert2Expires = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Not After : //p'");
|
||||
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', $cert2Subject);
|
||||
$subject2URL = $cert2Subject;
|
||||
$dnsValid = false;
|
||||
$dnsRebindingProtection = false;
|
||||
if ($isWildcardCert) {
|
||||
exec("openssl x509 -checkend 2592000 -noout -in $cert2File 2>/dev/null", $arrout, $retval_expired);
|
||||
if (!$addr) {
|
||||
@@ -115,12 +117,12 @@ if ($cert2Present) {
|
||||
}
|
||||
}
|
||||
|
||||
$http_port = _var($var,'PORT',80) != 80 ? ":{$var['PORT']}" : '';
|
||||
$https_port = _var($var,'PORTSSL',443) != 443 ? ":{$var['PORTSSL']}" : '';
|
||||
$http_port = _var($var,'PORT','80') != '80' ? ":{$var['PORT']}" : '';
|
||||
$https_port = _var($var,'PORTSSL','443') != '443' ? ":{$var['PORTSSL']}" : '';
|
||||
$http_ip_url = "http://"._var($nginx,'NGINX_LANIP')."{$http_port}/";
|
||||
$https_ip_url = "https://"._var($nginx,'NGINX_LANIP')."{$https_port}/";
|
||||
$http_ip6_url = "http://"._var($nginx,'NGINX_LANIP6')."{$http_port}/";
|
||||
$https_ip6_url = "https://"._var($nginx,'NGINX_LANIP6')."{$https_port}/";
|
||||
$http_ip6_url = "http://["._var($nginx,'NGINX_LANIP6')."]{$http_port}/";
|
||||
$https_ip6_url = "https://["._var($nginx,'NGINX_LANIP6')."]{$https_port}/";
|
||||
$http_mdns_url = "http://"._var($nginx,'NGINX_LANMDNS')."{$http_port}/";
|
||||
$https_mdns_url = "https://"._var($nginx,'NGINX_LANMDNS')."{$https_port}/";
|
||||
$https_fqdn_url = "https://"._var($nginx,'NGINX_LANFQDN')."{$https_port}/";
|
||||
@@ -164,7 +166,6 @@ $cert_time_format = $display['date'].($display['date']!='%c' ? ', '.str_replac
|
||||
$provisionlabel = $isWildcardCert ? _('Renew') : _('Provision');
|
||||
$disabled_provision = $keyfile===false || ($isWildcardCert && $retval_expired===0) || !$addr ? 'disabled' : '';
|
||||
$disabled_provision_msg = !$addr ? _('Ensure the primary network card eth0 has an IP address.') : '';
|
||||
$disabled_updatedns = $keyfile!==false && $isWildcardCert ? '' : 'disabled';
|
||||
$disabled_delete = $cert2Present && $var['USE_SSL']!='auto' ? '' : 'disabled';
|
||||
$disabled_auto = $isWildcardCert && !$dnsRebindingProtection && $dnsValid ? '' : 'disabled';
|
||||
|
||||
@@ -189,23 +190,6 @@ function provisionHandler(event, form) { // provisions and renewals require bein
|
||||
if (event.submitter.value === 'Renew') return true; // always allow renewals
|
||||
};
|
||||
|
||||
function updateDNS(button) {
|
||||
$(button).prop("disabled", true).html("<i class='fa fa-circle-o-notch fa-spin fa-fw'></i>_(Update DNS)_");
|
||||
var failure = function(data) {
|
||||
var status = data.status;
|
||||
var obj = data.responseJSON;
|
||||
var msg = "_(Sorry, an error occurred updating unraid.net DNS records)_. _(The error is)_: "+obj.error+".";
|
||||
$(button).prop("disabled", false).html("_(Update DNS)_");
|
||||
swal({title:"_(Oops)_",text:msg,type:"error",html:true,confirmButtonText:"_(Ok)_"});
|
||||
};
|
||||
var success = function(data) {
|
||||
$(button).prop("disabled", false).html("_(Update DNS)_");
|
||||
<?$text = _('Your local IP address %s has been updated for unraid.net')?>
|
||||
swal({title:"",text:"<?=sprintf($text,$addr)?>",type:"success",html:true,confirmButtonText:"_(Ok)_"});
|
||||
};
|
||||
$.post("/webGui/include/UpdateDNS.php",success).fail(failure);
|
||||
}
|
||||
|
||||
function checkPorts(form) {
|
||||
var portsInUse = [<?=implode(',',$portsInUse)?>];
|
||||
var range = [], list = [], duplicates = [];
|
||||
@@ -359,12 +343,10 @@ _(Local access URLs)_:
|
||||
$n = 0;
|
||||
foreach($urls as $url) {
|
||||
$msg = "";
|
||||
$url0 = substr_count($url[0]??'',':')>3 ? preg_replace('#(://)(.+?)(:?\d*)/$#','$1[$2]$3/',$url[0]) : $url[0]; // IPv6 - IPv4 notation
|
||||
$url1 = substr_count($url[1]??'',':')>3 ? preg_replace('#(://)(.+?)(:?\d*)/$#','$1[$2]$3/',$url[1]) : $url[1]; // IPv6 - IPv4 notation
|
||||
if ($url[1]) $msg .= " "._("redirects to")." <a href='$url1'>$url1</a>";
|
||||
if ($url[1]) $msg .= " "._("redirects to")." <a href='$url[1]'>$url[1]</a>";
|
||||
if ($url[2]) $msg .= " "._("uses")." ".$url[2];
|
||||
if ($url[3]) $msg .= "<span class='warning'> <i class='fa fa-warning fa-fw'></i> "._("is a self-signed certificate, ignore the browser's warning and proceed to the GUI")."</span>";
|
||||
echo ($n ? "<dt> </dt><dd>" : ""),"<a href='$url0'>$url0</a>$msg",($n++ ? "</dd>" : "");
|
||||
echo ($n ? "<dt> </dt><dd>" : ""),"<a href='$url[0]'>$url[0]</a>$msg",($n++ ? "</dd>" : "");
|
||||
}?>
|
||||
|
||||
:mgmt_local_access_urls_help:
|
||||
@@ -431,7 +413,7 @@ _(CA-signed certificate file)_:
|
||||
|
||||
<?endif;?>
|
||||
|
||||
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?>><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><!-- <button type="button" onclick="updateDNS(this)" <?=$disabled_updatedns?>>_(Update DNS)_</button> --><?=$disabled_provision_msg?>
|
||||
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?>><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><?=$disabled_provision_msg?>
|
||||
|
||||
:mgmt_certificate_expiration_help:
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ Tag="folder-o"
|
||||
<?
|
||||
$width = [166,300];
|
||||
function data_disks($disk) {
|
||||
global $pools;
|
||||
return (_var($disk,'type')=="Data" || (_var($disk,'type')=="Cache" && in_array(_var($disk,'name'),$pools))) && _var($disk,'status')=='DISK_OK';
|
||||
return in_array(_var($disk,'type'),['Data','Cache']) && array_key_exists('exportable',$disk) && _var($disk,'fsStatus')=='Mounted';
|
||||
}
|
||||
?>
|
||||
<script>
|
||||
|
||||
311
emhttp/plugins/dynamix/OutgoingProxy.page
Normal file
311
emhttp/plugins/dynamix/OutgoingProxy.page
Normal file
@@ -0,0 +1,311 @@
|
||||
Menu="NetworkServices"
|
||||
Type="xmenu"
|
||||
Title="Outgoing Proxy Manager"
|
||||
Icon="icon-network"
|
||||
Tag="icon-network"
|
||||
---
|
||||
<?php
|
||||
/* Copyright 2024, 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.
|
||||
*/
|
||||
|
||||
$opmPlugin = "dynamix";
|
||||
require_once("plugins/".$opmPlugin."/include/OutgoingProxyLib.php");
|
||||
|
||||
/* Parse the plugin config file. */
|
||||
$cfg = parse_plugin_config();
|
||||
|
||||
/* Pid file used to track the Running/Stopped status. */
|
||||
$opm_pid = "OutgoingProxy";
|
||||
$pid_file = "/var/run/".$opm_pid.".pid";
|
||||
$cfg['proxy_active'] = $cfg['proxy_active'] ?? "0";
|
||||
if ($cfg['proxy_active'] != "0") {
|
||||
file_put_contents($pid_file, "running");
|
||||
} else if (file_exists($pid_file)) {
|
||||
unlink($pid_file);
|
||||
}
|
||||
|
||||
/* Be sure proxy_mames are defined */
|
||||
$cfg['proxy_name_1'] = $cfg['proxy_name_1'] ?? "";
|
||||
$cfg['proxy_name_2'] = $cfg['proxy_name_2'] ?? "";
|
||||
$cfg['proxy_name_3'] = $cfg['proxy_name_3'] ?? "";
|
||||
|
||||
/* Parse the url, user, and password from the full url for proxy 1. */
|
||||
$url_array = get_proxy_info($cfg['proxy_url_1'] ?? "", $cfg['proxy_user_1'] ?? "", $cfg['proxy_pass_1'] ?? "");
|
||||
$cfg['proxy_url_1'] = $url_array['url'];
|
||||
$cfg['proxy_user_1'] = $url_array['user'];
|
||||
$cfg['proxy_pass_1'] = $url_array['pass'];
|
||||
$proxy_1_url = $url_array['full_url'];
|
||||
|
||||
/* Parse the url, user, and password from the full url for proxy 2. */
|
||||
$url_array = get_proxy_info($cfg['proxy_url_2'] ?? "", $cfg['proxy_user_2'] ?? "", $cfg['proxy_pass_2'] ?? "");
|
||||
$cfg['proxy_url_2'] = $url_array['url'];
|
||||
$cfg['proxy_user_2'] = $url_array['user'];
|
||||
$cfg['proxy_pass_2'] = $url_array['pass'];
|
||||
$proxy_2_url = $url_array['full_url'];
|
||||
|
||||
/* Parse the url, user, and password from the full url for proxy 3. */
|
||||
$url_array = get_proxy_info($cfg['proxy_url_3'] ?? "", $cfg['proxy_user_3'] ?? "", $cfg['proxy_pass_3'] ?? "");
|
||||
$cfg['proxy_url_3'] = $url_array['url'];
|
||||
$cfg['proxy_user_3'] = $url_array['user'];
|
||||
$cfg['proxy_pass_3'] = $url_array['pass'];
|
||||
$proxy_3_url = $url_array['full_url'];
|
||||
?>
|
||||
|
||||
<form markdown="1" name="outgoing_proxy_manager" method="POST" action="/update.php" target="progressFrame">
|
||||
<input type="hidden" name="#file" value="<?=$plg_config_file;?>">
|
||||
<input type="hidden" name="#command" value="/plugins/<?=$opmPlugin;?>/scripts/outgoingproxy">
|
||||
<input type="hidden" name="#arg[1]" value="apply">
|
||||
|
||||
<p><strong>_(Enable Outgoing Proxy)_</strong></p>
|
||||
_(Select Proxy)_:
|
||||
: <select name="proxy_active" style="width:20%;" size="1">
|
||||
<?=mk_option($cfg['proxy_active'], "0", "_(None)_");?>
|
||||
|
||||
<?if (($cfg['proxy_url_1']) && ($cfg['proxy_name_1'])):?>
|
||||
<?=mk_option($cfg['proxy_active'], "1", $cfg['proxy_name_1'], "disabled");?>
|
||||
<?endif;?>
|
||||
|
||||
<?if (($cfg['proxy_url_2']) && ($cfg['proxy_name_2'])):?>
|
||||
<?=mk_option($cfg['proxy_active'], "2", $cfg['proxy_name_2'], "disabled");?>
|
||||
<?endif;?>
|
||||
|
||||
<?if (($cfg['proxy_url_3']) && ($cfg['proxy_name_3'])):?>
|
||||
<?=mk_option($cfg['proxy_active'], "3", $cfg['proxy_name_3'], "disabled");?>
|
||||
<?endif;?>
|
||||
</select>
|
||||
|
||||
:outgoing_proxy_enable_plug:
|
||||
> Select the Proxy to use. Only online Proxies will be selectable.
|
||||
>
|
||||
> If your network environment requires an outgoing http proxy, define that here.
|
||||
>
|
||||
> Outgoing connections from the webgui and some system processes will use the specified http proxy. Docker container installs and updates will use the proxy, but the container itself will not, neither will any VMs.
|
||||
>
|
||||
> For a more comprehensive solution you might consider setting up <u><a href='https://docs.unraid.net/unraid-os/manual/security/vpn/#configuring-vpn-tunneled-access-for-system/' target='_blank'>_(VPN tunnel access for System)_</a></u>.
|
||||
:end
|
||||
|
||||
<p><strong>_(Outgoing Proxy)_ 1</strong></p>
|
||||
_(Name)_:
|
||||
: <input type="text" name="proxy_name_1" style="width:20%;" maxlength="25" value="<?=$cfg['proxy_name_1'];?>" placeholder="(_(Required)_)"><span id="proxy-status-1"></span>
|
||||
|
||||
:outgoing_proxy_name_plug:
|
||||
> Outgoing Proxy name for this Proxy.
|
||||
:end
|
||||
|
||||
_(URL)_:
|
||||
: <input type="text" name="proxy_url_1" style="width:30%;" maxlength="100" value="<?=$cfg['proxy_url_1'];?>" onchange="verifyUrl(this)" placeholder="_(http://IP:port or http://host:port)_">
|
||||
|
||||
:outgoing_proxy_url_plug:
|
||||
> Outgoing Proxy URL for this Proxy. The URL can be entered with or without credentials. The credentials will be parsed from the URL.
|
||||
>
|
||||
> If you enter a User and Password, they will be used as new credentials.
|
||||
:end
|
||||
|
||||
_(User)_:
|
||||
: <input type="text" name="proxy_user_1" class="wide" maxlength="100" value="<?=$cfg['proxy_user_1'];?>" placeholder="(_(Optional)_)">
|
||||
|
||||
:outgoing_proxy_user_plug:
|
||||
> Outgoing Proxy User Name for this Proxy.
|
||||
:end
|
||||
|
||||
_(Password)_:
|
||||
: <input type="text" name="proxy_pass_1" class="wide" maxlength="100" value="<?=$cfg['proxy_pass_1'];?>" placeholder="(_(Optional)_)">
|
||||
|
||||
:outgoing_proxy_password_plug:
|
||||
> Outgoing Proxy Password for this Proxy.
|
||||
:end
|
||||
|
||||
<p><strong>_(Outgoing Proxy)_ 2</strong></p>
|
||||
_(Name)_:
|
||||
: <input type="text" name="proxy_name_2" style="width:20%;" maxlength="25" value="<?=$cfg['proxy_name_2'];?>" placeholder="(_(Required)_)"><span id="proxy-status-2"></span>
|
||||
|
||||
:outgoing_proxy_name_plug:
|
||||
> Outgoing Proxy name for this Proxy.
|
||||
:end
|
||||
|
||||
_(URL)_:
|
||||
: <input type="text" name="proxy_url_2" style="width:30%;" maxlength="100" value="<?=$cfg['proxy_url_2'];?>" onchange="verifyUrl(this)" placeholder="_(http://IP:port or http://host:port)_">
|
||||
|
||||
:outgoing_proxy_url_plug:
|
||||
> Outgoing Proxy URL for this Proxy. The URL can be entered with or without credentials. The credentials will be parsed from the URL.
|
||||
>
|
||||
> If you enter a User and Password, they will be used as new credentials.
|
||||
:end
|
||||
|
||||
_(User)_:
|
||||
: <input type="text" name="proxy_user_2" class="wide" maxlength="100" value="<?=$cfg['proxy_user_2'];?>" placeholder="(_(Optional)_)">
|
||||
|
||||
:outgoing_proxy_user_plug:
|
||||
> Outgoing Proxy User Name for this Proxy.
|
||||
:end
|
||||
|
||||
_(Password)_:
|
||||
: <input type="text" name="proxy_pass_2" class="wide" maxlength="100" value="<?=$cfg['proxy_pass_2'];?>" placeholder="(_(Optional)_)">
|
||||
|
||||
:outgoing_proxy_password_plug:
|
||||
> Outgoing Proxy Password for this Proxy.
|
||||
:end
|
||||
|
||||
<p><strong>_(Outgoing Proxy)_ 3</strong></p>
|
||||
_(Name)_:
|
||||
: <input type="text" name="proxy_name_3" style="width:20%;" maxlength="25" value="<?=$cfg['proxy_name_3'];?>" placeholder="(_(Required)_)"><span id="proxy-status-3"></span>
|
||||
|
||||
:outgoing_proxy_name_plug:
|
||||
> Outgoing Proxy name for this Proxy.
|
||||
:end
|
||||
|
||||
_(URL)_:
|
||||
: <input type="text" name="proxy_url_3" style="width:30%;" maxlength="100" value="<?=$cfg['proxy_url_3'];?>" onchange="verifyUrl(this)" placeholder="_(http://IP:port or http://host:port)_">
|
||||
|
||||
:outgoing_proxy_url_plug:
|
||||
> Outgoing Proxy URL for this Proxy. The URL can be entered with or without credentials. The credentials will be parsed from the URL.
|
||||
>
|
||||
> If you enter a User and Password, they will be used as new credentials.
|
||||
:end
|
||||
|
||||
_(User)_:
|
||||
: <input type="text" name="proxy_user_3" class="wide" maxlength="100" value="<?=$cfg['proxy_user_3'];?>" placeholder="(_(Optional)_)">
|
||||
|
||||
:outgoing_proxy_user_plug:
|
||||
> Outgoing Proxy User Name for this Proxy.
|
||||
:end
|
||||
|
||||
_(Password)_:
|
||||
: <input type="text" name="proxy_pass_3" class="wide" maxlength="100" value="<?=$cfg['proxy_pass_3'];?>" placeholder="(_(Optional)_)">
|
||||
|
||||
:outgoing_proxy_password_plug:
|
||||
> Outgoing Proxy Password for this Proxy.
|
||||
:end
|
||||
|
||||
|
||||
: <input type="submit" value='_(Apply)_'><input type="button" value="_(Done)_" onclick="done()">
|
||||
</form>
|
||||
|
||||
<script>
|
||||
/* Refresh Proxy Manager page showing updated proxy status. */
|
||||
function refreshPage() {
|
||||
$.post(OPMURL, {
|
||||
action: "proxy_status",
|
||||
proxy_1_url: "<?=$proxy_1_url;?>",
|
||||
proxy_2_url: "<?=$proxy_2_url;?>",
|
||||
proxy_3_url: "<?=$proxy_3_url;?>",
|
||||
proxy_active: "<?=$cfg['proxy_active'];?>"
|
||||
}, function(data) {
|
||||
/* Refresh the proxy status. */
|
||||
/* Update the proxy status div */
|
||||
$('#proxy-status-1').html('<strong>' + data.proxy_status_1 + '</strong>');
|
||||
|
||||
/* Update the proxy status div */
|
||||
$('#proxy-status-2').html('<strong>' + data.proxy_status_2 + '</strong>');
|
||||
|
||||
/* Update the proxy status div */
|
||||
$('#proxy-status-3').html('<strong>' + data.proxy_status_3 + '</strong>');
|
||||
|
||||
//*Get a reference to the dropdown element. */
|
||||
const dropdown = document.querySelector('select[name="proxy_active"]');
|
||||
const options = dropdown.getElementsByTagName('option');
|
||||
|
||||
/* Enable the dropdown element if the proxy is available or active. */
|
||||
const condition_1 = $('#proxy-status-1').text().trim() === '' || $('#proxy-status-1').text().trim() === 'Active';
|
||||
const optionToEnableOrDisable_1 = options[1];
|
||||
|
||||
if (optionToEnableOrDisable_1) {
|
||||
if (condition_1) {
|
||||
/* Enable the option. */
|
||||
optionToEnableOrDisable_1.removeAttribute('disabled');
|
||||
} else {
|
||||
/* Disable the option. */
|
||||
optionToEnableOrDisable_1.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the dropdown element if the proxy is available or active. */
|
||||
const condition_2 = $('#proxy-status-2').text().trim() === '' || $('#proxy-status-2').text().trim() === 'Active';
|
||||
const optionToEnableOrDisable_2 = options[2];
|
||||
|
||||
if (optionToEnableOrDisable_2) {
|
||||
if (condition_2) {
|
||||
/* Enable the option. */
|
||||
optionToEnableOrDisable_2.removeAttribute('disabled');
|
||||
} else {
|
||||
/* Disable the option. */
|
||||
optionToEnableOrDisable_2.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the dropdown element if the proxy is available or active. */
|
||||
const condition_3 = $('#proxy-status-3').text().trim() === '' || $('#proxy-status-3').text().trim() === 'Active';
|
||||
const optionToEnableOrDisable_3 = options[3];
|
||||
|
||||
if (optionToEnableOrDisable_3) {
|
||||
if (condition_3) {
|
||||
/* Enable the option. */
|
||||
optionToEnableOrDisable_3.removeAttribute('disabled');
|
||||
} else {
|
||||
/* Disable the option. */
|
||||
optionToEnableOrDisable_3.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
/* polyfill to fix reportValidity() for Firefox. */
|
||||
if (!HTMLInputElement.prototype.reportValidity || (navigator.userAgent.indexOf("Firefox") !== -1)) {
|
||||
HTMLInputElement.prototype.reportValidity = function () {
|
||||
if (this.checkValidity()) {
|
||||
return true;
|
||||
} else {
|
||||
var labelText = "_(Invalid data)_";
|
||||
try {
|
||||
labelText = $(this).closest('dl').children().first()[0].textContent;
|
||||
} catch (err) { }
|
||||
/* the browser generates the validationMessage, we cannot translate it. */
|
||||
swal({title:labelText,text:this.validationMessage,html:true,type:'error',confirmButtonText:"_(Ok)_"});
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Verify the format of the url. */
|
||||
function verifyUrl(inputElement) {
|
||||
const fieldValue = inputElement.value;
|
||||
/* Return true if the field is blank. */
|
||||
if (fieldValue.trim() === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Verify the url is in the correct format. */
|
||||
if (fieldValue.startsWith("http://") && fieldValue.match(/:\d+$/)) {
|
||||
inputElement.setCustomValidity("");
|
||||
return true;
|
||||
} else {
|
||||
inputElement.setCustomValidity("_(Please match the requested format)_:\n\n"+"'_(http://IP:port or http://host:port)_'");
|
||||
inputElement.reportValidity();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
/* Status indicator on upper right of page. */
|
||||
showStatus('pid','<?=$opm_pid;?>');
|
||||
|
||||
/* Page refresh rate in milliseconds. */
|
||||
const REFRESH_INTERVAL = 15000;
|
||||
|
||||
/* Set page refresh interval every 15 seconds. */
|
||||
window.setInterval(refreshPage, REFRESH_INTERVAL);
|
||||
|
||||
/* Do an initial page refresh to fill in values. */
|
||||
refreshPage();
|
||||
});
|
||||
|
||||
/* URL for Outgoing Proxy PHP file. */
|
||||
const OPMURL = '/plugins/<?=$opmPlugin;?>/include/OutgoingProxy.php';
|
||||
</script>
|
||||
@@ -101,7 +101,7 @@ function textsave(module,remove = false) {
|
||||
if (data.modprobe == "") $('#text'+module).attr('hidden', true); else $('#text'+module).attr('rows', 3);
|
||||
if (data.supportpage == true) {
|
||||
if (data.support == true) {
|
||||
document.getElementById("link" + module).innerHTML = "<a href='" + data.supporturl + "'target='_blank'><i title='"+_("Support page")_+"' class='fa fa-phone-square'></i></a>";
|
||||
document.getElementById("link" + module).innerHTML = "<a href='" + data.supporturl + "'target='_blank'><i title='"+"_(Support page)_"+"' class='fa fa-phone-square'></i></a>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,15 @@ _(Local syslog folder)_:
|
||||
|
||||
:syslog_local_folder_help:
|
||||
|
||||
_(System identifier for logfile name)_:
|
||||
: <select name="server_filename">
|
||||
<?=mk_option($syslog['server_filename'], "syslog-%FROMHOST-IP%.log", _("IP Address"))?>
|
||||
<?=mk_option($syslog['server_filename'], "syslog-%HOSTNAME%.log", _("Hostname (from syslog message)"))?>
|
||||
<?=mk_option($syslog['server_filename'], "syslog-%FROMHOST%.log", _("Hostname (from DNS reverse lookup)"))?>
|
||||
</select>
|
||||
|
||||
:syslog_remote_system_identifier_help:
|
||||
|
||||
_(Local syslog rotation)_:
|
||||
: <select name="log_rotation" onchange="logOptions(this.value,'slow')">
|
||||
<?=mk_option(_var($syslog,'log_rotation'), "", _("Disabled"))?>
|
||||
@@ -146,7 +155,7 @@ _(Local syslog number of files)_:
|
||||
</div>
|
||||
|
||||
_(Remote syslog server)_:
|
||||
: <span class="span"><input type="text" name="remote_server" class="narrow" value="<?=_var($syslog,'remote_server')?>" maxlength="23" placeholder="_(name or ip address)_"></span>
|
||||
: <span class="span"><input type="text" name="remote_server" class="narrow" value="<?=_var($syslog,'remote_server')?>" maxlength="50" placeholder="_(name or ip address)_"></span>
|
||||
<select name="remote_protocol" class="narrow">
|
||||
<?=mk_option(_var($syslog,'remote_protocol'), "udp", _("UDP"))?>
|
||||
<?=mk_option(_var($syslog,'remote_protocol'), "tcp", _("TCP"))?>
|
||||
|
||||
@@ -30,6 +30,8 @@ $(function() {
|
||||
$globals = [];
|
||||
$names = ['_SERVER','devs','disks','sec','sec_nfs','shares','users','var'];
|
||||
foreach ($names as $name) $globals[$name] = $$name;
|
||||
// show outgoing proxy information, is in the environment but not a superglobal
|
||||
$globals['environment'] = ['http_proxy' => getenv('http_proxy'), 'no_proxy' => getenv('no_proxy')];
|
||||
echo "<pre class='up'>",htmlspecialchars(print_r($globals,true)),"</pre>";
|
||||
?>
|
||||
<input type="button" value="_(Done)_" onclick="done()">
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
Menu="UNRAID-OS"
|
||||
Title="Wake On LAN"
|
||||
Icon="fa-bell"
|
||||
Tag="server"
|
||||
---
|
||||
<?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.
|
||||
*/
|
||||
|
||||
if (count($_POST)) {
|
||||
$cfg = NULL ;
|
||||
if ($_POST['#apply'] == "_(Save)_") {
|
||||
foreach($_POST as $postkey=>$data) {
|
||||
if ($postkey=="#apply") continue;
|
||||
$keys = explode(";",$postkey);
|
||||
if (count($keys) >1) $update_file[$keys[1]][$keys[2]][$keys[0]]=$data;
|
||||
}
|
||||
|
||||
foreach($update_file as $type => $types) {
|
||||
foreach($types as $name => $details) {
|
||||
if ($details['user_mac'] == "") $details['user_mac'] = "None Defined";
|
||||
if ($details['user_mac'] == "None Defined" && ($details['enable'] == "enable" || $details['enable'] == "shutdown")) unset($update_file[$type][$name]) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($_POST) ;
|
||||
file_put_contents("/boot/config/wol.json",json_encode($update_file));
|
||||
#echo '<meta http-equiv="refresh" content="0;url=/Tools">';
|
||||
echo '<meta http-equiv="refresh" content="0">';
|
||||
#unset($_SESSION['csrf_token']);
|
||||
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
<script src="/webGui/javascript/jquery.tablesorter.widgets.js"></script>
|
||||
|
||||
<script>
|
||||
function showWOL(options, init = false) {
|
||||
option = options;
|
||||
if (init) {
|
||||
$('#wolsearch').prop('disabled', true);
|
||||
$.post('/webGui/include/WOL.php',{table:'t1load',option:"all"},function(data){
|
||||
clearTimeout(timers.refresh);
|
||||
filter = [];
|
||||
$("#t1").trigger("destroy");
|
||||
$('#t1').html(data.html);
|
||||
$('#t1').tablesorter({
|
||||
sortList: [[0,0]],
|
||||
sortAppend: [[0,0]],
|
||||
widgets: ['stickyHeaders','filter','zebra'],
|
||||
widgetOptions: {
|
||||
// on black and white, offset is height of #menu
|
||||
// on azure and gray, offset is height of #header
|
||||
stickyHeaders_offset: ($('#menu').height() < 50) ? $('#menu').height() : $('#header').height(),
|
||||
filter_columnFilters: false,
|
||||
zebra: ["normal-row","alt-row"]
|
||||
}
|
||||
});
|
||||
$('div.spinner.fixed').hide('slow');
|
||||
$('#wolsearch').prop('disabled', false);
|
||||
$('#select').prop('disabled', false);
|
||||
$('#rebuild').prop('disabled', data.init);
|
||||
},"json");
|
||||
} else {
|
||||
filter = [];
|
||||
filterWOL();
|
||||
}
|
||||
}
|
||||
|
||||
function filterWOL() {
|
||||
var totalColumns = $('#t1')[0].config.columns;
|
||||
var filter = [];
|
||||
filter[totalColumns] = $('#wolsearch').val(); // this searches all columns
|
||||
$('#t1').trigger('search', [filter]);
|
||||
}
|
||||
|
||||
function showWOLupdate() {
|
||||
$('#rebuild').prop('disabled', true);
|
||||
$('#t1').html("");
|
||||
$('#wolsearch').prop('disabled', true);
|
||||
$('#select').prop('disabled', true);
|
||||
$('div.spinner.fixed').show('slow');
|
||||
$.post('/webGui/include/WOL.php',{table:'t1create',option:"all"},function(data){
|
||||
$('#rebuild').prop('disabled', false);
|
||||
showWOL("all",true);
|
||||
$('div.spinner.fixed').hide('slow');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function maccreate(name) {
|
||||
|
||||
$.post('/webGui/include/WOL.php',{table:'macaddress'}, function( data ) {
|
||||
if (data.mac) {
|
||||
$('#'+name).val(data.mac);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
showWOL("all",true);
|
||||
</script>
|
||||
|
||||
:WOL_intro_help:
|
||||
|
||||
<form autocomplete="off" onsubmit="return false;"><span><input class="t1 search" id="wolsearch" type="search" placeholder="Search..." onchange="filterWOL();"></span></form>
|
||||
<pre><form name="WOL" id="WOL" method="POST" class="js-confirm-leave" >
|
||||
<table name="t1"id='t1' class="t1 unraid tablesorter" >
|
||||
<tr><td><div class="spinner"></div></td></tr></table></pre><br>
|
||||
<input type="button" value="_(Done)_" onclick="done()">
|
||||
<input type="submit" name="#apply" id='#apply' value="_(Save)_" >
|
||||
</form>
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
Menu="OtherSettings"
|
||||
Type="xmenu"
|
||||
Title="Wake on Lan Settings"
|
||||
Icon="fa-bell"
|
||||
Tag="share-alt"
|
||||
---
|
||||
<?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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
exec("ls --indicator-style=none /sys/class/net|grep -P '^eth[1-9][0-9]*$'",$ports);
|
||||
$disabled = _var($var,'fsState')!='Stopped' ? 'disabled' : '';
|
||||
$width = [166,300];
|
||||
$file = '/boot/config/wol.cfg';
|
||||
$current = parse_ini_file($file);
|
||||
if (!isset($current['LOGFILE'])) $current['LOGFILE'] = "syslog"
|
||||
?>
|
||||
<script>
|
||||
showStatus('pid','unraidwold');
|
||||
</script>
|
||||
<form markdown="1" name="WOLsettings" method="POST" action="/update.php" target="progressFrame" >
|
||||
<input type="hidden" name="#file" value="<?=$file;?>">
|
||||
<input type="hidden" name="#command" value="/webGui/scripts/WOL_action">
|
||||
<input type="hidden" name="#arg[1]" value="load">
|
||||
|
||||
_(Enable Wake on Lan)_:
|
||||
: <select name="WOLENABLED" >
|
||||
<?=mk_option($current['WOLENABLED'], "no", _('No'))?>
|
||||
<?=mk_option($current['WOLENABLED'], "yes", _('Yes'))?>
|
||||
</select>
|
||||
|
||||
:WOL_enable_help:
|
||||
|
||||
_(Enable Docker actions)_:
|
||||
|
||||
: <select name="RUNDOCKER" >
|
||||
<?=mk_option($current['RUNDOCKER'], "y", _('Yes'))?>
|
||||
<?=mk_option($current['RUNDOCKER'], "n", _('No'))?>
|
||||
</select>
|
||||
|
||||
:WOL_run_docker_help:
|
||||
|
||||
_(Enable LXC actions)_:
|
||||
: <select name="RUNLXC" >
|
||||
<?=mk_option($current['RUNLXC'], "y", _('Yes'))?>
|
||||
<?=mk_option($current['RUNLXC'], "n", _('No'))?>
|
||||
</select>
|
||||
|
||||
:WOL_run_LXC_help:
|
||||
|
||||
_(Enable VM actions)_:
|
||||
: <select name="RUNVM" >
|
||||
<?=mk_option($current['RUNVM'], "y", _('Yes'))?>
|
||||
<?=mk_option($current['RUNVM'], "n", _('No'))?>
|
||||
</select>
|
||||
|
||||
:WOL_run_VM_help:
|
||||
|
||||
_(Enable Shutdown actions)_:
|
||||
: <select name="RUNSHUT" >
|
||||
<?=mk_option($current['RUNSHUT'], "n", _('No'))?>
|
||||
<?=mk_option($current['RUNSHUT'], "y", _('Yes'))?>
|
||||
</select>
|
||||
|
||||
:WOL_run_shutdown_help:
|
||||
|
||||
_(Interface to listern on)_:
|
||||
: <select id="INTERFACE" name="INTERFACE" >
|
||||
<?=mk_option(_var($eth0,'INTERFACE'),'eth0','eth0','selected')?>
|
||||
<?foreach ($ports as $port):?>
|
||||
<?if (!locked('eth0',$port)) echo mk_option_check($current['INTERFACE'],$port,$port)?>
|
||||
<?endforeach;?>
|
||||
</select>
|
||||
|
||||
:WOL_interface_help:
|
||||
|
||||
_(Interface promiscuous mode)_:
|
||||
: <select id="IFMODE" name="IFMODE" >
|
||||
<?=mk_option($current['IFMODE'], "n", _('No'))?>
|
||||
<?=mk_option($current['IFMODE'], "y", _('Yes'))?>
|
||||
</select>
|
||||
|
||||
:WOL_promiscuous_mode_help:
|
||||
|
||||
_(Log file)_:
|
||||
: <input name="LOGFILE" class="narrow"type="text" value=<?=$current['LOGFILE']?>>
|
||||
|
||||
|
||||
:WOL_log_file_help:
|
||||
|
||||
|
||||
: <input type="submit" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
</form>
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
/usr/local/emhttp/plugins/dynamix/scripts/WOL_action load &
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
/usr/local/emhttp/plugins/dynamix/include/script/WOL_action stop &
|
||||
@@ -72,6 +72,57 @@ function my_devs(&$devs,$name,$menu) {
|
||||
}
|
||||
return implode($text);
|
||||
}
|
||||
function icon_class($ext) {
|
||||
switch ($ext) {
|
||||
case '3gp': case 'asf': case 'avi': case 'f4v': case 'flv': case 'm4v': case 'mkv': case 'mov': case 'mp4': case 'mpeg': case 'mpg': case 'm2ts': case 'ogm': case 'ogv': case 'vob': case 'webm': case 'wmv':
|
||||
return 'fa fa-film';
|
||||
case '7z': case 'bz2': case 'gz': case 'rar': case 'tar': case 'xz': case 'zip':
|
||||
return 'fa fa-file-archive-o';
|
||||
case 'aac': case 'ac3': case 'dsf': case 'flac': case 'm4a': case 'mka': case 'mp2': case 'mp3': case 'oga': case 'ogg': case 'tds': case 'wav': case 'wma':
|
||||
return 'fa fa-music';
|
||||
case 'ai': case 'eps': case 'fla': case 'psd': case 'swf':
|
||||
return 'fa fa-file-image-o';
|
||||
case 'avif': case 'bmp': case 'gif': case 'ico': case 'jp2': case 'jpc': case 'jpeg': case 'jpg': case 'jpx': case 'png': case 'svg': case 'tif': case 'tiff': case 'wbmp': case 'webp': case 'xbm':
|
||||
return 'fa fa-picture-o';
|
||||
case 'bak': case 'swp':
|
||||
return 'fa fa-clipboard';
|
||||
case 'bat':
|
||||
return 'fa fa-terminal';
|
||||
case 'bot': case 'cfg': case 'conf': case 'dat': case 'htaccess': case 'htpasswd': case 'ini': case 'log': case 'pl': case 'tmp': case 'toml': case 'top': case 'txt': case 'yaml': case 'yml':
|
||||
return 'fa fa-file-text-o';
|
||||
case 'c': case 'config': case 'cpp': case 'cs': case 'dtd': case 'exe': case 'ftpquota': case 'gitignore': case 'hbs': case 'json': case 'jsx': case 'lock': case 'map': case 'md': case 'msi': case 'passwd': case 'rs': case 'sh': case 'sql': case 'tpl': case 'ts': case 'tsx': case 'twig':
|
||||
return 'fa fa-file-code-o';
|
||||
case 'css': case 'less': case 'sass': case 'scss':
|
||||
return 'fa fa-css3';
|
||||
case 'csv':
|
||||
return 'fa fa-file-text-o';
|
||||
case 'cue': case 'm3u': case 'm3u8': case 'pls': case 'xspf':
|
||||
return 'fa fa-headphones';
|
||||
case 'doc': case 'docm': case 'docx': case 'dot': case 'dotm': case 'dotx': case 'odt':
|
||||
return 'fa fa-file-word-o';
|
||||
case 'eml': case 'msg':
|
||||
return 'fa fa-envelope-o';
|
||||
case 'eot': case 'fon': case 'otf': case 'ttc': case 'ttf': case 'woff': case 'woff2':
|
||||
return 'fa fa-font';
|
||||
case 'htm': case 'html': case 'shtml': case 'xhtml':
|
||||
return 'fa fa-html5';
|
||||
case 'js': case 'php': case 'php4': case 'php5': case 'phps': case 'phtml': case 'py':
|
||||
return 'fa fa-code';
|
||||
case 'key':
|
||||
return 'fa fa-key';
|
||||
case 'ods': case 'xla': case 'xls': case 'xlsb': case 'xlsm': case 'xlsx': case 'xlt': case 'xltm': case 'xltx':
|
||||
return 'fa fa-file-excel-o';
|
||||
case 'pdf':
|
||||
return 'fa fa-file-pdf-o';
|
||||
case 'pot': case 'potx': case 'ppt': case 'pptm': case 'pptx':
|
||||
return 'fa fa-file-powerpoint-o';
|
||||
case 'xml': case 'xsl':
|
||||
return 'fa fa-file-excel-o';
|
||||
default:
|
||||
return 'fa fa-file-o';
|
||||
}
|
||||
}
|
||||
|
||||
$dir = validdir(htmlspecialchars_decode(rawurldecode($_GET['dir'])));
|
||||
if (!$dir) {echo '<tbody><tr><td></td><td></td><td colspan="6">',_('Invalid path'),'</td><td></td></tr></tbody>'; exit;}
|
||||
|
||||
@@ -102,7 +153,7 @@ while (($row = fgets($stat))!==false) {
|
||||
$text = [];
|
||||
if ($type[0]=='d') {
|
||||
$text[] = '<tr><td><i id="check_'.$objs.'" class="fa fa-fw fa-square-o" onclick="selectOne(this.id)"></i></td>';
|
||||
$text[] = '<td data=""><div class="icon-dir"></div></td>';
|
||||
$text[] = '<td data=""><i class="fa fa-folder-o"></i></td>';
|
||||
$text[] = '<td><a id="name_'.$objs.'" oncontextmenu="folderContextMenu(this.id,\'right\');return false" href="/'.$path.'?dir='.rawurlencode(htmlspecialchars($name)).'">'.htmlspecialchars(basename($name)).'</a></td>';
|
||||
$text[] = '<td id="owner_'.$objs.'">'.$owner.'</td>';
|
||||
$text[] = '<td id="perm_'.$objs.'">'.$perm.'</td>';
|
||||
@@ -115,7 +166,7 @@ while (($row = fgets($stat))!==false) {
|
||||
$ext = strtolower(pathinfo($name,PATHINFO_EXTENSION));
|
||||
$tag = count($devs)>1 ? 'warning' : '';
|
||||
$text[] = '<tr><td><i id="check_'.$objs.'" class="fa fa-fw fa-square-o" onclick="selectOne(this.id)"></i></td>';
|
||||
$text[] = '<td class="ext" data="'.$ext.'"><div class="icon-file icon-'.$ext.'"></div></td>';
|
||||
$text[] = '<td class="ext" data="'.$ext.'"><i class="'.icon_class($ext).'"></i></td>';
|
||||
$text[] = '<td id="name_'.$objs.'" class="'.$tag.'" onclick="fileEdit(this.id)" oncontextmenu="fileContextMenu(this.id,\'right\');return false">'.htmlspecialchars(basename($name)).'</td>';
|
||||
$text[] = '<td id="owner_'.$objs.'" class="'.$tag.'">'.$owner.'</td>';
|
||||
$text[] = '<td id="perm_'.$objs.'" class="'.$tag.'">'.$perm.'</td>';
|
||||
@@ -128,6 +179,6 @@ while (($row = fgets($stat))!==false) {
|
||||
}
|
||||
}
|
||||
pclose($stat);
|
||||
if ($link = parent_link()) echo '<tbody class="tablesorter-infoOnly"><tr><td></td><td><div><img src="/webGui/icons/folderup.png"></div></td><td>',$link,'</td><td colspan="6"></td></tr></tbody>';
|
||||
if ($link = parent_link()) echo '<tbody class="tablesorter-infoOnly"><tr><td></td><td><i class="fa fa-folder-open-o"></i></td><td>',$link,'</td><td colspan="6"></td></tr></tbody>';
|
||||
echo write($dirs),write($files),'<tfoot><tr><td></td><td></td><td colspan="7">',add($objs,'object'),': ',add($dirs,'director','y','ies'),', ',add($files,'file'),' (',my_scale($total,$unit),' ',$unit,' ',_('total'),')</td></tr></tfoot>';
|
||||
?>
|
||||
|
||||
@@ -165,7 +165,7 @@ if ($_POST['vms']) {
|
||||
echo $vmhtml;
|
||||
}
|
||||
if (!count($vmusagehtml)) echo "<span id='no_usagevms'><br> "._('No running virtual machines')."<br></span>";
|
||||
if ($running < 1 && count($vmsusagehtml)) echo "<span id='no_usagevms'><br>". _('No running virtual machines')."<br></span>";
|
||||
if ($running < 1 && count($vmusagehtml)) echo "<span id='no_usagevms'><br>". _('No running virtual machines')."<br></span>";
|
||||
echo "</td></tr>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,4 +291,13 @@ function my_mkdir($dirname,$permissions = 0777,$recursive = false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
function get_realvolume($path) {
|
||||
if (strpos($path,"/mnt/user/",0) === 0)
|
||||
$reallocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($path)." 2>/dev/null"));
|
||||
else {
|
||||
$realexplode = explode("/",str_replace("/mnt/","",$path));
|
||||
$reallocation = $realexplode[0];
|
||||
}
|
||||
return $reallocation;
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -73,3 +73,11 @@ class KeyInstaller
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$getHasUrlParam = $_GET !== null && !empty($_GET) && isset($_GET['url']);
|
||||
|
||||
if ($isGetRequest && $getHasUrlParam) {
|
||||
$keyInstaller = new KeyInstaller();
|
||||
$keyInstaller->installKey();
|
||||
}
|
||||
|
||||
@@ -39,13 +39,13 @@ foreach ($files as $file) {
|
||||
$c = 0;
|
||||
foreach ($fields as $field) {
|
||||
if ($c==5) break;
|
||||
$text = $field ? explode('=',$field,2)[1] : "-";
|
||||
$text = $field ? (explode('=',$field,2)[1]??"") : "-";
|
||||
$tag = ($c<4) ? "" : " data='".str_replace(['alert','warning','normal'],['0','1','2'],$text)."'";
|
||||
echo (!$c++) ? "<tr>".str_replace('*',$text,$td_).date($dynamix['notify']['date'].' '.$dynamix['notify']['time'],$text)."$_td" : "<td$tag>"._($text)."</td>";
|
||||
}
|
||||
echo "<td><a href='#' onclick='$(this).hide();$.post(\"/webGui/include/DeleteLogFile.php\",{log:\"$archive\"},function(){archiveList();});return false' title=\""._('Delete notification')."\"><i class='fa fa-trash-o'></i></a></td></tr>";
|
||||
if ($extra) {
|
||||
$text = explode('=',$field,2)[1];
|
||||
$text = explode('=',$field,2)[1]??"";
|
||||
echo "<tr class='tablesorter-childRow row$row'><td colspan='4'>$text</td><td></td></tr><tr class='tablesorter-childRow row$row'><td colspan='5'></td></tr>";
|
||||
$row++;
|
||||
}
|
||||
|
||||
50
emhttp/plugins/dynamix/include/OutgoingProxy.php
Normal file
50
emhttp/plugins/dynamix/include/OutgoingProxy.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/* Copyright 2024, 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.
|
||||
*/
|
||||
|
||||
$opmPlugin = "dynamix";
|
||||
require_once("plugins/".$opmPlugin."/include/OutgoingProxyLib.php");
|
||||
|
||||
switch ($_POST['action']) {
|
||||
case 'proxy_status':
|
||||
/* Get the active proxy. */
|
||||
$proxy_active = urldecode($_POST['proxy_active']);
|
||||
|
||||
/* Get the proxy 1 status. */
|
||||
$proxy_1_url = urldecode($_POST['proxy_1_url']);
|
||||
if ($proxy_1_url) {
|
||||
$proxy_1_status = proxy_online($proxy_1_url) ? ($proxy_active == "1" ? "Active" : "") : ($proxy_active == "1" ? "Offline" : "Not Available");
|
||||
} else {
|
||||
$proxy_1_status = "";
|
||||
}
|
||||
|
||||
/* Get the proxy 2 status. */
|
||||
$proxy_2_url = urldecode($_POST['proxy_2_url']);
|
||||
if ($proxy_2_url) {
|
||||
$proxy_2_status = proxy_online($proxy_2_url) ? ($proxy_active == "2" ? "Active" : "") : ($proxy_active == "2" ? "Offline" : "Not Available");
|
||||
} else {
|
||||
$proxy_2_status = "";
|
||||
}
|
||||
/* Get the proxy 3 status. */
|
||||
$proxy_3_url = urldecode($_POST['proxy_3_url']);
|
||||
if ($proxy_3_url) {
|
||||
$proxy_3_status = proxy_online($proxy_3_url) ? ($proxy_active == "3" ? "Active" : "") : ($proxy_active == "3" ? "Offline" : "Not Available");
|
||||
} else {
|
||||
$proxy_3_status = "";
|
||||
}
|
||||
|
||||
echo json_encode(array( 'proxy_status_1' => $proxy_1_status, 'proxy_status_2' => $proxy_2_status, 'proxy_status_3' => $proxy_3_status ));
|
||||
break;
|
||||
|
||||
default:
|
||||
outgoingproxy_log("Undefined POST action - ".$_POST['action'].".");
|
||||
break;
|
||||
}
|
||||
?>
|
||||
191
emhttp/plugins/dynamix/include/OutgoingProxyLib.php
Normal file
191
emhttp/plugins/dynamix/include/OutgoingProxyLib.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/* Copyright 2024, 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.
|
||||
*/
|
||||
|
||||
$opmPlugin = "dynamix";
|
||||
|
||||
/* UI config file location. */
|
||||
$plg_config_file = "/boot/config/plugins/".$opmPlugin."/outgoingproxy.cfg";
|
||||
|
||||
/* Outgoing Proxy Manager logging tag. */
|
||||
$opm_log = "Outgoing Proxy Manager";
|
||||
|
||||
/* Outgoing Proxy logging. */
|
||||
function outgoingproxy_log($m) {
|
||||
global $opm_log;
|
||||
|
||||
$m = print_r($m,true);
|
||||
$m = str_replace("\n", " ", $m);
|
||||
$m = str_replace('"', "'", $m);
|
||||
exec("/usr/bin/logger"." ".escapeshellarg($m)." -t ".escapeshellarg($opm_log));
|
||||
}
|
||||
|
||||
/* Parse plugin config file. */
|
||||
function parse_plugin_config() {
|
||||
global $plg_config_file;
|
||||
|
||||
$cfg = is_file($plg_config_file) ? @parse_ini_file($plg_config_file, true) : array();
|
||||
|
||||
return($cfg);
|
||||
}
|
||||
|
||||
/* Write values to plugin config file. */
|
||||
function write_plugin_config($config) {
|
||||
global $plg_config_file;
|
||||
|
||||
/* Rewrite config file. */
|
||||
/* Convert the array to an INI string. */
|
||||
$iniString = '';
|
||||
foreach ($config as $key => $value) {
|
||||
$iniString .= "$key=\"$value\"\n";
|
||||
}
|
||||
|
||||
/* Write the INI string to a file. */
|
||||
file_put_contents($plg_config_file, $iniString);
|
||||
}
|
||||
|
||||
/* Check to see if the proxy is online and available. */
|
||||
function proxy_online($proxyUrl) {
|
||||
|
||||
$rc = true;
|
||||
|
||||
if ($proxyUrl) {
|
||||
/* Initialize cURL session. */
|
||||
$ch = curl_init("http://www.msftncsi.com/ncsi.txt");
|
||||
|
||||
/* Set cURL options. */
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); /* Timeout in seconds. */
|
||||
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, true);
|
||||
curl_setopt($ch, CURLOPT_PROXY, $proxyUrl); /* Url is a proxy. */
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); /* Return transfer as a string. */
|
||||
|
||||
/* Execute cURL request. */
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if ($response === false) {
|
||||
/* Proxy is not available. */
|
||||
$rc = false;
|
||||
}
|
||||
|
||||
/* Close cURL session. */
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
return ($rc);
|
||||
}
|
||||
|
||||
/* Get the URL with the user and password parsed from the url. */
|
||||
function get_proxy_info($cfg_url, $cfg_user = "", $cfg_pass = "") {
|
||||
/* Passed in values:
|
||||
cfg_url - can be with or without credentials (user and password).
|
||||
cfg_user - user from config file.
|
||||
cfg_pass - encrypted password from the config file.
|
||||
*/
|
||||
|
||||
/* An array is returned with the following values. */
|
||||
$return = [
|
||||
'url' => '', /* URL without credentials. */
|
||||
'user' => '', /* User. */
|
||||
'pass' => '', /* Unencrypted password. */
|
||||
'full_url' => '', /* Full URL with credentials urlencoded. */
|
||||
];
|
||||
|
||||
if ($cfg_url) {
|
||||
/* Decrypt password. */
|
||||
$cfg_pass = decrypt_data($cfg_pass);
|
||||
|
||||
/* Parse the URL by removing the user and password. */
|
||||
$urlComponents = parse_url($cfg_url);
|
||||
|
||||
/* Parse user, password, host, and port from stored URL. */
|
||||
$host = isset($urlComponents['host']) ? $urlComponents['host'] : '';
|
||||
$port = isset($urlComponents['port']) ? $urlComponents['port'] : '';
|
||||
$user = isset($urlComponents['user']) ? $urlComponents['user'] : '';
|
||||
$pass = isset($urlComponents['pass']) ? $urlComponents['pass'] : '';
|
||||
|
||||
/* Return array of url, user, and password. */
|
||||
$return['url'] = "http://".$host.':'.$port;
|
||||
|
||||
/* Extract the credentials. */
|
||||
if (strpos($cfg_url, '%') !== false) {
|
||||
/* The credentials are urlencoded. */
|
||||
$return['user'] = $user ? urldecode($user) : $cfg_user;
|
||||
$return['pass'] = $pass ? urldecode($pass) : $cfg_pass;
|
||||
} else {
|
||||
/* The credentials are not urlencoded. */
|
||||
$return['user'] = $user ? $user : $cfg_user;
|
||||
$return['pass'] = $pass ? $pass : $cfg_pass;
|
||||
}
|
||||
|
||||
/* Put together the full url. */
|
||||
if (($return['user']) && ($return['pass'])) {
|
||||
$return['full_url'] = "http://".urlencode($return['user']).":".urlencode($return['pass'])."@".$host.":".$port;
|
||||
} else {
|
||||
$return['full_url'] = $return['url'];
|
||||
}
|
||||
}
|
||||
|
||||
return($return);
|
||||
}
|
||||
|
||||
/* Get configuration parameter. */
|
||||
function get_config($variable) {
|
||||
|
||||
$config = parse_plugin_config();
|
||||
|
||||
return $config[$variable] ?? "";
|
||||
}
|
||||
|
||||
/* Set configuration parameter. */
|
||||
function set_config($variable, $value) {
|
||||
|
||||
$config = parse_plugin_config();
|
||||
|
||||
$config[$variable] = $value;
|
||||
|
||||
write_plugin_config($config);
|
||||
}
|
||||
|
||||
/* Encrypt data. */
|
||||
function encrypt_data($data) {
|
||||
$key = get_config("key");
|
||||
if ((! $key) || strlen($key) != 32) {
|
||||
$key = substr(base64_encode(openssl_random_pseudo_bytes(32)), 0, 32);
|
||||
set_config("key", $key);
|
||||
}
|
||||
$iv = get_config("iv");
|
||||
if ((! $iv) || strlen($iv) != 16) {
|
||||
$iv = substr(base64_encode(openssl_random_pseudo_bytes(16)), 0, 16);
|
||||
set_config("iv", $iv);
|
||||
}
|
||||
|
||||
/* Encrypt the data using aes256. */
|
||||
$value = trim(openssl_encrypt($data, 'aes256', $key, $options=0, $iv));
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/* Decrypt data. */
|
||||
function decrypt_data($data) {
|
||||
$key = get_config("key");
|
||||
$iv = get_config("iv");
|
||||
|
||||
/* Decrypt the data using aes256. */
|
||||
$value = openssl_decrypt($data, 'aes256', $key, $options=0, $iv);
|
||||
|
||||
/* Make sure the data is UTF-8 encoded. */
|
||||
if (! mb_check_encoding($value, 'UTF-8')) {
|
||||
outgoingproxy_log("Warning: Data is not UTF-8 encoded");
|
||||
$value = "";
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
?>
|
||||
@@ -73,7 +73,7 @@ case 't1load':
|
||||
} else {
|
||||
$supporturl = $module['supporturl'];
|
||||
$pluginname = $module['plugin'];
|
||||
$supporthtml = "<span id='link$modname'><a href='$supporturl' target='_blank'><i title='"._("Support page $pluginname")."' class='fa fa-phone-square'></i></a></span>";
|
||||
$supporthtml = "<span id='link$modname'><a href='$supporturl' target='_blank'><i title='"._("Support page")." $pluginname' class='fa fa-phone-square'></i></a></span>";
|
||||
}
|
||||
}
|
||||
if (!empty($module["version"])) $version = " (".$module["version"].")"; else $version = "";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* 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,
|
||||
@@ -12,353 +12,15 @@
|
||||
?>
|
||||
<?
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = 'settings';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
function host_lookup_ip($host) {
|
||||
$result = @dns_get_record($host, DNS_A);
|
||||
$ip = $result ? _var($result[0],'ip') : '';
|
||||
return($ip);
|
||||
}
|
||||
function rebindDisabled() {
|
||||
global $isLegacyCert;
|
||||
$rebindtesturl = $isLegacyCert ? "rebindtest.unraid.net" : "rebindtest.myunraid.net";
|
||||
// DNS Rebind Protection - this checks the server but clients could still have issues
|
||||
$validResponse = ["192.168.42.42", "fd42"];
|
||||
$response = host_lookup_ip($rebindtesturl);
|
||||
return in_array(explode('::',$response)[0], $validResponse);
|
||||
}
|
||||
function format_port($port) {
|
||||
return ($port != 80 && $port != 443) ? ':'.$port : '';
|
||||
}
|
||||
function anonymize_host($host) {
|
||||
global $anon;
|
||||
if ($anon) {
|
||||
$host = preg_replace('/.*\.myunraid\.net/', '*.hash.myunraid.net', $host);
|
||||
$host = preg_replace('/.*\.unraid\.net/', 'hash.unraid.net', $host);
|
||||
}
|
||||
return $host;
|
||||
}
|
||||
function anonymize_ip($ip) {
|
||||
global $anon;
|
||||
if ($anon && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
|
||||
$ip = "[redacted]";
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
function generate_internal_host($host, $ip) {
|
||||
if (strpos($host,'.myunraid.net') !== false) {
|
||||
$host = str_replace('*', str_replace('.', '-', $ip), $host);
|
||||
}
|
||||
return $host;
|
||||
}
|
||||
function generate_external_host($host, $ip) {
|
||||
if (strpos($host,'.myunraid.net') !== false) {
|
||||
$host = str_replace('*', str_replace('.', '-', $ip), $host);
|
||||
} elseif (strpos($host,'.unraid.net') !== false) {
|
||||
$host = "www.".$host;
|
||||
}
|
||||
return $host;
|
||||
}
|
||||
function verbose_output($httpcode, $result) {
|
||||
global $cli, $verbose, $anon, $plgversion, $post, $var, $isRegistered, $myservers, $reloadNginx, $nginx, $isLegacyCert;
|
||||
global $remoteaccess;
|
||||
global $icon_warn, $icon_ok;
|
||||
if (!$cli || !$verbose) return;
|
||||
|
||||
if ($anon) echo "(Output is anonymized, use '-vv' to see full details)".PHP_EOL;
|
||||
echo "Unraid OS "._var($var,'version','???').((strpos($plgversion, "base-") === false) ? " with My Servers plugin version {$plgversion}" : '').PHP_EOL;
|
||||
echo ($isRegistered) ? "{$icon_ok}Signed in to Unraid.net as {$myservers['remote']['username']}".PHP_EOL : "{$icon_warn}Not signed in to Unraid.net".PHP_EOL ;
|
||||
echo "Use SSL is "._var($nginx,'NGINX_USESSL','No').PHP_EOL;
|
||||
echo (rebindDisabled()) ? "{$icon_ok}Rebind protection is disabled" : "{$icon_warn}Rebind protection is enabled";
|
||||
echo " for ".($isLegacyCert ? "unraid.net" : "myunraid.net").PHP_EOL;
|
||||
if ($post) {
|
||||
$wanip = trim(@file_get_contents("https://wanip4.unraid.net/"));
|
||||
// check the data
|
||||
$certhostname = _var($nginx,'NGINX_CERTNAME');
|
||||
if ($certhostname) {
|
||||
// $certhostname is $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
|
||||
$certhostip = host_lookup_ip(generate_internal_host($certhostname, _var($post,'internalip')));
|
||||
$certhosterr = ($certhostip != _var($post,'internalip'));
|
||||
}
|
||||
if (_var($post,'internalhostname') != $certhostname) {
|
||||
// $post['internalhostname'] is $nginx['NGINX_LANMDNS'] (no cert, or Server_unraid_bundle.pem) || $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
|
||||
$internalhostip = host_lookup_ip(generate_internal_host(_var($post,'internalhostname'), _var($post,'internalip')));
|
||||
$internalhosterr = ($internalhostip != _var($post,'internalip'));
|
||||
}
|
||||
if (!empty($post['externalhostname'])) {
|
||||
// $post['externalhostname'] is $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
|
||||
$externalhostip = host_lookup_ip(generate_external_host($post['externalhostname'], $wanip));
|
||||
$externalhosterr = ($externalhostip != $wanip);
|
||||
}
|
||||
// anonymize data. no caclulations can be done with this data beyond this point.
|
||||
if ($anon) {
|
||||
if (!empty($certhostip)) $certhostip = anonymize_ip($certhostip);
|
||||
if (!empty($certhostname)) $certhostname = anonymize_host($certhostname);
|
||||
if (!empty($internalhostip)) $internalhostip = anonymize_ip($internalhostip);
|
||||
if (!empty($externalhostip)) $externalhostip = anonymize_ip($externalhostip);
|
||||
if (!empty($wanip)) $wanip = anonymize_ip($wanip);
|
||||
if (!empty($post['internalip'])) $post['internalip'] = anonymize_ip($post['internalip']);
|
||||
if (!empty($post['internalhostname'])) $post['internalhostname'] = anonymize_host($post['internalhostname']);
|
||||
if (!empty($post['externalhostname'])) $post['externalhostname'] = anonymize_host($post['externalhostname']);
|
||||
if (!empty($post['externalport'])) $post['externalport'] = "[redacted]";
|
||||
}
|
||||
// always anonymize the keyfile
|
||||
if (!empty($post['keyfile'])) $post['keyfile'] = "[redacted]";
|
||||
// output notes
|
||||
if (!empty($post['internalprotocol']) && !empty($post['internalhostname']) && !empty($post['internalport'])) {
|
||||
$localurl = $post['internalprotocol']."://".generate_internal_host($post['internalhostname'], _var($post,'internalip')).format_port($post['internalport']);
|
||||
echo 'Local Access url: '.$localurl.PHP_EOL;
|
||||
if ($internalhostip) {
|
||||
// $internalhostip will not be defined for .local domains, ok to skip
|
||||
echo ($internalhosterr) ? $icon_warn : $icon_ok;
|
||||
echo generate_internal_host($post['internalhostname'], _var($post,'internalip'))." resolves to {$internalhostip}";
|
||||
echo ($internalhosterr) ? ", it should resolve to "._var($post,'internalip') : "";
|
||||
echo PHP_EOL;
|
||||
}
|
||||
if ($certhostname) {
|
||||
echo ($certhosterr) ? $icon_warn : $icon_ok;
|
||||
echo generate_internal_host($certhostname, _var($post,'internalip')).' ';
|
||||
echo ($certhostip) ? "resolves to {$certhostip}" : "does not resolve to an IP address";
|
||||
echo ($certhosterr) ? ", it should resolve to "._var($post,'internalip') : "";
|
||||
echo PHP_EOL;
|
||||
}
|
||||
if ($remoteaccess == 'yes' && !empty($post['externalprotocol']) && !empty($post['externalhostname']) && !empty($post['externalport'])) {
|
||||
$remoteurl = $post['externalprotocol']."://".generate_external_host($post['externalhostname'], $wanip).format_port($post['externalport']);
|
||||
echo 'Remote Access url: '.$remoteurl.PHP_EOL;
|
||||
echo ($externalhosterr) ? $icon_warn : $icon_ok;
|
||||
echo generate_external_host($post['externalhostname'], $wanip).' ';
|
||||
echo ($externalhosterr) ? "does not resolve to an IP address" : "resolves to ".($externalhostip??'');
|
||||
echo PHP_EOL;
|
||||
}
|
||||
if ($reloadNginx) {
|
||||
echo "IP address changes were detected, nginx was reloaded".PHP_EOL;
|
||||
}
|
||||
}
|
||||
// output post data
|
||||
echo PHP_EOL.'Request:'.PHP_EOL;
|
||||
echo @json_encode($post, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL;
|
||||
}
|
||||
if ($result) {
|
||||
echo "Response (HTTP $httpcode):".PHP_EOL;
|
||||
$mutatedResult = is_array($result) ? json_encode($result) : $result;
|
||||
echo @json_encode(@json_decode($mutatedResult, true), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @name response_complete
|
||||
* @param {HTTP Response Status Code} $httpcode https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
||||
* @param {String|Array} $result - strings are assumed to be encoded JSON. Arrays will be encoded to JSON.
|
||||
* @param {String} $cli_success_msg
|
||||
*/
|
||||
function response_complete($httpcode, $result, $cli_success_msg='') {
|
||||
global $cli, $verbose;
|
||||
$mutatedResult = is_array($result) ? json_encode($result) : $result;
|
||||
if ($cli) {
|
||||
if ($verbose) verbose_output($httpcode, $result);
|
||||
$json = @json_decode($mutatedResult,true);
|
||||
if (!empty($json['error'])) {
|
||||
echo 'Error: '.$json['error'].PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
exit($cli_success_msg.PHP_EOL);
|
||||
}
|
||||
header('Content-Type: application/json');
|
||||
http_response_code($httpcode);
|
||||
exit((string)$mutatedResult);
|
||||
}
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
// This is a stub, does nothing but return success
|
||||
my_logger("This is a stub and should not be called", "UpdateDNS");
|
||||
$cli = php_sapi_name()=='cli';
|
||||
$verbose = $anon = false;
|
||||
if ($cli && ($argc > 1) && $argv[1] == "-v") {
|
||||
$verbose = true;
|
||||
$anon = true;
|
||||
}
|
||||
if ($cli && ($argc > 1) && $argv[1] == "-vv") {
|
||||
$verbose = true;
|
||||
}
|
||||
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
$nginx = (array)@parse_ini_file('/var/local/emhttp/nginx.ini');
|
||||
$is69 = version_compare(_var($var,'version'),"6.9.9","<");
|
||||
$reloadNginx = false;
|
||||
$dnserr = false;
|
||||
$icon_warn = "⚠️ ";
|
||||
$icon_ok = "✅ ";
|
||||
|
||||
$myservers_flash_cfg_path='/boot/config/plugins/dynamix.my.servers/myservers.cfg';
|
||||
$myservers = (array)@parse_ini_file($myservers_flash_cfg_path,true);
|
||||
// ensure some vars are defined here so we don't have to test them later
|
||||
if (empty($myservers['remote']['apikey'])) {
|
||||
$myservers['remote']['apikey'] = "";
|
||||
}
|
||||
if (empty($myservers['remote']['wanaccess'])) {
|
||||
$myservers['remote']['wanaccess'] = "no";
|
||||
}
|
||||
if (empty($myservers['remote']['wanport'])) {
|
||||
$myservers['remote']['wanport'] = 443;
|
||||
}
|
||||
// remoteaccess, externalport
|
||||
if ($cli) {
|
||||
$remoteaccess = empty($nginx['NGINX_WANFQDN']) ? 'no' : 'yes';
|
||||
$externalport = $myservers['remote']['wanport'];
|
||||
} else {
|
||||
$remoteaccess = _var($_POST,'remoteaccess','no');
|
||||
$externalport = intval(_var($_POST,'externalport',443));
|
||||
|
||||
if ($remoteaccess != 'yes') {
|
||||
$remoteaccess = 'no';
|
||||
}
|
||||
|
||||
if ($externalport < 1 || $externalport > 65535) {
|
||||
$externalport = 443;
|
||||
}
|
||||
|
||||
if ($myservers['remote']['wanaccess'] != $remoteaccess) {
|
||||
// update the wanaccess ini value
|
||||
$orig = file_exists($myservers_flash_cfg_path) ? parse_ini_file($myservers_flash_cfg_path,true) : [];
|
||||
if (!$orig) {
|
||||
$orig = ['remote' => $myservers['remote']];
|
||||
}
|
||||
$orig['remote']['wanaccess'] = $remoteaccess;
|
||||
$text = '';
|
||||
foreach ($orig as $section => $block) {
|
||||
$pairs = "";
|
||||
foreach ($block as $key => $value) if (strlen($value)) $pairs .= "$key=\"$value\"\n";
|
||||
if ($pairs) $text .= "[$section]\n".$pairs;
|
||||
}
|
||||
if ($text) file_put_contents($myservers_flash_cfg_path, $text);
|
||||
// need nginx reload
|
||||
$reloadNginx = true;
|
||||
}
|
||||
exit("success".PHP_EOL);
|
||||
}
|
||||
$isRegistered = !empty($myservers['remote']['username']);
|
||||
|
||||
// protocols, hostnames, ports
|
||||
$internalprotocol = 'http';
|
||||
$internalport = _var($nginx,'NGINX_PORT');
|
||||
$internalhostname = _var($nginx,'NGINX_LANMDNS');
|
||||
$externalprotocol = 'https';
|
||||
// keyserver will expand *.hash.myunraid.net or add www to hash.unraid.net as needed
|
||||
$externalhostname = _var($nginx,'NGINX_CERTNAME');
|
||||
$isLegacyCert = preg_match('/.*\.unraid\.net$/', _var($nginx,'NGINX_CERTNAME'));
|
||||
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', _var($nginx,'NGINX_CERTNAME'));
|
||||
$internalip = _var($nginx,'NGINX_LANIP');
|
||||
|
||||
if (_var($nginx,'NGINX_USESSL')=='yes') {
|
||||
// When NGINX_USESSL is 'yes' in 6.9, it could be using either Server_unraid_bundle.pem or certificate_bundle.pem
|
||||
// When NGINX_USESSL is 'yes' in 6.10, it is is using Server_unraid_bundle.pem
|
||||
$internalprotocol = 'https';
|
||||
$internalport = _var($nginx,'NGINX_PORTSSL');
|
||||
if ($is69 && _var($nginx,'NGINX_CERTNAME')) {
|
||||
// this is from certificate_bundle.pem
|
||||
$internalhostname = _var($nginx,'NGINX_CERTNAME');
|
||||
}
|
||||
}
|
||||
if (_var($nginx,'NGINX_USESSL')=='auto') {
|
||||
// NGINX_USESSL cannot be 'auto' in 6.9, it is either 'yes' or 'no'
|
||||
// When NGINX_USESSL is 'auto' in 6.10, it is using certificate_bundle.pem
|
||||
$internalprotocol = 'https';
|
||||
$internalport = _var($nginx,'NGINX_PORTSSL');
|
||||
// keyserver will expand *.hash.myunraid.net as needed
|
||||
$internalhostname = _var($nginx,'NGINX_CERTNAME');
|
||||
}
|
||||
|
||||
// My Servers version
|
||||
$plgversion = file_exists("/var/log/plugins/dynamix.unraid.net.plg") ? trim(exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
|
||||
: (file_exists("/var/log/plugins/dynamix.unraid.net.staging.plg") ? trim(exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
|
||||
: 'base-'._var($var,'version'));
|
||||
|
||||
// only proceed when when signed in or when legacy unraid.net SSL certificate exists
|
||||
if (!$isRegistered && !$isLegacyCert) {
|
||||
response_complete(406, ['error' => _('Nothing to do')]);
|
||||
}
|
||||
|
||||
// keyfile
|
||||
$keyfile = empty($var['regFILE']) ? false : @file_get_contents($var['regFILE']);
|
||||
if ($keyfile === false) {
|
||||
response_complete(406, ['error' => _('Registration key required')]);
|
||||
}
|
||||
$keyfile = @base64_encode($keyfile);
|
||||
|
||||
// build post array
|
||||
$post = [
|
||||
'keyfile' => $keyfile,
|
||||
'plgversion' => $plgversion
|
||||
];
|
||||
if ($isLegacyCert) {
|
||||
// sign in not required to maintain local ddns for unraid.net cert
|
||||
// enable local ddns regardless of use_ssl value
|
||||
$post['internalip'] = $internalip;
|
||||
// if host.unraid.net does not resolve to the internalip and DNS Rebind Protection is disabled, disable caching
|
||||
if (host_lookup_ip(generate_internal_host(_var($nginx,'NGINX_CERTNAME'), $post['internalip'])) != $post['internalip'] && rebindDisabled()) $dnserr = true;
|
||||
}
|
||||
if ($isRegistered) {
|
||||
// if signed in, send data needed to maintain My Servers Dashboard
|
||||
$post['internalhostname'] = $internalhostname;
|
||||
$post['internalport'] = $internalport;
|
||||
$post['internalprotocol'] = $internalprotocol;
|
||||
$post['remoteaccess'] = $remoteaccess;
|
||||
$post['servercomment'] = _var($var,'COMMENT');
|
||||
$post['servername'] = _var($var,'NAME');
|
||||
if ($isWildcardCert) {
|
||||
// keyserver needs the internalip to generate the local access url
|
||||
$post['internalip'] = $internalip;
|
||||
}
|
||||
if ($remoteaccess == 'yes') {
|
||||
// include wanip in the cache file so we can track if it changes
|
||||
$post['_wanip'] = trim(@file_get_contents("https://wanip4.unraid.net/"));
|
||||
$post['externalhostname'] = $externalhostname;
|
||||
$post['externalport'] = $externalport;
|
||||
$post['externalprotocol'] = $externalprotocol;
|
||||
// if wanip.hash.myunraid.net or www.hash.unraid.net does not resolve to the wanip, disable caching
|
||||
if (host_lookup_ip(generate_external_host($post['externalhostname'], $post['_wanip'])) != $post['_wanip']) $dnserr = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if remoteaccess is enabled in 6.10.0-rc3+ and WANIP has changed since nginx started, reload nginx
|
||||
if (_var($post,'_wanip') != _var($nginx,'NGINX_WANIP') && version_compare(_var($var,'version'),"6.10.0-rc2",">")) $reloadNginx = true;
|
||||
// if remoteaccess is currently disabled (perhaps because a wanip was not available when nginx was started)
|
||||
// BUT the system is configured to have it enabled AND a wanip is now available
|
||||
// then reload nginx
|
||||
if ($remoteaccess == 'no' && _var($nginx,'NGINX_WANACCESS') == 'yes' && !empty(trim(@file_get_contents("https://wanip4.unraid.net/")))) $reloadNginx = true;
|
||||
if ($reloadNginx) {
|
||||
exec("/etc/rc.d/rc.nginx reload &>/dev/null");
|
||||
}
|
||||
|
||||
// maxage is 36 hours
|
||||
$maxage = 36*60*60;
|
||||
if ($dnserr || $verbose) $maxage = 0;
|
||||
$datafile = "/tmp/UpdateDNS.txt";
|
||||
$datafiletmp = "/tmp/UpdateDNS.txt.new";
|
||||
$dataprev = @file_get_contents($datafile) ?: '';
|
||||
$datanew = implode("\n",$post)."\n";
|
||||
if ($datanew == $dataprev && (time()-filemtime($datafile) < $maxage)) {
|
||||
response_complete(204, null, _('No change to report'));
|
||||
}
|
||||
file_put_contents($datafiletmp,$datanew);
|
||||
rename($datafiletmp, $datafile);
|
||||
|
||||
// do not submit the wanip, it will be captured from the submission if needed for remote access
|
||||
unset($post['_wanip']);
|
||||
|
||||
// report necessary server details to limetech for DNS updates
|
||||
$ch = curl_init('https://keys.lime-technology.com/account/server/register');
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$result = curl_exec($ch);
|
||||
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ( ($result === false) || ($httpcode != "200") ) {
|
||||
// delete cache file to retry submission on next run
|
||||
@unlink($datafile);
|
||||
response_complete($httpcode ?? "500", ['error' => $error]);
|
||||
}
|
||||
|
||||
response_complete($httpcode, $result, _('success'));
|
||||
header('Content-Type: application/json');
|
||||
http_response_code(204);
|
||||
exit(0);
|
||||
?>
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
<?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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
global $lv;
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/SysDriversHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = 'tools';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt.php";
|
||||
|
||||
function macbyte($val) {
|
||||
if ($val < 16)
|
||||
return '0'.dechex($val);
|
||||
|
||||
return dechex($val);
|
||||
}
|
||||
|
||||
$arrEntries = [];
|
||||
$vms = $lv->get_domains() ?:[];
|
||||
sort($vms,SORT_NATURAL);
|
||||
foreach($vms as $vm){
|
||||
$arrEntries['VM'][$vm]['interfaces'] = $lv->get_nic_info($vm);
|
||||
$arrEntries['VM'][$vm]['name'] = $vm;
|
||||
}
|
||||
|
||||
$DockerClient = new DockerClient();
|
||||
$containers = $DockerClient->getDockerJSON("/containers/json?all=1");
|
||||
foreach($containers as $ct)
|
||||
$arrEntries['Docker'][substr($ct["Names"][0],1)] = [
|
||||
'interfaces' => ['0 '=> ['mac' => isset($ct["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]) ? $ct["NetworkSettings"]["Networks"]["bridge"]["MacAddress"] : ""]],
|
||||
'name' => substr($ct["Names"][0],1),
|
||||
];
|
||||
|
||||
$lxc = explode("\n",shell_exec("lxc-ls -1")) ;
|
||||
$lxcpath = trim(shell_exec("lxc-config lxc.lxcpath"));
|
||||
foreach ($lxc as $lxcname) {
|
||||
if ($lxcname == "") continue;
|
||||
$value = explode("=",shell_exec("cat $lxcpath/$lxcname/config | grep 'hwaddr'"));
|
||||
$arrEntries['LXC'][$lxcname]['interfaces'][0]['mac'] = trim($value[1]);
|
||||
$arrEntries['LXC'][$lxcname]['name'] = $lxcname;
|
||||
}
|
||||
|
||||
if (is_file("/boot/config/wol.json")) $user_mac = json_decode(file_get_contents("/boot/config/wol.json"),true); else $user_mac = [];
|
||||
|
||||
foreach($arrEntries as $key => $data) {
|
||||
$type=$key;
|
||||
foreach($data as $data2){
|
||||
$name=$data2['name'];
|
||||
if (isset($user_mac[$type][$name])) {
|
||||
$name=$name;
|
||||
$arrEntries[$type][$name]['enable'] = $user_mac[$type][$name]['enable'];
|
||||
$arrEntries[$type][$name]['user_mac'] = strtolower($user_mac[$type][$name]['user_mac']);
|
||||
} else {
|
||||
$arrEntries[$type][$name]['enable'] = 'enable';
|
||||
$arrEntries[$type][$name]['user_mac'] = 'None Defined';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch ($_POST['table']) {
|
||||
|
||||
case 't1load':
|
||||
$arrMacs = $arrEntries;
|
||||
$html = "<thead><tr><th>"._('Service')."</th><th>"._('Name')."</th><th>"._('Mac Address')."</th><th>"._('Enabled')."</th><th>"._('User Mac Address')."</th></tr></thead>";
|
||||
$html .= "<tbody>";
|
||||
ksort($arrMacs);
|
||||
foreach($arrMacs as $systype => $m) {
|
||||
foreach($m as $macaddr) {
|
||||
if ($systype == "") continue;
|
||||
|
||||
$html .= "<tr id='row$systype'>";
|
||||
$macs = "";
|
||||
foreach($macaddr['interfaces'] as $intdetail)
|
||||
{
|
||||
$macs .= " {$intdetail['mac']}" ;
|
||||
}
|
||||
$html .= "<td>$systype</td>";
|
||||
$selecttypename="enable;".$systype.";".$macaddr['name'];
|
||||
$mactypename=htmlspecialchars("user_mac;".$systype.";".$macaddr['name']);
|
||||
$mactypeid=htmlspecialchars("user_mac".$systype."".$macaddr['name']);
|
||||
$user_mac_str = '<input type="text" name="'.$mactypename.'" id="'.$mactypeid.'" class="narrow" value="'.htmlspecialchars($macaddr['user_mac']).'" title="'._("random mac, you can supply your own").'" /><a><i onclick="maccreate(\''.$mactypeid.'\')" class="fa fa-refresh mac_generate" title="re-generate random mac address"></i></a>';
|
||||
$html .= "<td>{$macaddr['name']}</td><td id=\"status$systype\">$macs</td><td>";
|
||||
$html .="<select name='$selecttypename' class='audio narrow'>";
|
||||
$html .= mk_option($macaddr["enable"] , "disable", _("Disabled"));
|
||||
$html .= mk_option($macaddr["enable"] , "enable", _("Enabled"));
|
||||
$html .= mk_option($macaddr["enable"] , "shutdown", _("Enabled and Shutdown"));
|
||||
$html .= "</select></td><td>".$user_mac_str."</td></tr>";
|
||||
$text = "";
|
||||
}
|
||||
}
|
||||
if (count($arrMacs) < 1) {
|
||||
$html .= "<tr id='row'>";
|
||||
$html .= "<td></td><td></td><td>"._("No Entries")."</td><td></td><td></td></tr>";
|
||||
}
|
||||
$html .= "</tbody>";
|
||||
|
||||
$rtn = array();
|
||||
$rtn['html'] = $html;
|
||||
echo json_encode($rtn);
|
||||
break;
|
||||
|
||||
case "macaddress":
|
||||
$seed = 1;
|
||||
$prefix = '62:00:00';
|
||||
$prefix .=':'.macbyte(($seed * rand()) % 256).':'.macbyte(($seed * rand()) % 256).':'.macbyte(($seed * rand()) % 256);
|
||||
echo json_encode(['mac' => $prefix]);
|
||||
break;
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,180 +0,0 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/Custom.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
||||
function getContainerStats($container, $option) {
|
||||
exec("lxc-info " . $container, $content);
|
||||
foreach($content as $index => $string) {
|
||||
if (strpos($string, $option) !== FALSE)
|
||||
return trim(explode(':', $string)[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$mac = strtolower($argv[1]);
|
||||
|
||||
$libvirtd_running = is_file('/var/run/libvirt/libvirtd.pid') ;
|
||||
$dockerd_running = is_file('/var/run/dockerd.pid');
|
||||
$lxc_ls_exist = is_file('/usr/bin/lxc-ls');
|
||||
#$RUNDOCKER = $RUNLXC = $RUNVM = true;
|
||||
extract(parse_ini_file("/boot/config/wol.cfg")) ;
|
||||
if (!isset($RUNLXC)) $RUNLXC = "y";
|
||||
if (!isset($RUNVM)) $RUNVM = "y";
|
||||
if (!isset($RUNDocker)) $RUNDocker = "y";
|
||||
if (!isset($RUNSHUT)) $RUNSHUT = "n";
|
||||
|
||||
$arrEntries = [] ;
|
||||
if ($libvirtd_running && $RUNVM == "y") {
|
||||
$vms = $lv->get_domains();
|
||||
sort($vms,SORT_NATURAL);
|
||||
foreach($vms as $vm){
|
||||
$arrEntries['VM'][$vm]['interfaces'] = $lv->get_nic_info($vm);
|
||||
$arrEntries['VM'][$vm]['name'] = $vm;
|
||||
}
|
||||
}
|
||||
if ($dockerd_running && $RUNDOCKER == "y") {
|
||||
$DockerClient = new DockerClient();
|
||||
$containers = $DockerClient->getDockerJSON("/containers/json?all=1");
|
||||
foreach($containers as $container)
|
||||
$arrEntries['Docker'][ substr($container["Names"][0],1) ] = [
|
||||
'interfaces' => ['0' => ['mac' => isset($container["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]) ? $container["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]:""]],
|
||||
'name' => substr($container["Names"][0],1),
|
||||
'state' => $container["State"],
|
||||
];
|
||||
}
|
||||
|
||||
if ($lxc_ls_exist && $RUNLXC == "y") {
|
||||
$lxc = explode("\n",shell_exec("lxc-ls -1")) ;
|
||||
$lxcpath = trim(shell_exec("lxc-config lxc.lxcpath"));
|
||||
foreach ($lxc as $lxcname) {
|
||||
if ($lxcname == "") continue;
|
||||
$values = explode("=",shell_exec("cat $lxcpath/$lxcname/config | grep 'hwaddr'"));
|
||||
$arrEntries['LXC'][$lxcname]['interfaces'][0]['mac'] = trim($values[1]);
|
||||
$arrEntries['LXC'][$lxcname]['name'] = $lxcname;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file("/boot/config/wol.json")) $user_mac = json_decode(file_get_contents("/boot/config/wol.json"),true); else $user_mac = [];
|
||||
|
||||
foreach($arrEntries as $typekey => $typedata)
|
||||
{
|
||||
foreach($typedata as $typeEntry){
|
||||
$name=$typeEntry['name'];
|
||||
if (isset($user_mac[$typekey][$name])) {
|
||||
|
||||
$name=$name;
|
||||
|
||||
$arrEntries[$typekey][$name]['enable'] = $user_mac[$typekey][$name]['enable'];
|
||||
$arrEntries[$typekey][$name]['user_mac'] = strtolower($user_mac[$typekey][$name]['user_mac']);
|
||||
|
||||
} else {
|
||||
$arrEntries[$typekey][$name]['enable'] = "enable";
|
||||
$arrEntries[$typekey][$name]['user_mac'] = 'None Defined';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$mac_list=[];
|
||||
foreach($arrEntries as $type => $detail)
|
||||
{
|
||||
foreach($detail as $name => $entryDetail)
|
||||
{
|
||||
foreach($entryDetail['interfaces'] as $interfaces)
|
||||
{
|
||||
$interfaces['mac'] = strtolower($interfaces['mac']);
|
||||
if($interfaces['mac'] == "" && $entryDetail['user_mac'] == "None Defined") continue;
|
||||
if (isset($entryDetail['state'])) $state = $entryDetail['state']; else $state = "";
|
||||
if (isset($entryDetail['enable']) && !$entryDetail['enable'] ) $enable = false; else $enable = true;
|
||||
if ($entryDetail['user_mac'] != "None Defined") {
|
||||
$mac_list[$entryDetail['user_mac']] = [
|
||||
'type' => $type,
|
||||
'name' => $name,
|
||||
'state' => $state,
|
||||
'enable' => $entryDetail['enable'],
|
||||
];
|
||||
}
|
||||
if ($interfaces['mac'] != "") {
|
||||
$mac_list[$interfaces['mac']] = [
|
||||
'type' => $type,
|
||||
'name' => $name,
|
||||
'state' => $state,
|
||||
'enable' => $entryDetail['enable'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$found = array_key_exists($mac,$mac_list);
|
||||
|
||||
|
||||
if ($found && $mac_list[$mac]['enable'] != "disable") {
|
||||
echo _("Found"). " " . $mac . " " .$mac_list[$mac]['type'] . " " . $mac_list[$mac]['name'];
|
||||
switch ($mac_list[$mac]['type']) {
|
||||
|
||||
case "VM":
|
||||
if ($libvirtd_running && $RUNVM == "y") {
|
||||
$res = $lv->get_domain_by_name($mac_list[$mac]['name']);
|
||||
$dom = $lv->domain_get_info($res);
|
||||
$state = $lv->domain_state_translate($dom['state']);
|
||||
switch ($state) {
|
||||
case 'running':
|
||||
if ($RUNSHUT == "y" && $mac_list[$mac]['enable'] == "shutdown") $lv->domain_shutdown("{$mac_list[$mac]['name']}");
|
||||
break;
|
||||
case 'paused':
|
||||
case 'pmsuspended':
|
||||
$lv->domain_resume("{$mac_list[$mac]['name']}");
|
||||
break;
|
||||
default:
|
||||
$lv->domain_start("{$mac_list[$mac]['name']}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "LXC":
|
||||
if ($lxc_ls_exist && $RUNLXC == "y") {
|
||||
$state = getContainerStats($mac_list[$mac]['name'], "State");
|
||||
switch ($state) {
|
||||
case 'RUNNING':
|
||||
if ($RUNSHUT == "y" && $mac_list[$mac]['enable'] == "shutdown") shell_exec("lxc-stop {$mac_list[$mac]['name']}");
|
||||
break;
|
||||
case 'FROZEN':
|
||||
shell_exec("lxc-unfreeze {$mac_list[$mac]['name']}");
|
||||
break;
|
||||
default:
|
||||
shell_exec("lxc-start {$mac_list[$mac]['name']}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "Docker":
|
||||
if ($dockerd_running && $RUNDOCKER == "y") {
|
||||
|
||||
switch ($mac_list[$mac]['state']) {
|
||||
case "running":
|
||||
if ($RUNSHUT == "y" && $mac_list[$mac]['enable'] == "shutdown") shell_exec("docker stop {$mac_list[$mac]['name']}");
|
||||
break;
|
||||
case "exited":
|
||||
case "created":
|
||||
shell_exec("docker start {$mac_list[$mac]['name']}");
|
||||
break;
|
||||
case "paused":
|
||||
shell_exec("docker unpause {$mac_list[$mac]['name']}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ($mac_list[$mac]['enable'] == "disable") echo $mac . " " . _(" has not been actioned as set to disabled");
|
||||
else echo _("Not Found"). " " . $mac . " " . _("ignoring or Maybe actions disabled for type(Docker/VM/LXC)");
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -149,4 +149,56 @@ function my_date($fmt, $time) {
|
||||
function my_logger($message, $logger='webgui') {
|
||||
exec('logger -t '.escapeshellarg($logger).' -- '.escapeshellarg($message));
|
||||
}
|
||||
// Original PHP code by Chirp Internet: www.chirpinternet.eu
|
||||
// Please acknowledge use of this code by including this header.
|
||||
// https://www.the-art-of-web.com/php/http-get-contents/
|
||||
// Modified for Unraid
|
||||
/**
|
||||
* Fetches URL and returns content
|
||||
* @param string $url The URL to fetch
|
||||
* @param array $opts Array of options to pass to curl_setopt()
|
||||
* @param array $getinfo Empty array passed by reference, will contain results of curl_getinfo and curl_error
|
||||
* @return string|false $out The fetched content
|
||||
*/
|
||||
function http_get_contents(string $url, array $opts = [], array &$getinfo = NULL) {
|
||||
$ch = curl_init();
|
||||
if(isset($getinfo)) {
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 45);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, "");
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_REFERER, "");
|
||||
curl_setopt($ch, CURLOPT_FAILONERROR, true);
|
||||
if(is_array($opts) && $opts) {
|
||||
foreach($opts as $key => $val) {
|
||||
curl_setopt($ch, $key, $val);
|
||||
}
|
||||
}
|
||||
$out = curl_exec($ch);
|
||||
if(isset($getinfo)) {
|
||||
$getinfo = curl_getinfo($ch);
|
||||
}
|
||||
if (curl_errno($ch)) {
|
||||
$msg = curl_error($ch) . " {$url}";
|
||||
if(isset($getinfo)) {
|
||||
$getinfo['error'] = $msg;
|
||||
}
|
||||
my_logger($msg, "http_get_contents");
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
/**
|
||||
* Detect network connectivity via Network Connectivity Status Indicator
|
||||
* @return bool
|
||||
*/
|
||||
function check_network_connectivity(): bool {
|
||||
$url = 'http://www.msftncsi.com/ncsi.txt';
|
||||
$out = http_get_contents($url);
|
||||
return ($out=="Microsoft NCSI");
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -39,4 +39,8 @@ if ($_SERVER['SCRIPT_NAME'] != '/login.php' && $_SERVER['SCRIPT_NAME'] != '/auth
|
||||
if ($var['csrf_token'] != $_POST['csrf_token']) csrf_terminate("wrong");
|
||||
unset($_POST['csrf_token']);
|
||||
}
|
||||
$proxy_cfg = (array)@parse_ini_file('/var/local/emhttp/proxy.ini',true);
|
||||
putenv('http_proxy='.((array_key_exists('http_proxy', $proxy_cfg)) ? $proxy_cfg['http_proxy'] : ''));
|
||||
putenv('https_proxy='.((array_key_exists('https_proxy', $proxy_cfg)) ? $proxy_cfg['https_proxy'] : ''));
|
||||
putenv('no_proxy='.((array_key_exists('http_proxy', $proxy_cfg)) ? $proxy_cfg['no_proxy'] : ''));
|
||||
?>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<?
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = 'settings';
|
||||
@@ -425,11 +426,10 @@ case 'public':
|
||||
$ip = _var($_POST,'#ip');
|
||||
$v4 = _var($_POST,'#prot')!='6';
|
||||
$v6 = _var($_POST,'#prot')!='';
|
||||
$context = stream_context_create(['https'=>['timeout'=>12]]);
|
||||
$int_ipv4 = $v4 ? (preg_match("/^$validIP4$/",$ip) ? $ip : (@dns_get_record($ip,DNS_A)[0]['ip'] ?: '')) : '';
|
||||
$ext_ipv4 = $v4 ? (@file_get_contents('https://wanip4.unraid.net',false,$context) ?: '') : '';
|
||||
$ext_ipv4 = $v4 ? (http_get_contents('https://wanip4.unraid.net') ?: '') : '';
|
||||
$int_ipv6 = $v6 ? (preg_match("/^$validIP6$/",$ip) ? $ip : (@dns_get_record($ip,DNS_AAAA)[0]['ipv6'] ?: '')) : '';
|
||||
$ext_ipv6 = $v6 ? (@file_get_contents('https://wanip6.unraid.net',false,$context) ?: '') : '';
|
||||
$ext_ipv6 = $v6 ? (http_get_contents('https://wanip6.unraid.net') ?: '') : '';
|
||||
echo "$int_ipv4;$ext_ipv4;$int_ipv6;$ext_ipv6";
|
||||
break;
|
||||
case 'addtunnel':
|
||||
|
||||
@@ -78,7 +78,7 @@ function device_info(&$disk,$online) {
|
||||
$help .= "<br>"._("Click to spin $action device");
|
||||
}
|
||||
$status = "<a class='info'><i ".($ctrl?"id='dev-$named' ":"")."class='fa fa-$orb orb $color-orb'$ctrl></i><span>$help</span></a>";
|
||||
$link = (($parity || $data || $pool) && !str_contains($disk_status,'_NP')) || $name=='flash' || in_array($name,$pools) || $type=='New'
|
||||
$link = (($parity || $data || $pool) && $disk_status!='DISK_NP') || $name=='flash' || in_array($name,$pools) || $type=='New'
|
||||
? "<a href=\"".htmlspecialchars("/Main/Settings/$source?name=$name")."\">$fancy</a>"
|
||||
: $fancy;
|
||||
return $view.$status.$link;
|
||||
|
||||
@@ -20,10 +20,12 @@ require_once "$docroot/webGui/include/publish.php";
|
||||
|
||||
while (true) {
|
||||
$echo = shell_exec("$notify get");
|
||||
$md5_new = md5($echo,true);
|
||||
if ($md5_new !== $md5_old) {
|
||||
publish('notify', $echo);
|
||||
$md5_old = $md5_new;
|
||||
if ( $echo ) {
|
||||
$md5_new = md5($echo,true);
|
||||
if ($md5_new !== $md5_old) {
|
||||
publish('notify', $echo);
|
||||
$md5_old = $md5_new;
|
||||
}
|
||||
}
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/publish.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
global $vmusagestats;
|
||||
exec("/etc/rc.d/rc.libvirt status >/dev/null",$dummy,$libvirtd);
|
||||
$libvirtd = $libvirtd==0;
|
||||
if (!$libvirtd) return;
|
||||
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
get_vm_usage_stats();
|
||||
sleep(1);
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# script: WOL_action
|
||||
#
|
||||
# Startup script for unraidwold
|
||||
#
|
||||
# Simon Fairweather - Initial Script October 2023
|
||||
|
||||
DAEMON="unraidwold"
|
||||
BINARY="/usr/local/bin/unraidwold"
|
||||
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
. /boot/config/wol.cfg
|
||||
|
||||
unraidwold_running(){
|
||||
sleep 0.1
|
||||
ps axc | grep -q ' unraidwold'
|
||||
}
|
||||
|
||||
unraidwold_start(){
|
||||
log "Starting $DAEMON..."
|
||||
local REPLY
|
||||
if unraidwold_running; then
|
||||
REPLY="Already started"
|
||||
else
|
||||
nohup $BINARY $1 $2 $3 $4 $5 $6 > /dev/null &
|
||||
fi
|
||||
log "$DAEMON... $REPLY."
|
||||
}
|
||||
|
||||
unraidwold_stop(){
|
||||
log "Stopping $DAEMON..."
|
||||
local REPLY
|
||||
if ! unraidwold_running; then
|
||||
REPLY="Already stopped"
|
||||
else
|
||||
killall -TERM $DAEMON
|
||||
if ! unraidwold_running; then REPLY="Stopped"; else REPLY="Failed"; fi
|
||||
fi
|
||||
log "$DAEMON... $REPLY."
|
||||
}
|
||||
|
||||
unraidwold_status(){
|
||||
if unraidwold_running; then
|
||||
echo "$DAEMON is currently running."
|
||||
else
|
||||
echo "$DAEMON is not running."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
unraidwold_load()
|
||||
{
|
||||
if unraidwold_running; then
|
||||
unraidwold_stop
|
||||
fi
|
||||
sleep 1
|
||||
if [ "$WOLENABLED" == "yes" ]; then
|
||||
interfacemode=""
|
||||
logoptions=""
|
||||
|
||||
if [ "$IFMODE" == "y" ]; then
|
||||
interfacemode="--promiscuous"
|
||||
fi
|
||||
|
||||
if [ "$LOGFILE" != "syslog" ]; then
|
||||
logoptions="--log $LOGFILE"
|
||||
fi
|
||||
|
||||
unraidwold_start --interface $INTERFACE $interfacemode $logoptions
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start')
|
||||
unraidwold_start $2 $3 $4 $5 $6
|
||||
;;
|
||||
'stop')
|
||||
unraidwold_stop
|
||||
;;
|
||||
'status')
|
||||
unraidwold_status
|
||||
;;
|
||||
'load')
|
||||
unraidwold_load
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $BDAEMON start|stop|restart|status"
|
||||
exit 1
|
||||
esac
|
||||
exit 0
|
||||
@@ -25,6 +25,7 @@ $zip = $all ? ($argv[2]??'') : ($argv[1]??'');
|
||||
$cli = empty($zip);
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
$folders = ['/boot','/boot/config','/boot/config/plugins','/boot/syslinux','/var/log','/var/log/plugins','/boot/extra','/var/log/packages','/var/lib/pkgtools/packages','/tmp'];
|
||||
@@ -115,16 +116,6 @@ function maskIP($file) {
|
||||
// anonymize full IPv6 addresses
|
||||
run("sed -ri 's/([\"\[ ]([0-9a-f]{1,4}:){4})(([0-9a-f]{1,4}:){3}|:)([0-9a-f]{1,4})([/\" .]|$)/\\1XXXX:XXXX:XXXX:\\5\\6/g' ".escapeshellarg($file)." 2>/dev/null");
|
||||
}
|
||||
|
||||
function cache_only($disk) {
|
||||
return _var($disk,'type')=='Cache';
|
||||
}
|
||||
function cache_filter($disks) {
|
||||
return array_filter($disks,'cache_only');
|
||||
}
|
||||
function pools_filter($disks) {
|
||||
return array_unique(array_map('prefix',array_keys(cache_filter($disks))));
|
||||
}
|
||||
function download_url($url, $path="", $bg=false, $timeout=15) {
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch,[
|
||||
@@ -661,6 +652,13 @@ if (file_exists($dhcplog)) {
|
||||
if (!$all) maskIP($log);
|
||||
}
|
||||
|
||||
// copy phplog
|
||||
$phplog = "/var/log/phplog";
|
||||
if (file_exists($phplog)) {
|
||||
$log = "/$diag/logs/phplog.txt";
|
||||
run("todos <$phplog >".escapeshellarg($log));
|
||||
}
|
||||
|
||||
// copy graphql-api.log
|
||||
$graphql = "/var/log/graphql-api.log";
|
||||
if (file_exists($graphql)) {
|
||||
|
||||
111
emhttp/plugins/dynamix/scripts/outgoingproxy
Executable file
111
emhttp/plugins/dynamix/scripts/outgoingproxy
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
/* Copyright 2024, 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.
|
||||
*/
|
||||
|
||||
$opmPlugin = "dynamix";
|
||||
require_once("plugins/".$opmPlugin."/include/OutgoingProxyLib.php");
|
||||
|
||||
/* Save settings and update config. */
|
||||
function apply() {
|
||||
global $opmPlugin, $plg_config_file;
|
||||
|
||||
/* Process the new configuration. */
|
||||
$cfg = parse_plugin_config();
|
||||
|
||||
/* Generate encryption keys if they have not been generated. */
|
||||
if ((! isset($cfg['key'])) || (! isset($cfg['iv']))) {
|
||||
/* Doing an encryption will generate keys. */
|
||||
encrypt_data("test");
|
||||
|
||||
/* Get new keys. */
|
||||
$cfg['key'] = get_config("key");
|
||||
$cfg['iv'] = get_config("iv");
|
||||
}
|
||||
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$proxy_name = "proxy_name_".$i;
|
||||
$name = trim($cfg[$proxy_name]);
|
||||
$proxy_url = "proxy_url_".$i;
|
||||
$url = trim($cfg[$proxy_url]);
|
||||
$proxy_user = "proxy_user_".$i;
|
||||
$proxy_pass = "proxy_pass_".$i;
|
||||
if (($name) && ($url)) {
|
||||
/* Confirm the url is in the proper format. */
|
||||
if (strpos($url, 'http://') !== false && preg_match('/:\d+$/', $url)) {
|
||||
/* The string contains 'http://' and a port designation at the end */
|
||||
|
||||
/* Parse the URL components. */
|
||||
$urlComponents = parse_url($url);
|
||||
|
||||
/* Replace user and password in the url. */
|
||||
$host = $urlComponents['host'] ?? "";
|
||||
$port = $urlComponents['port'] ?? "";
|
||||
$user = $urlComponents['user'] ?? "";
|
||||
$pass = $urlComponents['pass'] ?? "";
|
||||
|
||||
/* Remove credentials from the entered URL. */
|
||||
$cfg[$proxy_url] = "http://".$host.':'.$port;
|
||||
|
||||
/* Use the entered user if not blank. */
|
||||
$cfg_user = $cfg[$proxy_user] ?? "";
|
||||
$cfg[$proxy_user] = $cfg_user ? $cfg_user : urldecode($user);
|
||||
$encodedUser = (strpos($cfg[$proxy_user], '%') === false) ? urlencode($cfg[$proxy_user]) : $cfg[$proxy_user];
|
||||
|
||||
/* Use the entered pass if not blank. */
|
||||
$cfg_pass = $cfg[$proxy_pass] ?? "";
|
||||
$cfg[$proxy_pass] = $cfg_pass ? $cfg_pass : urldecode($pass);
|
||||
$encodedPass = (strpos($cfg[$proxy_pass], '%') === false) ? urlencode($cfg[$proxy_pass]) : $cfg[$proxy_pass];
|
||||
$cfg[$proxy_pass] = encrypt_data($cfg[$proxy_pass]);
|
||||
} else {
|
||||
/* The string does not contain 'http://' and/or a port designation at the end */
|
||||
$cfg[$proxy_url] = "";
|
||||
}
|
||||
} else if (! $name) {
|
||||
$cfg[$proxy_url] = "";
|
||||
}
|
||||
}
|
||||
|
||||
/* Rewrite config file. */
|
||||
/* Convert the array to an INI string. */
|
||||
$iniString = '';
|
||||
foreach ($cfg as $key => $value) {
|
||||
$iniString .= "$key=\"$value\"\n";
|
||||
}
|
||||
|
||||
/* Write the INI string to the plugin config file. */
|
||||
file_put_contents($plg_config_file, $iniString);
|
||||
|
||||
/* Let things settle. */
|
||||
sleep(1);
|
||||
|
||||
/* Now run the proxy setup script. */
|
||||
if (is_executable("/usr/local/sbin/set_proxy")) {
|
||||
exec("/usr/local/sbin/set_proxy 1>/dev/null");
|
||||
|
||||
outgoingproxy_log("'set_proxy' script executed");
|
||||
} else {
|
||||
outgoingproxy_log("'set_proxy' script does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
/* Main entry point, */
|
||||
switch ($argv[1]) {
|
||||
case 'apply':
|
||||
apply();
|
||||
break;
|
||||
|
||||
default:
|
||||
echo("Error: 'outgoingproxy {$argv[1]}' not understood\n");
|
||||
echo("outgoingproxy usage: 'apply'\n");
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
?>
|
||||
@@ -35,7 +35,7 @@ if [[ -n $local_server ]]; then
|
||||
sed -ri "\$a\\\$InputUDPServerBindRuleset remote\n\\\$UDPServerRun ${server_port:-514}" $ETC
|
||||
[[ $server_protocol == udp ]] && sed -ri 's/^(\$ModLoad imtcp)/#\1/;/^\$InputTCPServerBindRuleset remote$/d;/^\$InputTCPServerRun [0-9]+$/d' $ETC
|
||||
fi
|
||||
sed -ri "/^\\\$template remote,.*$/d;/^#\\\$UDPServerRun [0-9]+.*$/a\\\$template remote,\"${server_folder:-/mnt/user/system}/syslog-%FROMHOST-IP%.log\"" $ETC
|
||||
sed -ri "/^\\\$template remote,.*$/d;/^#\\\$UDPServerRun [0-9]+.*$/a\\\$template remote,\"${server_folder:-/mnt/user/system}/${server_filename:-syslog-%FROMHOST-IP%.log}\"" $ETC
|
||||
else
|
||||
sed -ri '/^\$RuleSet remote$/d;/^\$FileOwner nobody$/d;/^\$FileGroup users$/d;/^\$FileCreateMode 06[46][46]$/d;/^\$IncludeConfig \/etc\/rsyslog\.d\/\*\.conf # remote$/d;/^\*\.\* \?remote$/d;/^\$template remote,".*"$/d;/^\$Input(TCP|UDP)ServerBindRuleset remote$/d;/^\$(InputTCP|UDP)ServerRun [0-9]+$/d;s/^#?\$(ModLoad imtcp|ModLoad imudp)/#\$\1/' $ETC
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* 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,
|
||||
@@ -21,6 +21,7 @@ $disks = (array)@parse_ini_file("/var/local/emhttp/disks.ini",true);
|
||||
require_once "$docroot/webGui/include/CustomMerge.php";
|
||||
|
||||
$script = "$docroot/webGui/scripts/notify";
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg("dynamix",true));
|
||||
$output = _var($notify,'report');
|
||||
$server = strtoupper(_var($var,'NAME','tower'));
|
||||
@@ -178,7 +179,8 @@ $warn = ($error0 || $error3) ? "alert" : (($error1 || $error2) ? "warning" : "no
|
||||
$stat = $warn=="normal" ? "[PASS]" : "[FAIL]";
|
||||
$info = "Array has $size disk".($size==1 ? "" : "s").($parity ? " ({$word}parity".($pools ? " & pools)" : ")") : ($pools ? " ({$word}pools)" : ""));
|
||||
$message = implode('\n', $data);
|
||||
exec("$script -s ".escapeshellarg("Notice [$server] - array health report $stat")." -d ".escapeshellarg("$info")." -m ".escapeshellarg("$message")." -i ".escapeshellarg("$warn $output")." -l '/Main'");
|
||||
$subject = "Notice [$server] - array health report $stat";
|
||||
exec("$script -s ".escapeshellarg($subject)." -d ".escapeshellarg("$info")." -m ".escapeshellarg("$message")." -i ".escapeshellarg("$warn $output")." -l '/Main'");
|
||||
|
||||
exit(0);
|
||||
?>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
table#t1{margin-top:0;font-family:clear-sans}
|
||||
table#t1 thead tr th{font-weight:bold}
|
||||
table#t1 tbody tr td{padding:4px 20px 4px 0;margin:0;text-align:left;white-space:normal}
|
||||
table#t1 tbody tr td:nth-child(1){width:10%}
|
||||
table#t1 tbody tr td:nth-child(2){width:30%}
|
||||
table#t1 tbody tr td:nth-child(3){width:15%}
|
||||
table#t1 tbody tr td:nth-child(4){width:20%}
|
||||
table#t1 tbody tr td:nth-child(5){width:25%;padding-right:0}
|
||||
table.t1.tablesorter .filtered{display:none}
|
||||
.tablesorter-header-inner{font-family:clear-sans;font-weight:bold}
|
||||
#macform .mac_generate{cursor:pointer;margin-left:-5px;color:#08C;font-size:1.3rem;transform:translate(0px, 2px)}
|
||||
@@ -122,7 +122,9 @@ table.unraid thead tr:first-child>td{font-size:1.2rem;text-transform:uppercase;l
|
||||
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(0,0,0,0.05)}
|
||||
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
|
||||
table.unraid tr>td:hover{overflow:visible}
|
||||
table.legacy{table-layout:auto}
|
||||
table.legacy{table-layout:auto!important}
|
||||
table.legacy thead td{line-height:normal;height:auto;padding:7px 0}
|
||||
table.legacy tbody td{line-height:normal;height:auto;padding:5px 0}
|
||||
table.disk_status{table-layout:fixed}
|
||||
table.disk_status tr>td:last-child{padding-right:8px}
|
||||
table.disk_status tr>td:nth-child(1){width:13%}
|
||||
|
||||
@@ -120,7 +120,9 @@ table.unraid tbody tr:nth-child(even){background-color:#212121}
|
||||
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(255,255,255,0.1)}
|
||||
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
|
||||
table.unraid tr>td:hover{overflow:visible}
|
||||
table.legacy{table-layout:auto}
|
||||
table.legacy{table-layout:auto!important}
|
||||
table.legacy thead td{line-height:normal;height:auto;padding:7px 0}
|
||||
table.legacy tbody td{line-height:normal;height:auto;padding:5px 0}
|
||||
table.disk_status{table-layout:fixed}
|
||||
table.disk_status tr>td:last-child{padding-right:8px}
|
||||
table.disk_status tr>td:nth-child(1){width:13%}
|
||||
|
||||
@@ -122,7 +122,9 @@ table.unraid thead tr:first-child>td{font-size:1.2rem;text-transform:uppercase;l
|
||||
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(255,255,255,0.05)}
|
||||
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
|
||||
table.unraid tr>td:hover{overflow:visible}
|
||||
table.legacy{table-layout:auto}
|
||||
table.legacy{table-layout:auto!important}
|
||||
table.legacy thead td{line-height:normal;height:auto;padding:7px 0}
|
||||
table.legacy tbody td{line-height:normal;height:auto;padding:5px 0}
|
||||
table.disk_status{table-layout:fixed}
|
||||
table.disk_status tr>td:last-child{padding-right:8px}
|
||||
table.disk_status tr>td:nth-child(1){width:13%}
|
||||
|
||||
@@ -120,7 +120,9 @@ table.unraid tbody tr:nth-child(even){background-color:#ededed}
|
||||
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(0,0,0,0.1)}
|
||||
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
|
||||
table.unraid tr>td:hover{overflow:visible}
|
||||
table.legacy{table-layout:auto}
|
||||
table.legacy{table-layout:auto!important}
|
||||
table.legacy thead td{line-height:normal;height:auto;padding:7px 0}
|
||||
table.legacy tbody td{line-height:normal;height:auto;padding:5px 0}
|
||||
table.disk_status{table-layout:fixed}
|
||||
table.disk_status tr>td:last-child{padding-right:8px}
|
||||
table.disk_status tr>td:nth-child(1){width:13%}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.jGrowl{position:fixed;font-size:1.3rem}
|
||||
.jGrowl{position:fixed;font-size:1.3rem;z-index:10001}
|
||||
.jGrowl.top-left{left:10px;top:90px}
|
||||
.jGrowl.top-right{right:10px;top:90px}
|
||||
.jGrowl.bottom-left{left:10px;bottom:24px}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.jGrowl{position:fixed;font-size:1.3rem}
|
||||
.jGrowl{position:fixed;font-size:1.3rem;z-index:10001}
|
||||
.jGrowl.top-left{left:10px;top:130px}
|
||||
.jGrowl.top-right{right:10px;top:130px}
|
||||
.jGrowl.bottom-left{left:10px;bottom:24px}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.jGrowl{position:fixed;font-size:1.3rem}
|
||||
.jGrowl{position:fixed;font-size:1.3rem;z-index:10001}
|
||||
.jGrowl.top-left{left:10px;top:90px}
|
||||
.jGrowl.top-right{right:10px;top:90px}
|
||||
.jGrowl.bottom-left{left:10px;bottom:24px}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.jGrowl{position:fixed;font-size:1.3rem}
|
||||
.jGrowl{position:fixed;font-size:1.3rem;z-index:10001}
|
||||
.jGrowl.top-left{left:10px;top:130px}
|
||||
.jGrowl.top-right{right:10px;top:130px}
|
||||
.jGrowl.bottom-left{left:10px;bottom:24px}
|
||||
|
||||
@@ -43,13 +43,16 @@ flush();
|
||||
$docroot = $_SERVER['DOCUMENT_ROOT'];
|
||||
if (isset($_POST['#file'])) {
|
||||
$file = $_POST['#file'];
|
||||
$raw_file = isset($_POST['#raw_file']) ? ($_POST['#raw_file'] === 'true') : false;
|
||||
// prepend with boot (flash) if path is relative
|
||||
if ($file && $file[0]!='/') $file = "/boot/config/plugins/$file";
|
||||
$section = $_POST['#section'] ?? false;
|
||||
$cleanup = isset($_POST['#cleanup']);
|
||||
$default = ($file && isset($_POST['#default'])) ? @parse_ini_file("$docroot/plugins/".basename(dirname($file))."/default.cfg", $section) : [];
|
||||
|
||||
$keys = is_file($file) ? (parse_ini_file($file, $section) ?: []) : [];
|
||||
// if the file is not a raw file, it can be parsed
|
||||
$keys = (is_file($file) && !$raw_file) ? (parse_ini_file($file, $section) ?: []) : [];
|
||||
|
||||
// the 'save' switch can be reset by the include file to disallow settings saving
|
||||
$save = true;
|
||||
if (isset($_POST['#include'])) {
|
||||
|
||||
@@ -50,7 +50,7 @@ fi
|
||||
# initrd has already done so):
|
||||
if [[ -d /run ]]; then
|
||||
if ! /bin/grep -wq "tmpfs /run tmpfs" /proc/mounts; then
|
||||
/sbin/mount -v -n -t tmpfs tmpfs /run -o mode=0755,size=32M,nodev,nosuid,noexec
|
||||
/sbin/mount -v -n -t tmpfs tmpfs /run -o mode=0755,size=128M,nodev,nosuid,noexec
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ if /bin/grep -wq cgroup /proc/filesystems; then
|
||||
if [[ -d /sys/fs/cgroup ]]; then
|
||||
# See https://docs.kernel.org/admin-guide/cgroup-v2.html (section Mounting)
|
||||
# Mount cgroup2 filesystem
|
||||
mount -t cgroup2 -o rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot cgroup2 /sys/fs/cgroup
|
||||
/sbin/mount -t cgroup2 -o rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot cgroup2 /sys/fs/cgroup
|
||||
else
|
||||
# Display message if /sys/fs/cgroup does not exist
|
||||
echo "/sys/fs/cgroup does not exist. cgroup2 cannot be mounted."
|
||||
|
||||
@@ -42,7 +42,8 @@ SYSTEM="/sys/devices/system/cpu"
|
||||
# provides power savings on Intel processors while avoiding the ramp-up lag
|
||||
# present when using the powersave governor (which is the default if ondemand
|
||||
# is requested on these machines):
|
||||
if [[ $(cat $SYSTEM/cpu0/cpufreq/scaling_driver 2>/dev/null) == intel_pstate ]]; then
|
||||
if [[ $(cat $SYSTEM/cpu0/cpufreq/scaling_driver 2>/dev/null) == intel_pstate ||
|
||||
$(cat $SYSTEM/cpu0/cpufreq/scaling_driver 2>/dev/null) == amd-pstate-epp ]]; then
|
||||
SCALING_GOVERNOR="performance"
|
||||
fi
|
||||
|
||||
|
||||
@@ -501,7 +501,7 @@ docker_container_start(){
|
||||
log "$CONTAINER: $OUT" &
|
||||
else
|
||||
run container_add_route $CONTAINER
|
||||
log "$CONTAINER: started succesfully!" &
|
||||
log "$CONTAINER: started successfully!" &
|
||||
if [[ $WAIT -gt 0 ]]; then
|
||||
log "$CONTAINER: wait $WAIT seconds" &
|
||||
sleep $WAIT
|
||||
@@ -566,7 +566,7 @@ docker_service_stop(){
|
||||
run ip link del docker0
|
||||
fi
|
||||
REPLY="Stopped"
|
||||
# signal succesful stop
|
||||
# signal successful stop
|
||||
TIMER=-1
|
||||
else
|
||||
# show waiting message
|
||||
|
||||
@@ -69,7 +69,10 @@
|
||||
# Adapted by Bergware for use in Unraid OS - December 2023
|
||||
# - remove leading zeros in IPv4 and IPv6 addresses
|
||||
|
||||
# Bergware - modified for Unraid OS, December 2023
|
||||
# Adapted by Bergware for use in Unraid OS - February 2024
|
||||
# - revised bond interface creation for linux kernel 6.6.14 and later point releases
|
||||
|
||||
# Bergware - modified for Unraid OS, February 2024
|
||||
|
||||
###########
|
||||
# LOGGING #
|
||||
@@ -175,8 +178,8 @@ bond_up(){
|
||||
for BONDIF in ${BONDNICS[$i]}; do
|
||||
if [[ -e $SYSTEM/$BONDIF ]]; then
|
||||
[[ -z $PRIMARY ]] && PRIMARY=$BONDIF
|
||||
run ip link set $BONDIF down
|
||||
run ip link set $BONDIF master ${BONDNAME[$i]} up type bond_slave
|
||||
run ip link set $BONDIF up
|
||||
run ip link set $BONDIF master ${BONDNAME[$i]} down type bond_slave
|
||||
else
|
||||
[[ $DEBUG_ETH_UP == yes ]] && log "interface $BONDIF not present, can't add to ${BONDNAME[$i]}"
|
||||
fi
|
||||
|
||||
@@ -237,6 +237,7 @@ libvirtd_start(){
|
||||
|
||||
check_processor
|
||||
modprobe -a $MODULE $MODULES
|
||||
echo 0 > /sys/module/kvm/parameters/report_ignored_msrs
|
||||
libvirtd -d -l $LIBVIRTD_OPTS
|
||||
log "$DAEMON... Started."
|
||||
}
|
||||
|
||||
@@ -14,6 +14,28 @@
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
|
||||
# import CA proxy
|
||||
UnProxy=/boot/config/plugins/dynamix/outgoingproxy.cfg
|
||||
CAProxy=/boot/config/plugins/community.applications/proxy.cfg
|
||||
if [[ -f "${CAProxy}" && ! -f "${UnProxy}" ]]; then
|
||||
proxy=
|
||||
port=
|
||||
. "${CAProxy}"
|
||||
# proxy and port were set by the previous command
|
||||
if [[ -n "${proxy}" && -n "${port}" ]]; then
|
||||
cat << EOF > "${UnProxy}"
|
||||
proxy_active="1"
|
||||
proxy_url_1="${proxy}:${port}"
|
||||
proxy_name_1="Imported from CA"
|
||||
EOF
|
||||
fi
|
||||
mv "${CAProxy}" "${CAProxy}.bak"
|
||||
fi
|
||||
|
||||
# load proxy environment vars so it is used for plugin updates and the go script
|
||||
/usr/local/sbin/set_proxy
|
||||
[[ -x /etc/profile.d/proxy.sh ]] && . /etc/profile.d/proxy.sh
|
||||
|
||||
# irqbalance daemon distributes interrupts over processors and cores
|
||||
# if [[ -x /usr/sbin/irqbalance ]]; then
|
||||
# /usr/sbin/irqbalance
|
||||
@@ -69,7 +91,7 @@ rm -f /boot/plugins/unRAIDServer.plg
|
||||
rm -f $CONFIG/plugins/unRAIDServer.plg
|
||||
|
||||
# These plugins are now integrated in the OS or obsolete and may interfere
|
||||
OBSOLETE="vfio.pci dynamix.wireguard dynamix.ssd.trim dynamix.file.manager gui.search unlimited-width"
|
||||
OBSOLETE="vfio.pci dynamix.wireguard dynamix.ssd.trim dynamix.file.manager gui.search unlimited-width proxy.editor"
|
||||
for PLUGIN in $OBSOLETE; do
|
||||
if [[ -e $CONFIG/plugins/$PLUGIN.plg ]]; then
|
||||
log "moving obsolete plugin $PLUGIN.plg to $CONFIG/plugins-error"
|
||||
@@ -166,6 +188,21 @@ if [[ $PERSISTENT_BASH_HISTORY == 1 ]]; then
|
||||
ln -s /boot/config/history/bash_history /root/.bash_history
|
||||
fi
|
||||
|
||||
# cleanup the 'go' script
|
||||
# delete non-commented line with emhttp and trailing & (could also have leading env vars)
|
||||
# add new line with call to emhttp (preserve any params to emhttp and CRLF line endings)
|
||||
GOTEST1='^[^#]*/usr/local/sbin/emhttp(.*)&(.*)$'
|
||||
if grep -q -E "$GOTEST1" $CONFIG/go; then
|
||||
cp $CONFIG/go $CONFIG/go~
|
||||
sed -i -E "s@$GOTEST1@/usr/local/sbin/emhttp\1\2@g" $CONFIG/go
|
||||
fi
|
||||
# delete lines added by ProxyEditor
|
||||
GOTEST2='# Added by ProxyEditor'
|
||||
if grep -q "$GOTEST2" $CONFIG/go; then
|
||||
[[ ! -f $CONFIG/go~ ]] && cp $CONFIG/go $CONFIG/go~
|
||||
sed -i "/$GOTEST2/d" $CONFIG/go
|
||||
fi
|
||||
|
||||
# Invoke the 'go' script
|
||||
if [[ -f $CONFIG/go ]]; then
|
||||
log "Starting go script"
|
||||
|
||||
@@ -686,8 +686,6 @@ nginx_reload(){
|
||||
if nginx_check; then
|
||||
log "Reloading $DAEMON configuration..."
|
||||
kill -HUP $(cat $PID)
|
||||
# update DNS
|
||||
php -f /usr/local/emhttp/webGui/include/UpdateDNS.php
|
||||
sleep 3
|
||||
else
|
||||
log "Invalid configuration, $DAEMON not reloaded"
|
||||
@@ -705,8 +703,6 @@ nginx_renew(){
|
||||
build_ssl
|
||||
# start unconditionally
|
||||
$NGINX -c $CONF 2>/dev/null
|
||||
# update DNS
|
||||
php -f /usr/local/emhttp/webGui/include/UpdateDNS.php
|
||||
}
|
||||
|
||||
nginx_update(){
|
||||
|
||||
@@ -227,7 +227,7 @@ mv $INI ${INI%.*}
|
||||
|
||||
log "interface=${interface:-$1}, reason=$reason, protocol=$protocol"
|
||||
# delayed execution
|
||||
/usr/local/emhttp/webGui/scripts/update_services 30
|
||||
/usr/local/emhttp/webGui/scripts/update_services 45
|
||||
|
||||
# send update information
|
||||
if [[ -n $DATA && -e /var/run/nginx.socket ]]; then
|
||||
|
||||
@@ -3,7 +3,7 @@ DISABLE="no"
|
||||
source /boot/config/domain.cfg
|
||||
if [ $DISABLE == "yes" ]
|
||||
then
|
||||
printf '%s\n' "Start/autostart is disabled in VM settings." >&2 ## Send message to stderr.
|
||||
printf '\n%s\n' "Start/autostart is disabled in VM settings." >&2 ## Send message to stderr.
|
||||
exit 1 ;
|
||||
fi
|
||||
eval exec /usr/bin/qemu-system-x86_64 $(/usr/local/emhttp/plugins/dynamix.vm.manager/scripts/qemu.php "$@")
|
||||
156
sbin/set_proxy
Executable file
156
sbin/set_proxy
Executable file
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
/**
|
||||
* script: set_proxy
|
||||
*
|
||||
* Copyright 2005-2024, Lime Technology
|
||||
*
|
||||
* Call this script (/usr/local/sbin/set_proxy.php) to set up proxy files.
|
||||
*/
|
||||
|
||||
$opmPlugin = "dynamix";
|
||||
require_once("plugins/".$opmPlugin."/include/OutgoingProxyLib.php");
|
||||
|
||||
/* Files generated by this script based on the data in proxy.cfg. */
|
||||
$proxy_sh = '/etc/profile.d/proxy.sh';
|
||||
$proxy_ini = '/usr/local/emhttp/state/proxy.ini';
|
||||
|
||||
/* Random file extension for atomic writes. */
|
||||
$rnd = rand();
|
||||
|
||||
/* Comments to beginning of the proxy_sh file. */
|
||||
$comments = "#!/bin/bash\n"."# Do not edit. This file is autogenerated by /usr/local/sbin/set_proxy.\n";
|
||||
|
||||
/* Set verbose if command line switch is set. */
|
||||
$verbose = false;
|
||||
if (isset($argv[1]) && ($argv[1] == '-v')) {
|
||||
$verbose = true;
|
||||
}
|
||||
|
||||
/* Initialize global variables. */
|
||||
$proxy_active = "";
|
||||
$proxy_url = "";
|
||||
$no_proxy = "";
|
||||
|
||||
/* Write comments and content to a file. */
|
||||
function write_file($file, $content, $show_comments = false) {
|
||||
global $rnd, $comments;
|
||||
|
||||
$tmpFile = "{$file}.{$rnd}";
|
||||
file_put_contents($tmpFile, ($show_comments ? $comments : "").$content);
|
||||
chmod($tmpFile, 0755);
|
||||
rename($tmpFile, $file);
|
||||
}
|
||||
|
||||
/* Write environment variables to /etc/profile.d/proxy.sh. */
|
||||
function set_proxy_sh() {
|
||||
global $proxy_sh, $proxy_url, $no_proxy;
|
||||
|
||||
$content = "export http_proxy=".$proxy_url."\n";
|
||||
$content .= "export https_proxy=".$proxy_url."\n";
|
||||
$content .= "export no_proxy=".$no_proxy."\n";
|
||||
|
||||
write_file($proxy_sh, $content, true);
|
||||
}
|
||||
|
||||
/* Clear environment variables from /etc/profile.d/proxy.sh. */
|
||||
function unset_proxy_sh() {
|
||||
global $proxy_sh;
|
||||
|
||||
$content = "unset http_proxy\n";
|
||||
$content .= "unset https_proxy\n";
|
||||
$content .= "unset no_proxy\n";
|
||||
|
||||
write_file($proxy_sh, $content, true);
|
||||
}
|
||||
|
||||
/* Write proxy information to /usr/local/emhttp/state/proxy.ini. */
|
||||
function set_proxy_ini() {
|
||||
global $proxy_ini, $proxy_url, $no_proxy;
|
||||
|
||||
$content = "http_proxy=".$proxy_url."\n";
|
||||
$content .= "https_proxy=".$proxy_url."\n";
|
||||
$content .= "no_proxy=".$no_proxy."\n";
|
||||
|
||||
write_file($proxy_ini, $content);
|
||||
}
|
||||
|
||||
/* Clear /usr/local/emhttp/state/proxy.ini. */
|
||||
function unset_proxy_ini() {
|
||||
/* Vars are empty now, call set_proxy_ini to add empty vars to proxy.ini. */
|
||||
set_proxy_ini();
|
||||
}
|
||||
|
||||
/* Generate proxy files. */
|
||||
function add_proxy_to_generated_files() {
|
||||
global $verbose;
|
||||
|
||||
echo("generating proxy files\n");
|
||||
set_proxy_sh();
|
||||
set_proxy_ini();
|
||||
if ($verbose) {
|
||||
display_generated_files();
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove proxy info from all generated files. */
|
||||
function remove_proxy_from_generated_files() {
|
||||
global $verbose;
|
||||
|
||||
echo("removing proxy info from generated files\n");
|
||||
unset_proxy_sh();
|
||||
unset_proxy_ini();
|
||||
if ($verbose) {
|
||||
display_generated_files();
|
||||
}
|
||||
}
|
||||
|
||||
/* When verbose mode is enabled. */
|
||||
function display_generated_files() {
|
||||
global $proxy_sh, $proxy_ini;
|
||||
|
||||
echo("\n");
|
||||
display_generated_file($proxy_sh);
|
||||
echo("\n");
|
||||
display_generated_file($proxy_ini);
|
||||
}
|
||||
|
||||
/* When verbose mode is enabled. */
|
||||
function display_generated_file($file) {
|
||||
echo("file: ".$file."\n");
|
||||
if (file_exists($file)) {
|
||||
echo(file_get_contents($file));
|
||||
} else {
|
||||
echo("file does not exist\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Read current proxy information from Outgoing Proxy Manager config file. */
|
||||
$config = parse_plugin_config();
|
||||
|
||||
/* Get the current active proxy. */
|
||||
$proxy_active = $config['proxy_active'] ?? "0";
|
||||
$proxy_url = "";
|
||||
|
||||
/* Only build full url for an active proxy. */
|
||||
if ($proxy_active != "0") {
|
||||
/* Get the active proxy url, user, and pass. */
|
||||
$proxy_url = "proxy_url_".$proxy_active;
|
||||
$proxy_user = "proxy_user_".$proxy_active;
|
||||
$proxy_pass = "proxy_pass_".$proxy_active;
|
||||
|
||||
/* Get the full url for the active proxy. */
|
||||
$url_array = get_proxy_info($config[$proxy_url] ?? "", $config[$proxy_user] ?? "", $config[$proxy_pass] ?? "");
|
||||
$proxy_url = $proxy_active ? $url_array['full_url'] : "";
|
||||
|
||||
/* If the active proxy url is defined, create the generated files. */
|
||||
if ($proxy_url) {
|
||||
/* Proxies are defined, write generated files. */
|
||||
$no_proxy = "127.0.0.1,localhost";
|
||||
add_proxy_to_generated_files();
|
||||
}
|
||||
} else {
|
||||
/* If no active proxies, remove proxy info from all generated files. */
|
||||
remove_proxy_from_generated_files();
|
||||
}
|
||||
?>
|
||||
2
sbin/virtiofsd
Executable file
2
sbin/virtiofsd
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
eval exec /usr/bin/virtiofsd $(/usr/local/emhttp/plugins/dynamix.vm.manager/scripts/virtiofsd.php "$@")
|
||||
Reference in New Issue
Block a user