Compare commits
163 Commits
tailscale-
...
6.12.10
Author | SHA1 | Date | |
---|---|---|---|
|
4190c6c822 | ||
|
2901a1949f | ||
|
dfde9b68c0 | ||
|
98b52dc95f | ||
|
730b8ef91c | ||
|
e2d7b6f15c | ||
|
29e02bfc07 | ||
|
50567f450c | ||
|
cd52d6a7df | ||
|
29e2084181 | ||
|
cde846757b | ||
|
69641222bf | ||
|
16e058c62d | ||
|
109eb31b17 | ||
|
0b850b058b | ||
|
bc5c8a8bc5 | ||
|
3a53d311d2 | ||
|
900afa2105 | ||
|
fcdf88f997 | ||
|
83cad5852c | ||
|
cbfb8a3a90 | ||
|
24535c7272 | ||
|
3226f4a1c7 | ||
|
ee3d28a978 | ||
|
262aea7312 | ||
|
ed19f86e7d | ||
|
d238203acc | ||
|
2ff0d408a8 | ||
|
8ad4d879f3 | ||
|
dcfc6f9a1d | ||
|
e549b4a928 | ||
|
18044d98cc | ||
|
5eaaf2c220 | ||
|
c1b5a6ef7b | ||
|
4ffc04cd72 | ||
|
9ad869e134 | ||
|
e02713eeac | ||
60ab17d7ea | |||
|
f80813a73d | ||
|
235011d547 | ||
|
9789659f83 | ||
|
50c47005ba | ||
|
d0c40d5269 | ||
|
aad6cf6408 | ||
|
ae19e2aa16 | ||
|
96059fc4b5 | ||
|
a3be910f24 | ||
|
ad002faf36 | ||
|
f5257dd134 | ||
|
a479a1bd86 | ||
|
1c07f6fdc7 | ||
|
335d9eb225 | ||
|
4d50eaa3ab | ||
|
8e3913146b | ||
|
5bc9be6036 | ||
|
3af48b4393 | ||
|
98127c95f8 | ||
|
aa012f00f6 | ||
|
a5db8d917a | ||
|
2bd92658ab | ||
|
ce56b9008c | ||
|
bb5333abff | ||
|
a6c905eb7f | ||
|
2ff7230fc7 | ||
|
8de82407a1 | ||
|
8cac67a30f | ||
|
0893716d8c | ||
|
f0db9eb5ce | ||
|
7feea3a072 | ||
|
c1556a886d | ||
|
12a3815df0 | ||
|
56fd6fe75c | ||
|
a3fd550193 | ||
|
89483d2dc8 | ||
|
f763e4f6c1 | ||
|
88c139a915 | ||
|
c24a56921f | ||
|
c7966232f1 | ||
|
b9014de4db | ||
|
0e8d926d83 | ||
|
02470f48fb | ||
|
367960aaba | ||
|
fb4a7f00bf | ||
|
604c0704e8 | ||
|
c3b6179374 | ||
|
49c0b4af72 | ||
|
4486034800 | ||
|
8795728382 | ||
|
3bcd598df9 | ||
|
b0ddc34959 | ||
|
7d9b68cf0e | ||
|
0ebcfeb931 | ||
|
a21664c440 | ||
|
5a6a7ee90b | ||
|
16b306e0c5 | ||
|
d3fb1a2769 | ||
|
01c04682e8 | ||
|
a4276e665a | ||
|
3ebfba70dc | ||
|
0a7ed0447f | ||
|
041bc5fa9c | ||
|
7dd94e241d | ||
|
9a158ffb60 | ||
|
a2d320bc87 | ||
|
109f9e6799 | ||
5acf5c6f14 | |||
87392ab547 | |||
|
19b8f34641 | ||
|
452f1731df | ||
|
ded26b78c4 | ||
|
8c2efe3576 | ||
|
f9808dbc56 | ||
|
796524406e | ||
|
42884e9bc5 | ||
|
aada9841d6 | ||
|
a53f9afe0c | ||
|
f8866cecb6 | ||
|
f30c282f01 | ||
|
82711e42bb | ||
|
62cee260ca | ||
|
c33d807fa8 | ||
|
66ca926448 | ||
|
c5f4718c08 | ||
|
212c49e7c1 | ||
|
2d53681c99 | ||
|
fcb37cd2f6 | ||
|
2816295782 | ||
|
d51c6318d9 | ||
|
4db16ab50d | ||
|
dc04d84aa4 | ||
|
f023ba3cbd | ||
|
abf0d2390d | ||
|
93f9f2c691 | ||
|
f3c88f0fd2 | ||
|
96671aa9be | ||
|
abdd7c12cb | ||
|
24c8f7422f | ||
|
e75e481a9a | ||
|
edff3386b3 | ||
|
9fd6465be0 | ||
|
9210d0f6ab | ||
|
c53f078cbb | ||
|
3324d4bd1f | ||
|
264471d032 | ||
|
588c6ec80c | ||
|
d80995e682 | ||
|
1a67a68965 | ||
|
cd90daf483 | ||
|
52b8a0c9f4 | ||
|
1f9ee76883 | ||
|
e88e5e4193 | ||
|
df808e9b07 | ||
|
e69a94e7cf | ||
|
a0349267ff | ||
|
9596b91e09 | ||
|
e62d0e12be | ||
|
c42cff5320 | ||
|
4765dcb576 | ||
|
61eb1ef765 | ||
|
ee585aab54 | ||
|
54c2dfbdb0 | ||
|
2d6c7ab5ed | ||
|
8a74adb5f2 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -63,3 +63,9 @@ share/
|
||||
|
||||
# Auto-generated when emhttpd/webGUI start
|
||||
emhttp/languages/en_US/helptext.dot
|
||||
|
||||
# Auto-generated when web copmonents are built
|
||||
emhttp/plugins/dynamix.my.servers/unraid-components/index.html
|
||||
|
||||
# development scripts
|
||||
.dev-scripts/
|
||||
|
@@ -1189,7 +1189,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.
|
||||
|
||||
@@ -1253,10 +1253,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:
|
||||
|
||||
@@ -1270,24 +1270,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**
|
||||
|
||||
@@ -1295,7 +1291,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.
|
||||
@@ -1513,6 +1509,15 @@ Change this setting to YES when troubleshooting is required and it is not possib
|
||||
A mirror of the syslog file is stored in the **logs** folder of the flash device.
|
||||
:end
|
||||
|
||||
:syslog_shutdown_flash_help:
|
||||
This setting is YES by default and enables the system to copy the
|
||||
syslog file to the USB device on shutdown or reboot.
|
||||
|
||||
After rebooting, the syslog from this run will be visible on Tools >
|
||||
Syslog > syslog-previous;
|
||||
it will also be included in diagnostics as logs/syslog-previous.txt
|
||||
:end
|
||||
|
||||
:confirm_reboot_help:
|
||||
Choose if rebooting or powering down the server needs a confirmation checkbox.
|
||||
:end
|
||||
|
@@ -27,6 +27,9 @@ if ($_SERVER['REQUEST_URI'] == '/logout') {
|
||||
$error = _('Successfully logged out');
|
||||
}
|
||||
|
||||
// If issue with license key redirect to Tools/Registration, otherwise go to start page
|
||||
$start_page = (!empty(_var($var,'regCheck'))) ? 'Tools/Registration' : _var($var,'START_PAGE','Main');
|
||||
|
||||
$result = exec( "/usr/bin/passwd --status root");
|
||||
if (($result === false) || (substr($result, 0, 6) !== "root P"))
|
||||
include "$docroot/webGui/include/.set-password.php";
|
||||
|
@@ -87,7 +87,7 @@ if (file_exists("/var/run/apcupsd.pid")) {
|
||||
if (count($rows)%2==1) $result[] = "<td></td><td></td></tr>";
|
||||
if ($power && isset($load)) $status[5] = ($load<90 ? "<td $green>" : "<td $red>").round($power*$load/100)." W (".$status[5].")</td>";
|
||||
elseif (isset($load)) $status[5] = ($load<90 ? "<td $green>" : "<td $red>").$status[5]."</td>";
|
||||
$status[6] = isset($output) ? ((!$volt || ($minv<$output && $output<$maxv) ? "<td $green>" : "<td $red>").$status[6].($freq ? " ~ $freq Hz" : "")."</td>") : $status[6];
|
||||
$status[6] = isset($output) ? ((!$volt || ($minv<$output && $output<$maxv) ? "<td $green>" : "<td $red>").$status[6].(isset($freq) ? " ~ $freq Hz" : "")."</td>") : $status[6];
|
||||
}
|
||||
if (empty($rows)) $result[] = "<tr><td colspan='4' style='text-align:center'>"._('No information available')."</td></tr>";
|
||||
|
||||
|
@@ -124,6 +124,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/);
|
||||
|
@@ -257,16 +257,14 @@ _(Template Authoring Mode)_:
|
||||
|
||||
:docker_authoring_mode_help:
|
||||
|
||||
<?if ($bridge):?>
|
||||
_(Docker custom network type)_:
|
||||
: <select name="DOCKER_NETWORK_TYPE">
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '1', _('ipvlan'))?>
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '', _('macvlan'))?>
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '1', _('ipvlan'), $bridge?'':'disabled')?>
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '', _('macvlan'), $bridge?'':'selected')?>
|
||||
</select> _(Please read the Help carefully)_. _(Misconfiguration can cause problems)_.
|
||||
|
||||
:docker_custom_network_type_help:
|
||||
|
||||
<?endif;?>
|
||||
_(Host access to custom networks)_:
|
||||
: <select name="DOCKER_ALLOW_ACCESS">
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_ALLOW_ACCESS'), '', _('Disabled'))?>
|
||||
@@ -465,13 +463,11 @@ _(Docker LOG rotation)_:
|
||||
|
||||
:docker_log_rotation_active_help:
|
||||
|
||||
<?if ($bridge):?>
|
||||
_(Docker custom network type)_:
|
||||
: <?=_var($dockercfg,'DOCKER_NETWORK_TYPE')=='1' ? _('ipvlan') : _('macvlan')?>
|
||||
: <?=_var($dockercfg,'DOCKER_NETWORK_TYPE')!='1' || !$bridge ? _('macvlan') : _('ipvlan')?>
|
||||
|
||||
:docker_custom_network_type_help:
|
||||
|
||||
<?endif;?>
|
||||
_(Host access to custom networks)_:
|
||||
: <?=_var($dockercfg,'DOCKER_ALLOW_ACCESS')=='yes' ? _('Enabled') : _('Disabled')?>
|
||||
|
||||
|
@@ -51,9 +51,12 @@ $port = file_exists('/sys/class/net/br0') ? 'BR0' : (file_exists('/sys/class/net
|
||||
|
||||
// Docker configuration file - guaranteed to exist
|
||||
$docker_cfgfile = '/boot/config/docker.cfg';
|
||||
if (file_exists($docker_cfgfile) && exec("grep -Pom1 '_{$port}(_[0-9]+)?=' $docker_cfgfile")=='') {
|
||||
# interface has changed, update configuration
|
||||
exec("sed -ri 's/_(BR0|BOND0|ETH0)(_[0-9]+)?=/_{$port}\\2=/' $docker_cfgfile");
|
||||
if (file_exists($docker_cfgfile)) {
|
||||
exec("grep -Pom2 '_SUBNET_|_{$port}(_[0-9]+)?=' $docker_cfgfile",$cfg);
|
||||
if (isset($cfg[0]) && $cfg[0]=='_SUBNET_' && empty($cfg[1])) {
|
||||
# interface has changed, update configuration
|
||||
exec("sed -ri 's/_(BR0|BOND0|ETH0)(_[0-9]+)?=/_{$port}\\2=/' $docker_cfgfile");
|
||||
}
|
||||
}
|
||||
|
||||
$defaults = @parse_ini_file("$docroot/plugins/dynamix.docker.manager/default.cfg") ?: [];
|
||||
@@ -722,7 +725,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";
|
||||
@@ -979,7 +982,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'] = vsprintf('%1$s/%2$s', preg_split("#[:\/]#", DockerUtil::ensureImageTag($ct['RepoTags'][0]??'')));
|
||||
$c['usedBy'] = $this->usedBy($c['Id']);
|
||||
|
@@ -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,8 +1,8 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -17,6 +17,7 @@ $docroot = $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
|
||||
@@ -44,7 +45,7 @@ if (!isset($check)) {
|
||||
$DockerTemplates->getAllInfo(true);
|
||||
echo " Done.";
|
||||
} else {
|
||||
$notify = "$docroot/webGui/scripts/notify";
|
||||
$script = "$docroot/webGui/scripts/notify";
|
||||
$var = @parse_ini_file("/var/local/emhttp/var.ini") ?: [];
|
||||
$server = strtoupper(_var($var,'NAME','tower'));
|
||||
$output = _var($notify,'docker_notify');
|
||||
@@ -60,7 +61,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -179,11 +179,16 @@ foreach (explode('*',rawurldecode($argv[1])) as $value) {
|
||||
$startContainer = false;
|
||||
if (!empty($oldContainerInfo) && !empty($oldContainerInfo['State']) && !empty($oldContainerInfo['State']['Running'])) {
|
||||
// since container was already running, put it back it to a running state after update
|
||||
$cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
|
||||
$startContainer = true;
|
||||
// attempt graceful stop of container first
|
||||
stopContainer_nchan($Name);
|
||||
}
|
||||
if ( ($argv[2]??null) == "ca_docker_run_override" )
|
||||
$startContainer = true;
|
||||
|
||||
if ( $startContainer )
|
||||
$cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
|
||||
|
||||
// force kill container if still running after 10 seconds
|
||||
if (empty($_GET['communityApplications'])) removeContainer_nchan($Name);
|
||||
execCommand_nchan($cmd);
|
||||
|
@@ -1,62 +1,14 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
|
||||
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
|
||||
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
|
||||
}
|
||||
.ui-dropdownchecklist .ui-state-default{
|
||||
background:#f2f2f2;
|
||||
border:none;
|
||||
box-shadow:none;
|
||||
outline:none;
|
||||
cursor:pointer;
|
||||
height:2.2rem;
|
||||
line-height:2.2rem;
|
||||
}
|
||||
.ui-dropdownchecklist-group{
|
||||
font-weight:normal;
|
||||
font-style:italic;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector{
|
||||
border:1px solid #1c1c1c;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector-wrapper{
|
||||
vertical-align:middle;
|
||||
font-size:0;
|
||||
}
|
||||
.ui-widget-header{
|
||||
border:none;
|
||||
background:#e3e3e3;
|
||||
color:#1c1c1c;
|
||||
font-weight:bold;
|
||||
}
|
||||
.ui-widget-content{
|
||||
border:1px solid #1c1c1c;
|
||||
background:#f2f2f2;
|
||||
color:#1c1c1c;
|
||||
|
||||
.ui-state-active{
|
||||
background:#e8e8e8;
|
||||
}
|
||||
.ui-dropdownchecklist-dropcontainer{
|
||||
background:#f2f2f2;
|
||||
border:1px solid #1c1c1c;
|
||||
}
|
||||
.ui-state-disabled{
|
||||
color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5;
|
||||
}
|
||||
.ui-dropdownchecklist-indent{
|
||||
padding-left:7px;
|
||||
}
|
||||
.ui-dropdownchecklist-text{
|
||||
color:#1c1c1c;
|
||||
font-size:1.3rem;
|
||||
}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
|
||||
background:#f2f2f2;
|
||||
border:0px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#f2f2f2;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#e3e3e3;color:#1c1c1c;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #1c1c1c;background:#f2f2f2;color:#1c1c1c}
|
||||
.ui-state-active{background:#e8e8e8}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#f2f2f2;border:1px solid #1c1c1c}
|
||||
.ui-state-disabled{color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#1c1c1c;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#f2f2f2;border:0px}
|
||||
|
@@ -1,62 +1,14 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
|
||||
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
|
||||
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
|
||||
}
|
||||
.ui-dropdownchecklist .ui-state-default{
|
||||
background:#1c1c1c;
|
||||
border:none;
|
||||
box-shadow:none;
|
||||
outline:none;
|
||||
cursor:pointer;
|
||||
height:2.2rem;
|
||||
line-height:2.2rem;
|
||||
}
|
||||
.ui-dropdownchecklist-group{
|
||||
font-weight:normal;
|
||||
font-style:italic;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector{
|
||||
border:1px solid #e5e5e5;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector-wrapper{
|
||||
vertical-align:middle;
|
||||
font-size:0;
|
||||
}
|
||||
.ui-widget-header{
|
||||
border:none;
|
||||
background:#2b2b2b;
|
||||
color:#f2f2f2;
|
||||
font-weight:bold;
|
||||
}
|
||||
.ui-widget-content{
|
||||
border:1px solid #e5e5e5;
|
||||
background:#1c1c1c;
|
||||
color:#f2f2f2;
|
||||
|
||||
.ui-state-active{
|
||||
background:#262626;
|
||||
}
|
||||
.ui-dropdownchecklist-dropcontainer{
|
||||
background:#1c1c1c;
|
||||
border:1px solid #e5e5e5;
|
||||
}
|
||||
.ui-state-disabled{
|
||||
color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5;
|
||||
}
|
||||
.ui-dropdownchecklist-indent{
|
||||
padding-left:7px;
|
||||
}
|
||||
.ui-dropdownchecklist-text{
|
||||
color:#f2f2f2;
|
||||
font-size:1.3rem;
|
||||
}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
|
||||
background:#1c1c1c;
|
||||
border:0px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#1c1c1c;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #e5e5e5;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#2b2b2b;color:#f2f2f2;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #e5e5e5;background:#1c1c1c;color:#f2f2f2}
|
||||
.ui-state-active{background:#262626}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#1c1c1c;border:1px solid #e5e5e5}
|
||||
.ui-state-disabled{color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#f2f2f2;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#1c1c1c;border:0px}
|
||||
|
@@ -1,62 +1,14 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
|
||||
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
|
||||
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
|
||||
}
|
||||
.ui-dropdownchecklist .ui-state-default{
|
||||
background:#1c1c1c;
|
||||
border:none;
|
||||
box-shadow:none;
|
||||
outline:none;
|
||||
cursor:pointer;
|
||||
height:2.2rem;
|
||||
line-height:2.2rem;
|
||||
}
|
||||
.ui-dropdownchecklist-group{
|
||||
font-weight:normal;
|
||||
font-style:italic;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector{
|
||||
border:1px solid #e5e5e5;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector-wrapper{
|
||||
vertical-align:middle;
|
||||
font-size:0;
|
||||
}
|
||||
.ui-widget-header{
|
||||
border:none;
|
||||
background:#2b2b2b;
|
||||
color:#f2f2f2;
|
||||
font-weight:bold;
|
||||
}
|
||||
.ui-widget-content{
|
||||
border:1px solid #e5e5e5;
|
||||
background:#1c1c1c;
|
||||
color:#f2f2f2;
|
||||
|
||||
.ui-state-active{
|
||||
background:#262626;
|
||||
}
|
||||
.ui-dropdownchecklist-dropcontainer{
|
||||
background:#1c1c1c;
|
||||
border:1px solid #e5e5e5;
|
||||
}
|
||||
.ui-state-disabled{
|
||||
color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5;
|
||||
}
|
||||
.ui-dropdownchecklist-indent{
|
||||
padding-left:7px;
|
||||
}
|
||||
.ui-dropdownchecklist-text{
|
||||
color:#f2f2f2;
|
||||
font-size:1.3rem;
|
||||
}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
|
||||
background:#1c1c1c;
|
||||
border:0px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#1c1c1c;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #e5e5e5;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#2b2b2b;color:#f2f2f2;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #e5e5e5;background:#1c1c1c;color:#f2f2f2}
|
||||
.ui-state-active{background:#262626}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#1c1c1c;border:1px solid #e5e5e5}
|
||||
.ui-state-disabled{color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#f2f2f2;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#1c1c1c;border:0px}
|
||||
|
@@ -1,62 +1,14 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
|
||||
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
|
||||
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
|
||||
}
|
||||
.ui-dropdownchecklist .ui-state-default{
|
||||
background:#f2f2f2;
|
||||
border:none;
|
||||
box-shadow:none;
|
||||
outline:none;
|
||||
cursor:pointer;
|
||||
height:2.2rem;
|
||||
line-height:2.2rem;
|
||||
}
|
||||
.ui-dropdownchecklist-group{
|
||||
font-weight:normal;
|
||||
font-style:italic;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector{
|
||||
border:1px solid #1c1c1c;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector-wrapper{
|
||||
vertical-align:middle;
|
||||
font-size:0;
|
||||
}
|
||||
.ui-widget-header{
|
||||
border:none;
|
||||
background:#e3e3e3;
|
||||
color:#1c1c1c;
|
||||
font-weight:bold;
|
||||
}
|
||||
.ui-widget-content{
|
||||
border:1px solid #1c1c1c;
|
||||
background:#f2f2f2;
|
||||
color:#1c1c1c;
|
||||
|
||||
.ui-state-active{
|
||||
background:#e8e8e8;
|
||||
}
|
||||
.ui-dropdownchecklist-dropcontainer{
|
||||
background:#f2f2f2;
|
||||
border:1px solid #1c1c1c;
|
||||
}
|
||||
.ui-state-disabled{
|
||||
color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5;
|
||||
}
|
||||
.ui-dropdownchecklist-indent{
|
||||
padding-left:7px;
|
||||
}
|
||||
.ui-dropdownchecklist-text{
|
||||
color:#1c1c1c;
|
||||
font-size:1.3rem;
|
||||
}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
|
||||
background:#f2f2f2;
|
||||
border:0px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#f2f2f2;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#e3e3e3;color:#1c1c1c;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #1c1c1c;background:#f2f2f2;color:#1c1c1c}
|
||||
.ui-state-active{background:#e8e8e8}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#f2f2f2;border:1px solid #1c1c1c}
|
||||
.ui-state-disabled{color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#1c1c1c;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#f2f2f2;border:0px}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
Menu="About"
|
||||
Menu="About:30"
|
||||
Type="xmenu"
|
||||
Title="Registration"
|
||||
Icon="icon-registration"
|
||||
Tag="pencil"
|
||||
---
|
||||
<?PHP
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -15,239 +15,6 @@ Tag="pencil"
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
function my_time_any($time) {
|
||||
return $time ? _(my_time($time),0) : _('Anytime');
|
||||
}
|
||||
function my_time_now($time) {
|
||||
return $time ? _(my_time($time),0) : _('Unknown');
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
span.thanks{padding-left:12px;color:#6FA239;font-weight:bold;}
|
||||
span.thanks.red{color:#F0000C;}
|
||||
div.device{padding:0 12px;font-weight:normal;font-style:italic;}
|
||||
div.remark{padding:0 12px;text-align:justify;}
|
||||
</style>
|
||||
|
||||
<?if ( (strstr($var['regTy'], "unregistered")) or ($var['regTy']=="Trial") or (strstr($var['regTy'], "no connection")) or (strstr($var['regTy'], "withdrawn")) or (strstr($var['regTy'], "expired")) ):?>
|
||||
|
||||
<span class="thanks">_(Thank you for trying Unraid OS)_!</span>
|
||||
|
||||
<?elseif ( ($var['regTy']=="Basic") or ($var['regTy']=="Plus") or ($var['regTy']=="Pro") ):?>
|
||||
|
||||
<span class="thanks">_(Thank you for choosing Unraid OS)_!</span>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "unregistered")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
:registration_1_plug:
|
||||
Your server will not be usable until you purchase a Registration key or install a free 30-day *Trial* key. A *Trial*
|
||||
key provides all the functionality of a *Pro* Registration key.
|
||||
|
||||
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 (min 4GB recommended).
|
||||
|
||||
Note: USB memory card readers are generally **not** supported because most do not present unique serial numbers.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ($var['regTy']=="Trial"):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
:registration_3_plug:
|
||||
Your *Trial* key includes all the functionality and device support of a *Pro* Registration key.
|
||||
|
||||
After your *Trial* key has reached expiration, your server **still functions normally** until the next time you **Stop** the array.
|
||||
|
||||
At that point, you may either purchase a Registration key, or request a *Trial* extension.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "no connection")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
<span class='red-text'>_(Cannot connect to key-server)_!</span>
|
||||
|
||||
_(Your *Trial* key requires an internet connection)_. _(Please check your)_ [_(Network Settings)_](NetworkSettings).
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "withdrawn")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
<span class='red-text'>_(Release has been withdrawn)_!</span>
|
||||
|
||||
_(This release has been withdrawn for use with *Trial* keys)_.
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "expired")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
<span class='red-text'>_(Your *Trial* key has expired)_.</span>
|
||||
:registration_4_plug:
|
||||
To continue using Unraid OS you may purchase a Registration key. Alternately, you may request a *Trial* extension key.
|
||||
|
||||
Most *Trial* extension requests are processed immediately but please allow up to one business day to receive your *Trial* extension key.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "invalid installation")):?>
|
||||
|
||||
<span class='thanks red'>_(Invalid *Trial* Installation)_</span>
|
||||
<div markdown="1" class="remark">
|
||||
:registration_5_plug:
|
||||
It is not possible to use a *Trial* key with an existing Unraid OS installation.
|
||||
|
||||
You may purchase a Registration key corresponding to this USB Flash device to continue using this installation.
|
||||
|
||||
For more information, please [Contact Support](https://lime-technology.com/contact).
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "missing")):?>
|
||||
|
||||
<span class='thanks red'>_(Missing Key File)_</span>
|
||||
<div markdown="1" class="remark">
|
||||
:registration_6_plug:
|
||||
It appears that your Registration key file is corrupted or missing. The key file should be located in the
|
||||
[config](/Registration/Browse?dir=/boot/config) directory on your USB Flash boot device.
|
||||
|
||||
If you do not have a backup copy of your Registration key file, [Contact Support](https://lime-technology.com/contact).
|
||||
|
||||
If this was a *Trial* installation, you may purchase a Registration key.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "invalid key")):?>
|
||||
|
||||
<span class='thanks red'>_(The registered GUID does not match the USB Flash boot device GUID)_</span>
|
||||
|
||||
<?if (strstr($var['regTy'], "Trial")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
:registration_7_plug:
|
||||
*Trial* installations are only valid with the originally registered USB Flash device.
|
||||
|
||||
To continue using this installation with this USB Flash device, you may purchase a Registration key.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?else:?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
:registration_8_plug:
|
||||
The Registration key file does not correspond to the USB Flash boot device.
|
||||
Please copy the correct key file to the [config](/Registration/Browse?dir=/boot/config) directory
|
||||
on your USB Flash boot device. If you do not have a backup copy of your key file, [Contact Support](https://lime-technology.com/contact).
|
||||
|
||||
If you want to replace your Registration key with a new key bound to this USB Flash device, click Replace Key below. An original key may be
|
||||
replaced anytime. Thereafter, a replacement key may be replaced again after one year has passed. If you require
|
||||
another replacement key sooner, [Contact Support](https://lime-technology.com/contact).
|
||||
|
||||
**Note:** Replacing a Registration key results in permanently *blacklisting* the previous USB Flash GUID.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "blacklisted")):?>
|
||||
|
||||
<span class='thanks red'>_(Blacklisted USB Flash GUID)_</span>
|
||||
<div markdown="1" class="remark">
|
||||
:registration_9_plug:
|
||||
This USB Flash boot device has been *blacklisted*. This can occur as a result of transfering your Registration key to
|
||||
a replacement USB Flash device, and you are currently booted from your old USB Flash device.
|
||||
|
||||
A USB Flash device may also be *blacklisted* if there is no serial number, or if we discover the serial number
|
||||
is not unique (this is common with USB card readers).
|
||||
|
||||
For more information, please [Contact Support](https://lime-technology.com/contact).
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( ( !(strstr($var['regTy'], "invalid key")) and ((strstr($var['regTy'], "Trial"))) ) || (strstr($var['regTy'], "no connection")) || (strstr($var['regTy'], "withdrawn")) ):?>
|
||||
|
||||
_(***Trial*** key expires on)_:
|
||||
: <?=my_time_now($var['regTm2'])?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( strstr($var['regTy'], "invalid installation") || ( (strstr($var['regTy'], "invalid key")) && (strstr($var['regTy'], "Trial")) )):?>
|
||||
|
||||
_(Expiration)_:
|
||||
: <?=my_time_now($var['regTm2'])?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( (strstr($var['regTy'], "invalid installation")) || (strstr($var['regTy'], "invalid key")) || ($var['regTy']=="Basic") || ($var['regTy']=="Plus") || ($var['regTy']=="Pro") ):?>
|
||||
|
||||
_(Registered to)_:
|
||||
: <?=htmlspecialchars($var['regTo'])?>
|
||||
|
||||
_(Registered on)_:
|
||||
: <?=my_time_now($var['regTm'])?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( (strstr($var['regTy'], "invalid installation")) or ( (strstr($var['regTy'], "invalid key")) and (!(strstr($var['regTy'], "Trial")))) ):?>
|
||||
|
||||
_(Registered GUID)_:
|
||||
: <?=$var['regGUID']?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "flash device error")):?>
|
||||
|
||||
<span class='thanks red'>_(Error accessing your physical USB Flash boot device)_</span>
|
||||
<div markdown="1" class="remark">
|
||||
_(There is a physical problem accessing your USB Flash boot device)_. _(Please)_ [Contact Support](https://lime-technology.com/contact).
|
||||
|
||||
_(Flash GUID)_:
|
||||
: _(Error code)_: <?=$var['regCheck']?>
|
||||
|
||||
<?else:?>
|
||||
|
||||
_(Flash GUID)_:
|
||||
: <?=$var['flashGUID']?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
_(Flash Vendor)_:
|
||||
: <?=$var['flashVendor']?>
|
||||
|
||||
_(Flash Product)_:
|
||||
: <?=$var['flashProduct']?>
|
||||
|
||||
<?if ( ((strstr($var['regTy'], "invalid key")) and !(strstr($var['regTy'], "Trial"))) || ($var['regTy']=="Basic") || ($var['regTy']=="Plus") || ($var['regTy']=="Pro") ):?>
|
||||
|
||||
_(Replaceable)_:
|
||||
: <?=my_time_any($var['regTm2'])?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( !(strstr($var['regTy'], "flash device error")) || !(strstr($var['regTy'], "blacklisted")) ):?>
|
||||
|
||||
<div class="device"><?=sprintf(_("This server has %s attached storage device".($var['deviceCount']==1?'.':'s.')),$var['deviceCount'])?></div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<unraid-upc-trigger></unraid-upc-trigger>
|
||||
<unraid-i18n-host>
|
||||
<unraid-registration></unraid-registration>
|
||||
</unraid-i18n-host>
|
||||
|
23
emhttp/plugins/dynamix.my.servers/data/server-state.php
Normal file
23
emhttp/plugins/dynamix.my.servers/data/server-state.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
$var = (array)parse_ini_file('state/var.ini');
|
||||
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/state.php";
|
||||
|
||||
$serverState = new ServerState();
|
||||
|
||||
header('Content-type: application/json');
|
||||
|
||||
echo $serverState->getServerStateJson();
|
@@ -1,129 +1,62 @@
|
||||
<!-- myservers1 -->
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<style>
|
||||
#header {
|
||||
z-index: 102 !important;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
z-index: 102 !important;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
vue-userprofile,
|
||||
unraid-user-profile {
|
||||
font-size: 16px;
|
||||
margin-left: auto;
|
||||
height: 100%;
|
||||
#header unraid-i18n-host {
|
||||
font-size: 16px;
|
||||
margin-left: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
unraid-launchpad,
|
||||
unraid-promo {
|
||||
position: relative;
|
||||
z-index: 10001;
|
||||
/**
|
||||
* Tools page, rotate the Downgrade icon to prevent needing to add a new icon to the icon font.
|
||||
* The pseudo element is targeted here otherwise the rotation of the span would mess up spacing with the text.
|
||||
*/
|
||||
a[href="/Tools/Downgrade"] .icon-update:before {
|
||||
display: inline-block; /* required otherwise the rotation won't work */
|
||||
rotate: 180deg;
|
||||
}
|
||||
</style>
|
||||
<?
|
||||
$myservers_flash_cfg_path='/boot/config/plugins/dynamix.my.servers/myservers.cfg';
|
||||
$myservers = file_exists($myservers_flash_cfg_path) ? @parse_ini_file($myservers_flash_cfg_path,true) : [];
|
||||
<?php
|
||||
// Set the path for the local manifest file
|
||||
$localManifestFile = '/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components/manifest.json';
|
||||
|
||||
$ALLOWED_UPC_ENV_VALS = [
|
||||
'production',
|
||||
'staging',
|
||||
'stagingLogs',
|
||||
'development',
|
||||
'local',
|
||||
'preview',
|
||||
];
|
||||
$ALLOWED_UPC_ENV_PREVIEW_CNAME = '.d1eohvtyc6gnee.amplifyapp.com/';
|
||||
// Load the local manifest
|
||||
$localManifest = json_decode(file_get_contents($localManifestFile), true);
|
||||
|
||||
// defaults
|
||||
$computedCookieValue = $_COOKIE['UPC_ENV'] ?? '';
|
||||
$previewUrl = '';
|
||||
$isPreview = strpos($computedCookieValue, 'preview::');
|
||||
// extract preview src url
|
||||
if ($isPreview !== false) {
|
||||
list($computedCookieValue, $previewUrl) = explode('::', $computedCookieValue);
|
||||
// prevent unauthoraized URLs for previews
|
||||
$isPreviewAllowed = strpos($previewUrl, $ALLOWED_UPC_ENV_PREVIEW_CNAME);
|
||||
if (!$isPreviewAllowed) {
|
||||
$computedCookieValue = '';
|
||||
$previewUrl = '';
|
||||
}
|
||||
$searchText = 'unraid-components.client.mjs';
|
||||
$fileValue = null;
|
||||
|
||||
foreach ($localManifest as $key => $value) {
|
||||
if (strpos($key, $searchText) !== false && isset($value["file"])) {
|
||||
$fileValue = $value["file"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// finalize cookie value
|
||||
$UPC_ENV_CK = in_array($computedCookieValue, $ALLOWED_UPC_ENV_VALS)
|
||||
? $computedCookieValue
|
||||
: null;
|
||||
// Determine what source we should use for web components
|
||||
if (!file_exists('/usr/local/sbin/unraid-api')) { // When NOT using the plugin we should load the UPC from the file system unless $UPC_ENV_CK exists.
|
||||
$UPC_ENV = $UPC_ENV_CK ?? 'local';
|
||||
|
||||
if ($fileValue !== null) {
|
||||
$prefixedPath = '/plugins/dynamix.my.servers/unraid-components/';
|
||||
echo '<script src="' . $prefixedPath . $fileValue . '"></script>';
|
||||
} else {
|
||||
$UPC_ENV = $UPC_ENV_CK ?? 'production';
|
||||
echo '<script>console.error("%cNo matching key containing \'' . $searchText . '\' found.", "font-weight: bold; color: white; background-color: red");</script>';
|
||||
}
|
||||
$upcLocalSrc = autov('/plugins/dynamix.my.servers/webComps/unraid.min.js', true);
|
||||
switch ($UPC_ENV) {
|
||||
case 'production':
|
||||
$upcSrc = 'https://registration.unraid.net/webComps/unraid.min.js';
|
||||
break;
|
||||
case 'staging':
|
||||
$upcSrc = 'https://registration-dev.unraid.net/webComps/unraid.min.js';
|
||||
break;
|
||||
case 'stagingLogs':
|
||||
$upcSrc = 'https://registration-dev-logs.unraid.net/webComps/unraid.min.js';
|
||||
break;
|
||||
case 'development':
|
||||
$upcSrc = 'https://launchpad.unraid.test:6969/webComps/unraid.js?t=' . time();
|
||||
break;
|
||||
case 'preview':
|
||||
$upcSrc = $previewUrl . 'webComps/unraid.min.js';
|
||||
break;
|
||||
default: // load from webGUI filesystem.
|
||||
$upcSrc = $upcLocalSrc;
|
||||
break;
|
||||
}
|
||||
// add the intended web component source to the DOM
|
||||
echo '<script id="unraid-wc" defer src="' . $upcSrc . '"></script>';
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
const upcEnvCookie = "<?=$UPC_ENV_CK??''?>";
|
||||
if (upcEnvCookie) console.debug('[UPC_ENV] ✨', upcEnvCookie);
|
||||
|
||||
// If the UPC isn't defined after 3secs inject UPC via
|
||||
setTimeout(() => {
|
||||
// UPC exists do nothing
|
||||
if (window.customElements.get('unraid-user-profile')) return;
|
||||
|
||||
console.log('[UPC] Fallback to filesystem src 😖');
|
||||
const el = document.createElement('script');
|
||||
el.type = 'text/javascript';
|
||||
el.src = '<?=$upcLocalSrc?>';
|
||||
document.head.appendChild(el);
|
||||
return upcEnv('local', false, true); // set session cookie to prevent delayed loads of UPC
|
||||
}, 3000);
|
||||
|
||||
function upcEnv(str, reload = true, session = false) { // overwrite upc src
|
||||
const ckName = 'UPC_ENV';
|
||||
const ckDate = new Date();
|
||||
const ckDays = 30;
|
||||
ckDate.setTime(ckDate.getTime()+(ckDays*24*60*60*1000));
|
||||
const ckExpire = `expires=${session ? 0 : ckDate.toGMTString()};`;
|
||||
if (!str) { // if no str param provided we remove the cookie to fallback to the enviroment's default JS source
|
||||
console.log(`✨ ${ckName} removed…reloading ♻️ `);
|
||||
document.cookie = `${ckName}=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT`;
|
||||
return window.location.reload();
|
||||
}
|
||||
if (reload) {
|
||||
console.log(`✨ ${ckName} set…reloading ✨ `);
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
} else {
|
||||
console.log(`✨ ${ckName}=${str} for session ✨ `);
|
||||
}
|
||||
return document.cookie = `${ckName}=${str}; path=/; ${ckExpire}`;
|
||||
};
|
||||
</script>
|
||||
<!-- /myservers1 -->
|
||||
|
@@ -1,648 +1,36 @@
|
||||
<!-- myservers2 -->
|
||||
<?
|
||||
// add 'ipaddr' function for 6.9 backwards compatibility
|
||||
if (!function_exists('ipaddr')) {
|
||||
function ipaddr($ethX='eth0', $prot=4) {
|
||||
global $$ethX;
|
||||
switch ($$ethX['PROTOCOL:0']) {
|
||||
case 'ipv4':
|
||||
return $$ethX['IPADDR:0'];
|
||||
case 'ipv6':
|
||||
return $$ethX['IPADDR6:0'];
|
||||
case 'ipv4+ipv6':
|
||||
switch ($prot) {
|
||||
case 4: return $$ethX['IPADDR:0'];
|
||||
case 6: return $$ethX['IPADDR6:0'];
|
||||
default:return [$$ethX['IPADDR:0'],$$ethX['IPADDR6:0']];}
|
||||
default:
|
||||
return $$ethX['IPADDR:0'];
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once("$docroot/plugins/dynamix.my.servers/include/state.php");
|
||||
require_once("$docroot/plugins/dynamix.my.servers/include/translations.php");
|
||||
|
||||
$upc_translations = [
|
||||
($_SESSION['locale']) ? $_SESSION['locale'] : 'en_US' => [
|
||||
'getStarted' => _('Get Started'),
|
||||
'signIn' => _('Sign In'),
|
||||
'signUp' => _('Sign Up'),
|
||||
'signInUp' => _('Sign In / Up'),
|
||||
'signInUnraidNetAccount' => _('Sign In with Unraid.net Account'),
|
||||
'signOut' => _('Sign Out'),
|
||||
'error' => _('Error'),
|
||||
'fixError' => _('Fix Error'),
|
||||
'closeLaunchpad' => _('Close Launchpad and continue to webGUI'),
|
||||
'installPlugin' => _('Install Plugin'),
|
||||
'noThanks' => _('No thanks'),
|
||||
'closePromo' => _('Close Connect details and continue to webGUI'),
|
||||
'promoHeading' => _('Enhance your Unraid experience with these<br> Connect (BETA) features'),
|
||||
'learnMore' => _('Learn more'),
|
||||
'checkoutTheMyServersDocs' => _('Checkout the Connect docs'),
|
||||
'popUp' => _('Pop-up'),
|
||||
'close' => _('Close'),
|
||||
'backToPopUp' => sprintf(_('Back to %s'), _('Pop-up')),
|
||||
'closePopUp' => sprintf(_('Close %s'), _('Pop-up')),
|
||||
'contactSupport' => _('Contact Support'),
|
||||
'lanIp' => sprintf(_('Click to copy LAN IP %s'), '{0}'),
|
||||
'lanIpCopied' => _('LAN IP Copied'),
|
||||
'continueToUnraid' => _('Continue to Unraid'),
|
||||
'description' => _('Description'),
|
||||
'year' => _('year'),
|
||||
'years' => _('years'),
|
||||
'month' => _('month'),
|
||||
'months' => _('months'),
|
||||
'day' => _('day'),
|
||||
'days' => _('days'),
|
||||
'hour' => _('hour'),
|
||||
'hours' => _('hours'),
|
||||
'minute' => _('minute'),
|
||||
'minutes' => _('minutes'),
|
||||
'second' => _('second'),
|
||||
'seconds' => _('seconds'),
|
||||
'ago' => _('ago'),
|
||||
'basicPlusPro' => [
|
||||
'heading' => _('Thank you for choosing Unraid OS and Connect').'!',
|
||||
'message' => [
|
||||
'registered' => _('Register for Connect by signing in to Unraid.net'),
|
||||
'upgradeEligible' => _('To support more storage devices as your server grows click Upgrade Key'),
|
||||
],
|
||||
],
|
||||
'actions' => [
|
||||
'purchase' => _('Purchase Key'),
|
||||
'upgrade' => _('Upgrade Key'),
|
||||
'recover' => _('Recover Key'),
|
||||
'replace' => _('Replace Key'),
|
||||
'replaceIneligible' => _('Replace Key Ineligible'),
|
||||
'extend' => _('Extend Trial'),
|
||||
'startTrial' => _('Start Trial'),
|
||||
'signOutUnraidNet' => _('Sign Out of Unraid.net'),
|
||||
'redeemActivationCode' => _('Redeem Activation Code'),
|
||||
],
|
||||
'upc' => [
|
||||
'avatarAlt' => '{0} '._('Avatar'),
|
||||
'confirmClosure' => _('Confirm closure then continue to webGUI'),
|
||||
'closeDropdown' => _('Close dropdown'),
|
||||
'openDropdown' => _('Open dropdown'),
|
||||
'pleaseConfirmClosureYouHaveOpenPopUp' => _('Please confirm closure').'. '._('You have an open pop-up').'.',
|
||||
'trialHasExpiredSeeOptions' => _('Trial has expired see options below'),
|
||||
'errorCertRequiresSignIn' => _('Sign In before your Unraid.net SSL certificate expires'),
|
||||
'removeMyServersPlugin' => _('Remove Connect plugin'),
|
||||
'continueUsingMyServers' => _('Continue using Connect'),
|
||||
'confirmMyServersPluginRemoval' => _('Confirm Connect plugin removal'),
|
||||
'removingMyServersPlugin' => _('Removing Connect plugin…'),
|
||||
'enhanceYourExperienceWithMyServers' => _('Enhance your experience with Connect'),
|
||||
'lanIpCopied' => _('LAN IP Copied'),
|
||||
'installingMyServers' => _('Installing Connect (beta)'),
|
||||
"updatePlugin" => _('Update Plugin'),
|
||||
"updatingMyServers" => _('Updating Connect (beta)'),
|
||||
'thankYouForInstallingMyServers' => _('Thank you installing Connect') . '!',
|
||||
'connectYourUnraidnetAccountToGetStarted' => _('Connect your Unraid.net account to get started'),
|
||||
'noRemoteApikeyRegisteredWithPlg' => [
|
||||
'heading' => _('Connect Error'),
|
||||
'msg' => _('Unraid.net re-authentication required'),
|
||||
],
|
||||
'errorTooManyDisks' => [
|
||||
'heading' => 'Too many devices',
|
||||
'msg' => [
|
||||
'base' => 'You must upgrade your key to support more devices.',
|
||||
'basic' => 'Your Basic key supports 6 devices.',
|
||||
'plus' => 'Your Plus key supports 12 devices.',
|
||||
],
|
||||
],
|
||||
'extraLinks' => [
|
||||
'newTab' => sprintf(_('Opens %s in new tab'), '{0}'),
|
||||
'myServers' => _('Go to Connect'),
|
||||
'forums' => _('Unraid Forums'),
|
||||
'settings' => [
|
||||
'text' => _('Settings'),
|
||||
'title' => _('Settings > Management Access • Unraid.net'),
|
||||
],
|
||||
],
|
||||
'meta' => [
|
||||
'trial' => [
|
||||
'active' => [
|
||||
'date' => sprintf(_('Trial key expires at %s'), '{date}'),
|
||||
'timeDiff' => sprintf(_('Trial expires in %s'), '{timeDiff}'),
|
||||
],
|
||||
'expired' => [
|
||||
'date' => sprintf(_('Trial key expired at %s'), '{date}'),
|
||||
'timeDiff' => sprintf(_('Trial expired %s'), '{timeDiff}'),
|
||||
],
|
||||
],
|
||||
'uptime' => [
|
||||
'date' => sprintf(_('Server up since %s'), '{date}'),
|
||||
'readable' => sprintf(_('Uptime %s'), '{timeDiff}'),
|
||||
],
|
||||
],
|
||||
'myServers' => [
|
||||
'heading' => _('Connect'),
|
||||
'beta' => _('beta'),
|
||||
'restarting' => _('Restarting…'),
|
||||
'errors' => [
|
||||
'unraidApi' => [
|
||||
'heading' => _('Unraid API Error'),
|
||||
'message' => _('Failed to connect to Unraid API'),
|
||||
],
|
||||
'myServers' => [
|
||||
'heading' => _('Connect Error'),
|
||||
'message' => _('Please wait a moment and reload the page'),
|
||||
],
|
||||
],
|
||||
'closeDetails' => _('Close Details'),
|
||||
'loading' => _('Loading Connect data'),
|
||||
'displayingLastKnown' => _('Displaying last known server data'),
|
||||
'mothership' => [
|
||||
'connected' => _('Connected'),
|
||||
'notConnected' => _('Disconnected'),
|
||||
],
|
||||
'accessLabels' => [
|
||||
'current' => _('Current server'),
|
||||
'local' => _('Local access'),
|
||||
'offline' => _('Server Offline'),
|
||||
'remote' => _('Remote access'),
|
||||
'unavailable' => _('Access unavailable'),
|
||||
],
|
||||
'api' => [
|
||||
'start' => _('Restart unraid-api'),
|
||||
'startTitle' => _('Executes `unraid-api start`; no terminal needed'),
|
||||
'stop' => _('Stop unraid-api'),
|
||||
],
|
||||
],
|
||||
'opensNewHttpsWindow' => [
|
||||
'base' => sprintf(_('Opens new HTTPS window to %s'), '{0}'),
|
||||
'signIn' => sprintf(_('Opens new HTTPS window to %s'), _('Sign In')),
|
||||
'signOut' => sprintf(_('Opens new HTTPS window to %s'), _('Sign Out')),
|
||||
'purchase' => sprintf(_('Opens new HTTPS window to %s'), _('Purchase Key')),
|
||||
'upgrade' => sprintf(_('Opens new HTTPS window to %s'), _('Upgrade Key')),
|
||||
],
|
||||
'signInActions' => [
|
||||
'resolve' => _('Sign In to resolve'),
|
||||
'purchaseKey' => _('Sign In to Purchase Key'),
|
||||
'purchaseKeyOrExtendTrial' => '@:upc.signInActions.purchaseKey or @:actions.extend',
|
||||
],
|
||||
],
|
||||
'stateData' => [
|
||||
'ENOKEYFILE' => [
|
||||
'humanReadable' => _('No Keyfile'),
|
||||
'heading' => _("Let's unleash your hardware").'!',
|
||||
'message' => '<p>'._('Your server will not be usable until you purchase a Registration key or install a free 30-day Trial key').'. '._('A Trial 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 (min 4GB recommended)').'.</p><p>'._('Note: USB memory card readers are generally not supported because most do not present unique serial numbers').'.</p>',
|
||||
],
|
||||
'TRIAL' => [
|
||||
'humanReadable' => _('Trial'),
|
||||
'heading' => _('Thank you for choosing Unraid OS').'!',
|
||||
'message' => _('Your Trial key includes all the functionality and device support of a Pro key').'. '._('After your Trial has reached expiration your server still functions normally until the next time you Stop the array or reboot your server').'. '._('At that point you may either purchase a license key or request a Trial extension').'.',
|
||||
'_extraMsg' => sprintf(_('You have %s remaining on your Trial key'), '{parsedExpireTime}'),
|
||||
],
|
||||
'EEXPIRED' => [
|
||||
'humanReadable' => _('Trial Expired'),
|
||||
'heading' => _('Your Trial has expired'),
|
||||
'message' => [
|
||||
'base' => _('To continue using Unraid OS you may purchase a license key').'. ',
|
||||
'extensionNotEligible' => _('You have used all your Trial extensions').'. @:stateData.EEXPIRED.message.base',
|
||||
'extensionEligible' => '@:stateData.EEXPIRED.message.base '._('Alternately, you may request a Trial extension').'.',
|
||||
],
|
||||
],
|
||||
'BASIC' => [
|
||||
'humanReadable' => _('Basic'),
|
||||
],
|
||||
'PLUS' => [
|
||||
'humanReadable' => _('Plus'),
|
||||
],
|
||||
'PRO' => [
|
||||
'humanReadable' => _('Pro'),
|
||||
],
|
||||
'EGUID' => [
|
||||
'humanReadable' => _('GUID Error'),
|
||||
'error' => [
|
||||
'heading' => _('Registration key / GUID mismatch'),
|
||||
'message' => [
|
||||
'default' => _('The license key file does not correspond to the USB Flash boot device').'. '._('Please copy the correct key file to the */config* directory on your USB Flash boot device or choose Purchase Key').'.',
|
||||
'replacementIneligible' => _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months').'.',
|
||||
'replacementEligible' => _('The license key file does not correspond to the USB Flash boot device').'. '._('Please copy the correct key file to the */config* directory on your USB Flash boot device or choose Purchase Key or Replace Key').'.',
|
||||
'blacklisted' => _('Your Unraid registration key is ineligible for replacement as it is blacklisted') . '.',
|
||||
],
|
||||
],
|
||||
],
|
||||
'ENOKEYFILE2' => [
|
||||
'humanReadable' => _('Missing key file'),
|
||||
'error' => [
|
||||
'heading' => '@:stateData.ENOKEYFILE2.humanReadable',
|
||||
'message' => _('It appears that your license key file is corrupted or missing').'. '._('The key file should be located in the */config* directory on your USB Flash boot device').'. '._('If you do not have a backup copy of your license key file you may install the Connect (beta) plugin to attempt to recover your key').'. '._('If this was an expired Trial installation, you may purchase a license key').'.',
|
||||
],
|
||||
],
|
||||
'ETRIAL' => [
|
||||
'humanReadable' => _('Invalid installation'),
|
||||
'error' => [
|
||||
'heading' => '@:stateData.ETRIAL.humanReadable',
|
||||
'message' => _('It is not possible to use a Trial key with an existing Unraid OS installation').'. '._('You may purchase a license key corresponding to this USB Flash device to continue using this installation').'.',
|
||||
],
|
||||
],
|
||||
'ENOKEYFILE1' => [
|
||||
'humanReadable' => _('No Keyfile'),
|
||||
'error' => [
|
||||
'heading' => _('No USB flash configuration data'),
|
||||
'message' => _('There is a problem with your USB Flash device'),
|
||||
],
|
||||
],
|
||||
'ENOFLASH' => [
|
||||
'humanReadable' => _('No Flash'),
|
||||
'error' => [
|
||||
'heading' => _('Cannot access your USB Flash boot device'),
|
||||
'message' => _('There is a physical problem accessing your USB Flash boot device'),
|
||||
],
|
||||
],
|
||||
'EGUID1' => [
|
||||
'humanReadable' => _('Multiple License Keys Present'),
|
||||
'error' => [
|
||||
'heading' => '@:stateData.EGUID1.humanReadable',
|
||||
'message' => _('There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device').'. '._('Please remove all key files except the one you want to replace from the */config* directory on your USB Flash boot device').'. '._('Alternately you may purchase a license key for this USB flash device').'. '._('If you want to replace one of your license keys with a new key bound to this USB Flash device please first remove all other key files first').'.',
|
||||
],
|
||||
],
|
||||
'EBLACKLISTED' => [
|
||||
'humanReadable' => _('BLACKLISTED'),
|
||||
'error' => [
|
||||
'heading' => _('Blacklisted USB Flash GUID'),
|
||||
'message' => _('This USB Flash boot device has been blacklisted').'. '._('This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device').'. '._('A USB Flash device may also be blacklisted if we discover the serial number is not unique – this is common with USB card readers').'.',
|
||||
],
|
||||
],
|
||||
'EBLACKLISTED1' => [
|
||||
'humanReadable' =>'@:stateData.EBLACKLISTED.humanReadable',
|
||||
'error' => [
|
||||
'heading' => _('USB Flash device error'),
|
||||
'message' => _('This USB Flash device has an invalid GUID').'. '._('Please try a different USB Flash device').'.',
|
||||
],
|
||||
],
|
||||
'EBLACKLISTED2' => [
|
||||
'humanReadable' => '@:stateData.EBLACKLISTED.humanReadable',
|
||||
'error' => [
|
||||
'heading' => _('USB Flash has no serial number'),
|
||||
'message' => '@:stateData.EBLACKLISTED.error.message',
|
||||
],
|
||||
],
|
||||
'ENOCONN' => [
|
||||
'humanReadable' => _('Trial Requires Internet Connection'),
|
||||
'error' => [
|
||||
'heading' => _('Cannot validate Unraid Trial key'),
|
||||
'message' => _('Your Trial key requires an internet connection').'. '._('Please check Settings > Network').'.',
|
||||
],
|
||||
],
|
||||
'STALE' => [
|
||||
'humanReadable' => _('Stale'),
|
||||
'error' => [
|
||||
'heading' => _('Stale Server'),
|
||||
'message' => _('Please refresh the page to ensure you load your latest configuration'),
|
||||
],
|
||||
],
|
||||
],
|
||||
'regWizPopUp' => [
|
||||
'regWiz' => _('Registration Wizard'),
|
||||
'toHome' => _('To Registration Wizard Home'),
|
||||
'continueTrial' => _('Continue Trial'),
|
||||
'serverInfoToggle' => _('Toggle server info visibility'),
|
||||
'youCanSafelyCloseThisWindow' => _('You can safely close this window'),
|
||||
'automaticallyClosingIn' => sprintf(_('Auto closing in %s'), '{0}'),
|
||||
'byeBye' => _('bye bye 👋'),
|
||||
'browserWillSelfDestructIn' => sprintf(_('Browser will self destruct in %s'), '{0}'),
|
||||
'closingPopUpMayLeadToErrors' => _('Closing this pop-up window while actions are being preformed may lead to unintended errors'),
|
||||
'goBack' => _('Go Back'),
|
||||
'shutDown' => _('Shut Down'),
|
||||
'haveAccountSignIn' => _('Already have an account').'? '._('Sign In'),
|
||||
'noAccountSignUp' => _('Do not have an account').'? '._('Sign Up'),
|
||||
'willConnectYourServerToMyServers' => _('This will register your server with Connect <sup>BETA</sup>'),
|
||||
'serverInfo' => [
|
||||
'flash' => _('Flash'),
|
||||
'product' => _('Product'),
|
||||
'GUID' => _('GUID'),
|
||||
'name' => _('Name'),
|
||||
'ip' => _('IP'),
|
||||
],
|
||||
'forms' => [
|
||||
'displayName' => _('Display Name'),
|
||||
'emailAddress' => _('Email Address'),
|
||||
'displayNameOrEmailAddress' => _('Display Name or Email Address'),
|
||||
'displayNameRootMessage' => _('Use your Unraid.net credentials, not your local server credentials'),
|
||||
'honeyPotCopy' => _('If you fill this field out then your email will not be sent'),
|
||||
'fieldRequired' => _('This field is required'),
|
||||
'submit' => _('Submit'),
|
||||
'submitting' => _('Submitting'),
|
||||
'notValid' => _('Form not valid'),
|
||||
'cancel' => _('Cancel'),
|
||||
'confirm' => _('Confirm'),
|
||||
'createMyAccount' => _('Create My Account'),
|
||||
'subject' => _('Subject'),
|
||||
'password' => _('Password'),
|
||||
'togglePasswordVisibility' => _('Toggle Password Visibility'),
|
||||
'message' => _('Message'),
|
||||
'confirmPassword' => _('Confirm Password'),
|
||||
'passwordMustMatch' => _('Password confirmation must match'),
|
||||
'passwordMinimum' => _('8 or more characters'),
|
||||
'comments' => _('comments'),
|
||||
'newsletterCopy' => _('Sign me up for the monthly Unraid newsletter').': '._('a digest of recent blog posts, community videos, popular forum threads, product announcements, and more'),
|
||||
'terms' => [
|
||||
'iAgree' => _('I agree to the'),
|
||||
'text' => _('Terms of Use'),
|
||||
],
|
||||
],
|
||||
'routes' => [
|
||||
'extendTrial' => [
|
||||
'heading' => [
|
||||
'loading' => _('Extending Trial'),
|
||||
'error' => _('Trial Extension Failed'),
|
||||
],
|
||||
'message' => _('Not ready to purchase?').'<br>'._('Receive an additional 15 days for your trial').'.',
|
||||
],
|
||||
'forgotPassword' => [
|
||||
'heading' => _('Forgot Password'),
|
||||
'subheading' => _("After resetting your password come back to the Registration Wizard pop-up window to Sign In and complete your server's registration"),
|
||||
'resetPasswordNow' => _('Reset Password Now'),
|
||||
'backToSignIn' => _('Back to Sign In'),
|
||||
],
|
||||
'signIn' => [
|
||||
'heading' => [
|
||||
'signIn' => _('Unraid.net Sign In'),
|
||||
'recover' => _('Unraid.net Sign In to Recover Key'),
|
||||
'replace' => _('Unraid.net Sign In to Replace Key'),
|
||||
],
|
||||
'form' => [
|
||||
'replacementConditions' => [
|
||||
'name' => _('Acknowledge Replacement Conditions'),
|
||||
'label' => _('I acknowledge that replacing a license key results in permanently blacklisting the previous USB Flash GUID'),
|
||||
],
|
||||
'label' => [
|
||||
'password' => [
|
||||
'replace' => _('Unraid.net account password'),
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'signUp' => [
|
||||
'heading' => _('Create Unraid.net Account'),
|
||||
],
|
||||
'signOut' => [
|
||||
'heading' => _('Unraid.net Sign Out'),
|
||||
'warnings' => [
|
||||
'remoteAccessDisabled' => _('Remote access will be disabled'),
|
||||
'remoteAccessInaccessible' => sprintf(_('You will no longer have access to this server using <abbr title="%s" class="italic">this url</abbr>'), '{0}'),
|
||||
'disablingFlashBackup' => _('Automated flash backups will be disabled until you sign in again'),
|
||||
'downloadFlashBackup' => _('Download latest backup from Connect Dashboard before signing out'),
|
||||
],
|
||||
],
|
||||
'success' => [
|
||||
'heading' => [
|
||||
'username' => sprintf(_('Hi %s'), '{0}'),
|
||||
'default' => _('Success'),
|
||||
],
|
||||
'subheading' => [
|
||||
'extention' => _('Your trial will expire in 15 days'),
|
||||
'newTrial' => _('Your trial will expire in 30 days'),
|
||||
],
|
||||
'signIn' => [
|
||||
'tileTitle' => [
|
||||
'actionFail' => sprintf(_('%s was not signed in to your Unraid.net account'), '{0}'),
|
||||
'actionSuccess' => sprintf(_('%s is signed in to your Unraid.net account'), '{0}'),
|
||||
'loading' => sprintf(_('Signing in %s to Unraid.net account'), '{0}'),
|
||||
],
|
||||
],
|
||||
'signOut' => [
|
||||
'tileTitle' => [
|
||||
'actionFail' => sprintf(_('%s was not signed out of your Unraid.net account'), '{0}'),
|
||||
'actionSuccess' => sprintf(_('%s was signed out of your Unraid.net account'), '{0}'),
|
||||
'loading' => sprintf(_('Signing out %s from Unraid.net account'), '{0}'),
|
||||
],
|
||||
],
|
||||
'keys' => [
|
||||
'trial' => _('Trial'),
|
||||
'basic' => _('Basic'),
|
||||
'plus' => _('Plus'),
|
||||
'pro' => _('Pro'),
|
||||
],
|
||||
'extended' => sprintf(_('%s Key Extended'), '{0}'),
|
||||
'recovered' => sprintf(_('%s Key Recovered'), '{0}'),
|
||||
'replaced' => sprintf(_('%s Key Replaced'), '{0}'),
|
||||
'created' => sprintf(_('%s Key Created'), '{0}'),
|
||||
'install' => [
|
||||
'loading' => sprintf(_('Installing %s Key'), '{0}'),
|
||||
'error' => sprintf(_('%s Key Install Error'), '{0}'),
|
||||
'success' => sprintf(_('Installed %s Key'), '{0}'),
|
||||
'manualInstructions' => _('To manually install the key paste the key file url into the Key file URL field on the webGUI Tools > Registration page and then click Install Key') . '.',
|
||||
'copyFail' => _('Unable to copy'),
|
||||
'copySuccess' => _('Copied key url') . '!',
|
||||
'copyButton' => _('Copy Key URL'),
|
||||
'copyBeforeClose' => _('Please copy the Key URL before closing this window'),
|
||||
],
|
||||
'timeout' => sprintf(_('Communication with %s has timed out'), '{0}'),
|
||||
'loading1' => _('Please keep this window open'),
|
||||
'loading2' => _('Still working our magic'),
|
||||
'countdown' => [
|
||||
'success' => [
|
||||
'prefix' => sprintf(_('Auto closing in %s'), '{0}'),
|
||||
'text' => _('You can safely close this window'),
|
||||
],
|
||||
'error' => [
|
||||
'prefix' => sprintf(_('Auto redirecting in %s'), '{0}'),
|
||||
'text' => _('Back to Registration Home'),
|
||||
'complete' => _('Back in a flash ⚡️'),
|
||||
],
|
||||
],
|
||||
],
|
||||
'troubleshoot' => [
|
||||
'heading' => [
|
||||
'default' => _('Troubleshoot'),
|
||||
'success' => _('Thank you for contacting Unraid'),
|
||||
],
|
||||
'subheading' => [
|
||||
'default' => _("Forgot what Unraid.net account you used").'? '._("Have a USB flash device that already has an account associated with it").'? '._("Just give us the details about what happened and we'll do our best to get you up and running again").'.',
|
||||
'success' => _('We have received your e-mail and will respond in the order it was received').'. '._('While we strive to respond to all requests as quickly as possible please allow for up to 3 business days for a response').'.',
|
||||
],
|
||||
'relevantServerData' => _('Your USB Flash GUID and other relevant server data will also be sent'),
|
||||
],
|
||||
'verifyEmail' => [
|
||||
'heading' => _('Verify Email'),
|
||||
'subheading' => sprintf(_('We have sent a verifcation email to %s'), '{0}'),
|
||||
'form' => [
|
||||
'verificationCode' => _('verification code'),
|
||||
'verifyCode' => _('Paste or Enter code'),
|
||||
],
|
||||
'noCode' => _("Didn't get code?"),
|
||||
],
|
||||
'verifyEmailResend' => [
|
||||
'heading' => _('Resend Email Verification Code'),
|
||||
'goBack' => _("Have the code now? Go Back"),
|
||||
'resend' => _("Resend Code"),
|
||||
],
|
||||
'whatIsMyServers' => [
|
||||
'heading' => _('What is Unraid.net?'),
|
||||
'subheading' => _('Expand your servers capabilities'),
|
||||
'copy' => _('With an Unraid.net account you can start using Connect (beta) which gives you access to the following features:'),
|
||||
'features' => [
|
||||
"dynamicRemoteAccess" => [
|
||||
'heading' => _('Dynamic Remote Access'),
|
||||
'copy' => _('Toggle on/off server accessibility with dynamic remote access').'. '._('Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds').'.',
|
||||
],
|
||||
"manageWithinConnect" => [
|
||||
'heading' => _('Manage Your Server Within Connect'),
|
||||
'copy' => _('Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI').'. '._('Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window').'.',
|
||||
],
|
||||
"deepLinking" => [
|
||||
'heading' => _('Deep Linking'),
|
||||
'copy' => _('The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections').'.',
|
||||
],
|
||||
"onlineFlashBackup" => [
|
||||
'heading' => _('Online Flash Backup'),
|
||||
'copy' => _('Never ever be left without a backup of your config').'. '._('If you need to change flash drives, generate a backup from Connect and be up and running in minutes').'.',
|
||||
],
|
||||
"realTimeMonitoring" => [
|
||||
'heading' => _('Real-time Monitoring'),
|
||||
'copy' => _("Get an overview of your server's state, storage space, apps and VMs status, and more").'.',
|
||||
],
|
||||
"customizableDashboardTitles" => [
|
||||
'heading' => _('Customizable Dashboard Tiles'),
|
||||
'copy' => _("Set custom server tiles how you like and automatically display your server's banner image on your Connect Dashboard").'.',
|
||||
],
|
||||
"licenseManagement" => [
|
||||
'heading' => _('License Management'),
|
||||
'copy' => _('Manage your license keys at any time via the My Keys section').'.',
|
||||
],
|
||||
'plusMore' => [
|
||||
'heading' => _('Plus more on the way'),
|
||||
'copy' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin').'. '._('Get started by installing the plugin') . '.',
|
||||
],
|
||||
],
|
||||
],
|
||||
'replaceKey' => [
|
||||
'subheading' => [
|
||||
'registered' => 'A record of your replacement will be sent to your Unraid.net account email address',
|
||||
'notRegistered' => 'A record of your replacement will be sent to this email',
|
||||
],
|
||||
],
|
||||
'notFound' => [
|
||||
'subheading' => _('Page Not Found'),
|
||||
],
|
||||
'notAllowed' => [
|
||||
'subheading' => _('Page Not Allowed'),
|
||||
],
|
||||
],
|
||||
],
|
||||
'wanIpCheck' => [
|
||||
'checking' => _('Checking Wan IPs'),
|
||||
'match' => sprintf(_('Remark: your WAN IPv4 is **%s**'), '{0}'),
|
||||
'mismatch' => sprintf(_("Remark: Unraid's WAN IPv4 **%1s** does not match your client's WAN IPv4 **%2s**"), '{0}', '{1}').'. '._('This may indicate a complex network that will not work with this Remote Access solution').'. '._('Ignore this message if you are currently connected via Remote Access or VPN').'.',
|
||||
'resolveError' => _('DNS issue, unable to resolve wanip4.unraid.net'),
|
||||
],
|
||||
'upcTrigger' => [
|
||||
'upgrade' => _('To support more storage devices as your server grows click the *Open Dropdown* button').'.',
|
||||
'default' => _('Key management is done via the dropdown in the top right of the webGUI on every page').'.',
|
||||
'open' => _('Open Dropdown'),
|
||||
],
|
||||
'yargYePirate' => _('Oh no! Are you pirating Unraid OS?<br>Are you ready to buy a real license?'),
|
||||
'keyFileNotValid' => _('Key file not valid'),
|
||||
'installFailed' => [
|
||||
'heading' => _('Connect plugin install failed'),
|
||||
'message' => _('The Connect plugin install is incomplete').'. '._('Please uninstall and reinstall the Connect plugin').'. '._('Be sure to let the install complete before you close the window').'.',
|
||||
],
|
||||
"downloadUnraidApiLogs" => _('Download unraid-api Logs'),
|
||||
"download" => _('Download'),
|
||||
"pleaseWait" => _('Please wait…')
|
||||
],
|
||||
];
|
||||
// note: $myservers variable defined in myservers1.php, by parsing myservers.cfg
|
||||
|
||||
$configErrorEnum = [ // used to map $var['configValid'] value to mimic unraid-api's `configError` ENUM
|
||||
"error" => 'UNKNOWN_ERROR',
|
||||
"invalid" => 'INVALID',
|
||||
"nokeyserver" => 'NO_KEY_SERVER',
|
||||
"withdrawn" => 'WITHDRAWN',
|
||||
];
|
||||
$nginx = parse_ini_file('/var/local/emhttp/nginx.ini');
|
||||
|
||||
$plgInstalled = '';
|
||||
if (!file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net') && !file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) {
|
||||
$plgInstalled = ''; // base OS only, plugin not installed • show ad for plugin
|
||||
} else {
|
||||
// plugin is installed but if the unraid-api file doesn't fully install it's a failed install
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) $plgInstalled = 'dynamix.unraid.net.plg';
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) $plgInstalled = 'dynamix.unraid.net.staging.plg';
|
||||
// plugin install failed • append failure detected so we can show warning about failed install via UPC
|
||||
if (!file_exists('/usr/local/sbin/unraid-api')) $plgInstalled = $plgInstalled . '_installFailed';
|
||||
}
|
||||
|
||||
// read flashbackup ini file
|
||||
$flashbackup_ini = '/var/local/emhttp/flashbackup.ini';
|
||||
$flashbackup_status = (file_exists($flashbackup_ini)) ? @parse_ini_file($flashbackup_ini) : [];
|
||||
|
||||
$serverstate = [ // feeds server vars to Vuex store in a slightly different array than state.php
|
||||
"avatar" => (!empty($myservers['remote']['avatar']) && $plgInstalled) ? $myservers['remote']['avatar'] : '',
|
||||
"config" => [
|
||||
'valid' => $var['configValid'] === 'yes',
|
||||
'error' => $var['configValid'] !== 'yes'
|
||||
? (array_key_exists($var['configValid'], $configErrorEnum) ? $configErrorEnum[$var['configValid']] : 'UNKNOWN_ERROR')
|
||||
: null,
|
||||
],
|
||||
"deviceCount" => $var['deviceCount'],
|
||||
"email" => $myservers['remote']['email'] ?? '',
|
||||
"extraOrigins" => explode(',', $myservers['api']['extraOrigins']??''),
|
||||
"flashproduct" => $var['flashProduct'],
|
||||
"flashvendor" => $var['flashVendor'],
|
||||
"flashBackupActivated" => empty($flashbackup_status['activated']) ? '' : 'true',
|
||||
"guid" => $var['flashGUID'],
|
||||
"hasRemoteApikey" => !empty($myservers['remote']['apikey']),
|
||||
"internalip" => ipaddr(),
|
||||
"internalport" => $_SERVER['SERVER_PORT'],
|
||||
"keyfile" => empty($var['regFILE'])? "" : str_replace(['+','/','='], ['-','_',''], trim(base64_encode(@file_get_contents($var['regFILE'])))),
|
||||
"osVersion" => $var['version'],
|
||||
"plgVersion" => $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['version'] ),
|
||||
"plgInstalled" => $plgInstalled,
|
||||
"protocol" => $_SERVER['REQUEST_SCHEME'],
|
||||
"reggen" => (int)$var['regGen'],
|
||||
"regGuid" => $var['regGUID'],
|
||||
"registered" => (!empty($myservers['remote']['username']) && $plgInstalled),
|
||||
"servername" => $var['NAME'],
|
||||
"site" => $_SERVER['REQUEST_SCHEME']."://".$_SERVER['HTTP_HOST'],
|
||||
"state" => strtoupper(empty($var['regCheck']) ? $var['regTy'] : $var['regCheck']),
|
||||
"ts" => time(),
|
||||
"username" => (!empty($myservers['remote']['username']) && $plgInstalled) ? $myservers['remote']['username'] : '',
|
||||
"wanFQDN" => $nginx['NGINX_WANFQDN'] ?? '',
|
||||
];
|
||||
/** @TODO - prop refactor needed. The issue is because the prop names share the same name as the vuex store variables
|
||||
* if we remove the props and deployed a UPC that doesn't rely on props anymore uses that don't have an updated version
|
||||
* of this file will have a non-working UPC.
|
||||
* apikey
|
||||
* apiVersion
|
||||
* csrf
|
||||
* expiretime
|
||||
* hideMyServers
|
||||
* plgPath
|
||||
* regWizTime
|
||||
* sendCrashInfo
|
||||
* serverdesc
|
||||
* servermodel
|
||||
* serverupdate
|
||||
* uptime
|
||||
*/
|
||||
$serverState = new ServerState();
|
||||
$wCTranslations = new WebComponentTranslations();
|
||||
?>
|
||||
<unraid-user-profile
|
||||
apikey="<?=$myservers['upc']['apikey'] ?? ''?>"
|
||||
api-version="<?=$myservers['api']['version'] ?? ''?>"
|
||||
banner="<?=$display['banner'] ?? ''?>"
|
||||
bgcolor="<?=($backgnd) ? '#'.$backgnd : ''?>"
|
||||
csrf="<?=$var['csrf_token']?>"
|
||||
displaydesc="<?=($display['headerdescription']??''!='no') ? 'true' : ''?>"
|
||||
expiretime="<?=1000*($var['regTy']=='Trial'||strstr($var['regTy'],'expired')?$var['regTm2']:0)?>"
|
||||
hide-my-servers="<?=$plgInstalled ? '' : 'yes' ?>"
|
||||
locale="<?=($_SESSION['locale']) ? $_SESSION['locale'] : 'en_US'?>"
|
||||
locale-messages="<?=rawurlencode(json_encode($upc_translations, JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE))?>"
|
||||
metacolor="<?=($display['headermetacolor']??'') ? '#'.$display['headermetacolor'] : ''?>"
|
||||
plg-path="dynamix.my.servers"
|
||||
reg-wiz-time="<?=$myservers['remote']['regWizTime'] ?? ''?>"
|
||||
serverdesc="<?=$var['COMMENT']?>"
|
||||
servermodel="<?=$var['SYS_MODEL']?>"
|
||||
serverstate="<?=rawurlencode(json_encode($serverstate, JSON_UNESCAPED_SLASHES))?>"
|
||||
show-banner-gradient="<?=$display['showBannerGradient'] ?? 'yes'?>"
|
||||
textcolor="<?=($header) ? '#'.$header : ''?>"
|
||||
theme="<?=$display['theme']?>"
|
||||
uptime="<?=1000*(time() - round(strtok(exec("cat /proc/uptime"),' ')))?>"
|
||||
></unraid-user-profile>
|
||||
<!-- /myservers2 -->
|
||||
<script>
|
||||
window.LOCALE_DATA = '<?= $wCTranslations->getTranslationsJson(true) ?>';
|
||||
/**
|
||||
* So we're not needing to modify DefaultLayout with an additional include, we'll add the Modals web component to the bottom of the body.
|
||||
*/
|
||||
const i18nHostWebComponent = 'unraid-i18n-host';
|
||||
const modalsWebComponent = 'unraid-modals';
|
||||
if (!document.getElementsByTagName(modalsWebComponent).length) {
|
||||
const $body = document.getElementsByTagName('body')[0];
|
||||
const $i18nHost = document.createElement(i18nHostWebComponent);
|
||||
const $modals = document.createElement(modalsWebComponent);
|
||||
$body.appendChild($i18nHost);
|
||||
$i18nHost.appendChild($modals);
|
||||
}
|
||||
</script>
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-user-profile server="<?= $serverState->getServerStateJsonForHtmlAttr() ?>"></unraid-user-profile>
|
||||
</unraid-i18n-host>
|
||||
|
105
emhttp/plugins/dynamix.my.servers/include/reboot-details.php
Normal file
105
emhttp/plugins/dynamix.my.servers/include/reboot-details.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* RebootDetails class is responsible for detecting the type and version of a system reboot required in the context of an unRAID server.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* $rebootDetails = new RebootDetails();
|
||||
* $rebootType = $rebootDetails->getRebootType();
|
||||
* ```
|
||||
*/
|
||||
class RebootDetails
|
||||
{
|
||||
/**
|
||||
* @var string $rebootType Stores the type of reboot required, which can be 'update', 'downgrade', or 'thirdPartyDriversDownloading'.
|
||||
*/
|
||||
private $rebootType = '';
|
||||
|
||||
/**
|
||||
* Constructs a new RebootDetails object and automatically detects the reboot type during initialization.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->detectRebootType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the type of reboot required based on the contents of the unRAID server's README.md file.
|
||||
* Sets the $rebootType property accordingly.
|
||||
*/
|
||||
private function detectRebootType()
|
||||
{
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
|
||||
$rebootReadme = @file_get_contents("$docroot/plugins/unRAIDServer/README.md", false, null, 0, 20) ?: '';
|
||||
$rebootDetected = preg_match("/^\*\*(REBOOT REQUIRED|DOWNGRADE)/", $rebootReadme);
|
||||
|
||||
$rebootForDowngrade = $rebootDetected && strpos($rebootReadme, 'DOWNGRADE') !== false;
|
||||
$rebootForUpdate = $rebootDetected && strpos($rebootReadme, 'REBOOT REQUIRED') !== false;
|
||||
|
||||
$this->rebootType = $rebootForDowngrade ? 'downgrade' : ($rebootForUpdate ? 'update' : '');
|
||||
|
||||
// Detect if third-party drivers were part of the update process
|
||||
$processWaitingThirdPartyDrivers = "inotifywait -q /boot/changes.txt -e move_self,delete_self";
|
||||
// Run the ps command to list processes and check if the process is running
|
||||
$ps_command = "ps aux | grep -E \"$processWaitingThirdPartyDrivers\" | grep -v \"grep -E\"";
|
||||
$output = shell_exec($ps_command) ?? '';
|
||||
if ($this->rebootType != '' && strpos($output, $processWaitingThirdPartyDrivers) !== false) {
|
||||
$this->rebootType = 'thirdPartyDriversDownloading';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of reboot required, which can be 'update', 'downgrade', or 'thirdPartyDriversDownloading'.
|
||||
*
|
||||
* @return string The type of reboot required.
|
||||
*/
|
||||
public function getRebootType()
|
||||
{
|
||||
return $this->rebootType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects and retrieves the version information related to the system reboot based on the contents of the '/boot/changes.txt' file.
|
||||
*
|
||||
* @return string The system version information or 'Not found' if not found, or 'File not found' if the file is not present.
|
||||
*/
|
||||
public function getRebootVersion()
|
||||
{
|
||||
$file_path = '/boot/changes.txt';
|
||||
|
||||
// Check if the file exists
|
||||
if (file_exists($file_path)) {
|
||||
// Open the file for reading
|
||||
$file = fopen($file_path, 'r');
|
||||
|
||||
// Read the file line by line until we find a line that starts with '# Version'
|
||||
while (($line = fgets($file)) !== false) {
|
||||
if (strpos($line, '# Version') === 0) {
|
||||
// Use a regular expression to extract the full version string
|
||||
if (preg_match('/# Version\s+(\S+)/', $line, $matches)) {
|
||||
$fullVersion = $matches[1];
|
||||
return $fullVersion;
|
||||
} else {
|
||||
return 'Not found';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the file
|
||||
fclose($file);
|
||||
} else {
|
||||
return 'File not found';
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
<?PHP
|
||||
<?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,
|
||||
@@ -9,65 +8,330 @@
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
/**
|
||||
* @todo refactor globals – currently if you try to use $GLOBALS the class will break.
|
||||
*/
|
||||
$webguiGlobals = $GLOBALS;
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
/* add translations */
|
||||
$_SERVER['REQUEST_URI'] = '';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
/**
|
||||
* ServerState class encapsulates server-related information and settings.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* require_once "$docroot/plugins/dynamix.my.servers/include/state.php";
|
||||
* $serverStateClass = new ServerState();
|
||||
*
|
||||
* $serverStateClass->getServerState();
|
||||
* or
|
||||
* $serverStateClass->getServerStateJson();
|
||||
* ```
|
||||
*/
|
||||
class ServerState
|
||||
{
|
||||
protected $webguiGlobals;
|
||||
|
||||
$var = (array)parse_ini_file('state/var.ini');
|
||||
$license_state = strtoupper(empty($var['regCheck']) ? $var['regTy'] : $var['regCheck']);
|
||||
$key_contents = empty($var['regFILE'])? "" : str_replace(['+','/','='], ['-','_',''], trim(base64_encode(@file_get_contents($var['regFILE']))));
|
||||
$myservers_flash_cfg_path='/boot/config/plugins/dynamix.my.servers/myservers.cfg';
|
||||
$myservers = file_exists($myservers_flash_cfg_path) ? @parse_ini_file($myservers_flash_cfg_path,true) : [];
|
||||
private $var;
|
||||
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',
|
||||
];
|
||||
private $osVersion;
|
||||
private $osVersionBranch;
|
||||
private $rebootDetails;
|
||||
private $caseModel = '';
|
||||
private $keyfileBase64UrlSafe = '';
|
||||
private $updateOsCheck;
|
||||
private $updateOsNotificationsEnabled = false;
|
||||
private $updateOsResponse;
|
||||
private $updateOsIgnoredReleases = [];
|
||||
|
||||
$configErrorEnum = [ // used to map $var['configValid'] value to mimic unraid-api's `configError` ENUM
|
||||
"error" => 'UNKNOWN_ERROR',
|
||||
"invalid" => 'INVALID',
|
||||
"nokeyserver" => 'NO_KEY_SERVER',
|
||||
"withdrawn" => 'WITHDRAWN',
|
||||
];
|
||||
public $myServersFlashCfg = [];
|
||||
public $myServersMemoryCfg = [];
|
||||
public $host = 'unknown';
|
||||
public $combinedKnownOrigins = [];
|
||||
|
||||
public $nginxCfg = [];
|
||||
public $flashbackupStatus = [];
|
||||
public $registered = false;
|
||||
public $myServersMiniGraphConnected = false;
|
||||
public $keyfileBase64 = '';
|
||||
|
||||
$arr = [];
|
||||
if (empty($myservers['remote']['username'])) {
|
||||
$arr['registered'] = 0;
|
||||
$arr['username'] = '';
|
||||
$arr['avatar'] = '';
|
||||
} else {
|
||||
$arr['registered'] = 1;
|
||||
$arr['username'] = $myservers['remote']['username'];
|
||||
$arr['avatar'] = $myservers['remote']['avatar']??'';
|
||||
/**
|
||||
* Constructor to initialize class properties and gather server information.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
/**
|
||||
* @note – necessary evil until full webgui is class based.
|
||||
* @see - getWebguiGlobal() for usage
|
||||
* */
|
||||
global $webguiGlobals;
|
||||
$this->webguiGlobals =& $webguiGlobals;
|
||||
// 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->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';
|
||||
}
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) {
|
||||
$this->connectPluginInstalled = 'dynamix.unraid.net.staging.plg';
|
||||
}
|
||||
if ($this->connectPluginInstalled && !file_exists('/usr/local/sbin/unraid-api')) {
|
||||
$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';
|
||||
* - $mystatus = (file_exists($myservers_memory_cfg_path)) ? @parse_ini_file($myservers_memory_cfg_path) : [];
|
||||
*/
|
||||
$flashCfgPath = '/boot/config/plugins/dynamix.my.servers/myservers.cfg';
|
||||
$this->myServersFlashCfg = file_exists($flashCfgPath) ? @parse_ini_file($flashCfgPath, true) : [];
|
||||
// ensure some vars are defined here so we don't have to test them later
|
||||
if (empty($this->myServersFlashCfg['remote']['apikey'])) {
|
||||
$this->myServersFlashCfg['remote']['apikey'] = "";
|
||||
}
|
||||
if (empty($this->myServersFlashCfg['remote']['wanaccess'])) {
|
||||
$this->myServersFlashCfg['remote']['wanaccess'] = "no";
|
||||
}
|
||||
if (empty($this->myServersFlashCfg['remote']['wanport'])) {
|
||||
$this->myServersFlashCfg['remote']['wanport'] = 33443;
|
||||
}
|
||||
if (empty($this->myServersFlashCfg['remote']['upnpEnabled'])) {
|
||||
$this->myServersFlashCfg['remote']['upnpEnabled'] = "no";
|
||||
}
|
||||
if (empty($this->myServersFlashCfg['remote']['dynamicRemoteAccessType'])) {
|
||||
$this->myServersFlashCfg['remote']['dynamicRemoteAccessType'] = "DISABLED";
|
||||
}
|
||||
|
||||
$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'] ?? '';
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
$this->host = $_SERVER['HTTP_HOST'] ?? "unknown";
|
||||
$memoryCfgPath = '/var/local/emhttp/myservers.cfg';
|
||||
$this->myServersMemoryCfg = (file_exists($memoryCfgPath)) ? @parse_ini_file($memoryCfgPath) : [];
|
||||
$this->myServersMiniGraphConnected = (($this->myServersMemoryCfg['minigraph']??'') === 'CONNECTED');
|
||||
|
||||
$allowedOrigins = $this->myServersMemoryCfg['allowedOrigins'] ?? "";
|
||||
$extraOrigins = $this->myServersFlashCfg['api']['extraOrigins'] ?? "";
|
||||
$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);
|
||||
|
||||
if ($this->combinedKnownOrigins) {
|
||||
foreach($this->combinedKnownOrigins as $key => $origin) {
|
||||
if ( (strpos($origin, "http") === false) || (strpos($origin, "localhost") !== false) ) {
|
||||
// clean up $this->combinedKnownOrigins, only display warning if origins still remain to display
|
||||
unset($this->combinedKnownOrigins[$key]);
|
||||
}
|
||||
}
|
||||
// for some reason the unset creates an associative array, so reindex the array with just the values. Otherwise we get an object passed to the UPC JS instead of an array.
|
||||
if ($this->combinedKnownOrigins) {
|
||||
$this->combinedKnownOrigins = array_values($this->combinedKnownOrigins);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information as an associative array
|
||||
*
|
||||
* @return array An array containing server information.
|
||||
*/
|
||||
public function getServerState()
|
||||
{
|
||||
$serverState = [
|
||||
"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']] : null,
|
||||
],
|
||||
"connectPluginInstalled" => $this->connectPluginInstalled,
|
||||
"connectPluginVersion" => $this->connectPluginVersion,
|
||||
"csrf" => $this->var['csrf_token'],
|
||||
"dateTimeFormat" => [
|
||||
"date" => @$this->getWebguiGlobal('display', 'date') ?? '',
|
||||
"time" => @$this->getWebguiGlobal('display', 'time') ?? '',
|
||||
],
|
||||
"description" => $this->var['COMMENT'] ? htmlspecialchars($this->var['COMMENT'], ENT_HTML5, 'UTF-8') : '',
|
||||
"deviceCount" => $this->var['deviceCount'],
|
||||
"email" => $this->email,
|
||||
"expireTime" => 1000 * (($this->var['regTy'] === 'Trial' || strstr($this->var['regTy'], 'expired')) ? $this->var['regTm2'] : 0),
|
||||
"extraOrigins" => $this->extraOrigins,
|
||||
"flashProduct" => $this->var['flashProduct'],
|
||||
"flashVendor" => $this->var['flashVendor'],
|
||||
"flashBackupActivated" => $this->flashBackupActivated,
|
||||
"guid" => $this->var['flashGUID'],
|
||||
"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'] ? 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(),
|
||||
"regDevs" => @(int)$this->var['regDevs'] ?? 0,
|
||||
"regGen" => @(int)$this->var['regGen'],
|
||||
"regGuid" => @$this->var['regGUID'] ?? '',
|
||||
"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->registeredTime,
|
||||
"site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'),
|
||||
"state" => strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']),
|
||||
"theme" => [
|
||||
"banner" => !empty($this->getWebguiGlobal('display', 'banner')),
|
||||
"bannerGradient" => $this->getWebguiGlobal('display', 'showBannerGradient') === 'yes' ?? false,
|
||||
"bgColor" => ($this->getWebguiGlobal('display', 'background')) ? '#' . $this->getWebguiGlobal('display', 'background') : '',
|
||||
"descriptionShow" => (!empty($this->getWebguiGlobal('display', 'headerdescription')) && $this->getWebguiGlobal('display', 'headerdescription') !== 'no'),
|
||||
"metaColor" => ($this->getWebguiGlobal('display', 'headermetacolor') ?? '') ? '#' . $this->getWebguiGlobal('display', 'headermetacolor') : '',
|
||||
"name" => $this->getWebguiGlobal('display', 'theme'),
|
||||
"textColor" => ($this->getWebguiGlobal('display', 'header')) ? '#' . $this->getWebguiGlobal('display', 'header') : '',
|
||||
],
|
||||
"ts" => time(),
|
||||
"uptime" => 1000 * (time() - round(strtok(exec("cat /proc/uptime"), ' '))),
|
||||
"username" => $this->username,
|
||||
"wanFQDN" => @$this->nginxCfg['NGINX_WANFQDN'] ?? '',
|
||||
];
|
||||
|
||||
if ($this->combinedKnownOrigins) {
|
||||
$serverState['combinedKnownOrigins'] = $this->combinedKnownOrigins;
|
||||
}
|
||||
|
||||
if ($this->updateOsIgnoredReleases) {
|
||||
$serverState['updateOsIgnoredReleases'] = $this->updateOsIgnoredReleases;
|
||||
}
|
||||
|
||||
if ($this->updateOsNotificationsEnabled) {
|
||||
$serverState['updateOsNotificationsEnabled'] = $this->updateOsNotificationsEnabled;
|
||||
}
|
||||
|
||||
if ($this->updateOsResponse) {
|
||||
$serverState['updateOsResponse'] = $this->updateOsResponse;
|
||||
}
|
||||
|
||||
return $serverState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information as JSON
|
||||
*
|
||||
* @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');
|
||||
}
|
||||
}
|
||||
$arr['event'] = 'STATE';
|
||||
$arr['ts'] = time();
|
||||
$arr['deviceCount'] = $var['deviceCount'];
|
||||
$arr['guid'] = $var['flashGUID'];
|
||||
$arr['regGuid'] = $var['regGUID'];
|
||||
$arr['state'] = $license_state;
|
||||
$arr['keyfile'] = $key_contents;
|
||||
$arr['reggen'] = $var['regGen'];
|
||||
$arr['flashproduct'] = $var['flashProduct'];
|
||||
$arr['flashvendor'] = $var['flashVendor'];
|
||||
$arr['servername'] = $var['NAME'];
|
||||
$arr['serverdesc'] = $var['COMMENT'];
|
||||
$arr['internalip'] = $_SERVER['SERVER_ADDR'];
|
||||
$arr['internalport'] = $_SERVER['SERVER_PORT'];
|
||||
$arr['plgVersion'] = 'base-'.$var['version'];
|
||||
$arr['protocol'] = $_SERVER['REQUEST_SCHEME'];
|
||||
$arr['locale'] = $_SESSION['locale'] ?? 'en_US';
|
||||
$arr['expiretime']=1000*($var['regTy']=='Trial'||strstr($var['regTy'],'expired')?$var['regTm2']:0);
|
||||
$arr['uptime']=1000*(time() - round(strtok(exec("cat /proc/uptime"),' ')));
|
||||
$arr['hasRemoteApikey'] = empty($myservers['remote']['apikey']) ? 0 : 1;
|
||||
$arr['hideMyServers'] = (file_exists('/usr/local/sbin/unraid-api')) ? '' : 'yes';
|
||||
$arr['config'] = [
|
||||
'valid' => $var['configValid'] === 'yes',
|
||||
'error' => $var['configValid'] !== 'yes'
|
||||
? (array_key_exists($var['configValid'], $configErrorEnum) ? $configErrorEnum[$var['configValid']] : 'UNKNOWN_ERROR')
|
||||
: null,
|
||||
];
|
||||
|
||||
echo json_encode($arr);
|
||||
?>
|
||||
|
364
emhttp/plugins/dynamix.my.servers/include/translations.php
Normal file
364
emhttp/plugins/dynamix.my.servers/include/translations.php
Normal file
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* Welcome to the Thunderdome. A place where you can get lost in a sea of translations.
|
||||
*
|
||||
* This file is used to generate the translations for the Vue3 based web components.
|
||||
*
|
||||
* These key value pairs are derived from web/locales/en_US.json.
|
||||
* We use the en_US.json file as the source of truth for the translations.
|
||||
* This file is then used to generate the translations for the web components and delivered to them via PHP as a JSON object in myservers2.php (my favorite file name).
|
||||
* The web components then use the translations to display the appropriate text to the user.
|
||||
*
|
||||
* Workflow is as follows:
|
||||
* 1. Create a new translation in en_US.json
|
||||
* 2. Create a new translation in this file
|
||||
* 3. Open unraid/lang-en_US and add the new translation to the appropriate file – typically translations.txt.
|
||||
* 3a. This is done so that the translation is available to the rest of the Unraid webgui.
|
||||
* 3b. Unfortunately there are numerous "special characters" that aren't allowed in Unraid's translation keys as they're automatically stripped out.
|
||||
* 3c. This means that we have to create a new translation key that is a "safe" version of the translation key used in the web components.
|
||||
* 3d. Special characters that are not allowed are: ? { } | & ~ ! [ ] ( ) / : * ^ . " '
|
||||
* 3e. There are likely more but I'm unable to find the documentation PDF - updated list of invalid characters above as mentioned in the language guide document.
|
||||
*
|
||||
* Usage example:
|
||||
* ```
|
||||
* $wCTranslations = new WebComponentTranslations();
|
||||
* $wCTranslations->getTranslations();
|
||||
* ```
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
class WebComponentTranslations
|
||||
{
|
||||
private $translations = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->initializeTranslations();
|
||||
}
|
||||
|
||||
private function initializeTranslations()
|
||||
{
|
||||
$this->translations[$_SESSION['locale'] ?? 'en_US'] = [
|
||||
'{0} {1} Key…' => sprintf(_('%1s %2s Key…'), '{0}', '{1}'),
|
||||
'{0} devices' => sprintf(_('%s devices'), '{0}'),
|
||||
'{0} out of {1} allowed devices – upgrade your key to support more devices' => sprintf(_('%1s out of %2s allowed devices – upgrade your key to support more devices'), '{0}', '{1}'),
|
||||
'{0} out of {1} devices' => sprintf(_('%1s out of %2s devices'), '{0}', '{1}'),
|
||||
'{0} Release Notes' => sprintf(_('%s Release Notes'), '{0}'),
|
||||
'{0} Signed In Successfully' => sprintf(_('%s Signed In Successfully'), '{0}'),
|
||||
'{0} Signed Out Successfully' => sprintf(_('%s Signed Out Successfully'), '{0}'),
|
||||
'{0} Update Available' => sprintf(_('%s Update Available'), '{0}'),
|
||||
'{1} Key {0} Successfully' => sprintf(_('%2s Key %1s Successfully'), '{0}', '{1}'),
|
||||
'<p>It is not possible to use a Trial key with an existing Unraid OS installation.</p><p>You may purchase a license key corresponding to this USB Flash device to continue using this installation.</p>' => '<p>' . _('It is not possible to use a Trial key with an existing Unraid OS installation') . '</p><p>' . _('You may purchase a license key corresponding to this USB Flash device to continue using this installation.') . '</p>',
|
||||
'<p>Please refresh the page to ensure you load your latest configuration</p>' => '<p>' . _('Please refresh the page to ensure you load your latest configuration') . '</p>',
|
||||
'<p>Register for Connect by signing in to your Unraid.net account</p>' => '<p>' . _('Register for Connect by signing in to your Unraid.net account') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key.</p><p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key') . '</p><p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key.</p><p>Your Unraid registration key is ineligible for replacement as it is blacklisted.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key') . '</p><p>' . _('Your Unraid registration key is ineligible for replacement as it is blacklisted.') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device.</p><p>You may also attempt to Purchase or Replace your key.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device') . '</p><p>' . _('You may also attempt to Purchase or Replace your key.') . '</p>',
|
||||
'<p>There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device. Please remove all key files, except the one you want to replace, from the /config directory on your USB Flash boot device.</p><p>Alternately you may purchase a license key for this USB flash device.</p><p>If you want to replace one of your license keys with a new key bound to this USB Flash device, please first remove all other key files first.</p>' => '<p>' . _('There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device.') . ' ' . _('Please remove all key files, except the one you want to replace, from the /config directory on your USB Flash boot device') . '</p><p>' . _('Alternately you may purchase a license key for this USB flash device') . '</p><p>' . _('If you want to replace one of your license keys with a new key bound to this USB Flash device, please first remove all other key files first.') . '</p>',
|
||||
'<p>There is a physical problem accessing your USB Flash boot device</p>' => '<p>' . _('There is a physical problem accessing your USB Flash boot device') . '</p>',
|
||||
'<p>There is a problem with your USB Flash device</p>' => '<p>' . _('There is a problem with your USB Flash device') . '</p>',
|
||||
'<p>This USB Flash boot device has been blacklisted. This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device.</p><p>A USB Flash device may also be blacklisted if we discover the serial number is not unique – this is common with USB card readers.</p>' => '<p>' . _('This USB Flash boot device has been blacklisted.') . ' ' . _('This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device.') . '</p><p>' . _('A USB Flash device may also be blacklisted if we discover the serial number is not unique – this is common with USB card readers.') . '</p>',
|
||||
'<p>This USB Flash device has an invalid GUID. Please try a different USB Flash device</p>' => '<p>' . _('This USB Flash device has an invalid GUID. Please try a different USB Flash device') . '</p>',
|
||||
'<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 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 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 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.'),
|
||||
'Attached Storage Devices' => _('Attached Storage Devices'),
|
||||
'Backing up...this may take a few minutes' => _('Backing up...this may take a few minutes'),
|
||||
'Basic' => _('Basic'),
|
||||
'Begin downgrade to {0}' => sprintf(_('Begin downgrade to %s'), '{0}'),
|
||||
'Beta' => _('Beta'),
|
||||
'Blacklisted USB Flash GUID' => _('Blacklisted USB Flash GUID'),
|
||||
'BLACKLISTED' => _('BLACKLISTED'),
|
||||
'Calculating trial expiration…' => _('Calculating trial expiration…'),
|
||||
'Callback redirect type not present or incorrect' => _('Callback redirect type not present or incorrect'),
|
||||
'Cancel' => _('Cancel'),
|
||||
'Cannot access your USB Flash boot device' => _('Cannot access your USB Flash boot device'),
|
||||
'Cannot validate Unraid Trial key' => _('Cannot validate Unraid Trial key'),
|
||||
'Check for OS Updates' => _('Check for OS Updates'),
|
||||
'check for OS updates' => _('check for OS updates'),
|
||||
'Check for Prereleases' => _('Check for Prereleases'),
|
||||
'Checking WAN IPs…' => _('Checking WAN IPs…'),
|
||||
'Checking...' => _('Checking...'),
|
||||
'Checkout the Connect Documentation' => _('Checkout the Connect Documentation'),
|
||||
'Click to close modal' => _('Click to close modal'),
|
||||
'Click to Copy LAN IP {0}' => sprintf(_('Click to copy LAN IP %s'), '{0}'),
|
||||
'Close Dropdown' => _('Close Dropdown'),
|
||||
'Close Modal' => _('Close Modal'),
|
||||
'Close' => _('Close'),
|
||||
'Configure Connect Features' => _('Configure Connect Features'),
|
||||
'Confirm and start update' => _('Confirm and start update'),
|
||||
'Connected' => _('Connected'),
|
||||
'Contact Support' => _('Contact Support'),
|
||||
'Copied' => _('Copied'),
|
||||
'Copy Key URL' => _('Copy Key URL'),
|
||||
'Copy your Key URL: {0}' => sprintf(_('Copy your Key URL: %s'), '{0}'),
|
||||
'Create Flash Backup' => _('Create Flash Backup'),
|
||||
'Current Version {0}' => sprintf(_('Current Version %s'), '{0}'),
|
||||
'Current Version: Unraid {0}' => sprintf(_('Current Version: Unraid %s'), '{0}'),
|
||||
'Customizable Dashboard Tiles' => _('Customizable Dashboard Tiles'),
|
||||
'day' => sprintf(_('%s day'), '{n}') . ' | ' . sprintf(_('%s days'), '{n}'),
|
||||
'Deep Linking' => _('Deep Linking'),
|
||||
'DNS issue, unable to resolve wanip4.unraid.net' => _('DNS issue, unable to resolve wanip4.unraid.net'),
|
||||
'Downgrade Unraid OS to {0}' => sprintf(_('Downgrade Unraid OS to %s'), '{0}'),
|
||||
'Downgrade Unraid OS' => _('Downgrade Unraid OS'),
|
||||
'Downgrades are only recommended if you\'re unable to solve a critical issue.' => _('Downgrades are only recommended if you\'re unable to solve a critical issue.'),
|
||||
'Download the Diagnostics zip then please open a bug report on our forums with a description of the issue along with your diagnostics.' => _('Download the Diagnostics zip then please open a bug report on our forums with a description of the issue along with your diagnostics.'),
|
||||
'Download unraid-api Logs' => _('Download unraid-api Logs'),
|
||||
'Dynamic Remote Access' => _('Dynamic Remote Access'),
|
||||
'Enhance your experience with Unraid Connect' => _('Enhance your experience with Unraid Connect'),
|
||||
'Enhance your Unraid experience with Connect' => _('Enhance your Unraid experience with Connect'),
|
||||
'Enhance your Unraid experience' => _('Enhance your Unraid experience'),
|
||||
'Error creatiing a trial key. Please try again later.' => _('Error creatiing a trial key. Please try again later.'),
|
||||
'Error' => _('Error'),
|
||||
'Expired {0}' => sprintf(_('Expired %s'), '{0}'),
|
||||
'Expired' => _('Expired'),
|
||||
'Expires at {0}' => sprintf(_('Expires at %s'), '{0}'),
|
||||
'Expires in {0}' => sprintf(_('Expires in %s'), '{0}'),
|
||||
'Extend Trial' => _('Extend Trial'),
|
||||
'Extending your free trial by 15 days' => _('Extending your free trial by 15 days'),
|
||||
'Extension Installed' => _('Extension Installed'),
|
||||
'Failed to {0} {1} Key' => sprintf(_('Failed to %1s %2s Key'), '{0}', '{1}'),
|
||||
'Failed to install key' => _('Failed to install key'),
|
||||
'Failed to update Connect account configuration' => _('Failed to update Connect account configuration'),
|
||||
'Fix Error' => _('Fix Error'),
|
||||
'Flash Backup is not available. Navigate to {0}/Main/Settings/Flash to try again then come back to this page.' => sprintf(_('Flash Backup is not available. Navigate to %s/Main/Settings/Flash to try again then come back to this page.'), '{0}'),
|
||||
'Flash GUID Error' => _('Flash GUID Error'),
|
||||
'Flash GUID required to check replacement status' => _('Flash GUID required to check replacement status'),
|
||||
'Flash GUID' => _('Flash GUID'),
|
||||
'Flash Product' => _('Flash Product'),
|
||||
'Flash Vendor' => _('Flash Vendor'),
|
||||
'Get an overview of your server\'s state, storage space, apps and VMs status, and more.' => _('Get an overview of your server\'s state, storage space, apps and VMs status, and more.'),
|
||||
'Get Started' => _('Get Started'),
|
||||
'Go to Connect plugin settings' => _('Go to Connect plugin settings'),
|
||||
'Go to Connect' => _('Go to Connect'),
|
||||
'Go to Management Access Now' => _('Go to Management Access Now'),
|
||||
'Go to Tools > Management Access to activate the Flash Backup feature and ensure your backup is up-to-date.' => _('Go to Tools > Management Access to activate the Flash Backup feature and ensure your backup is up-to-date.'),
|
||||
'Go to Tools > Management Access to ensure your backup is up-to-date.' => _('Go to Tools > Management Access to ensure your backup is up-to-date.'),
|
||||
'Go to Tools > Registration to fix' => _('Go to Tools > Registration to fix'),
|
||||
'Go to Tools > Update' => _('Go to Tools > Update'),
|
||||
'hour' => sprintf(_('%s hour'), '{n}') . ' | ' . sprintf(_('%s hours'), '{n}'),
|
||||
'I have made a Flash Backup' => _('I have made a Flash Backup'),
|
||||
'If you are asked to supply logs, please open a support request on our Contact Page and reply to the email message you receive with your logs attached.' => _('If you are asked to supply logs, please open a support request on our Contact Page and reply to the email message you receive with your logs attached.'),
|
||||
'Ignore this message if you are currently connected via Remote Access or VPN.' => _('Ignore this message if you are currently connected via Remote Access or VPN.'),
|
||||
'In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue.' => _('In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue.'),
|
||||
'Install Connect' => _('Install Connect'),
|
||||
'Install Recovered' => _('Install Recovered'),
|
||||
'Install Replaced' => _('Install Replaced'),
|
||||
'Install' => _('Install'),
|
||||
'Installed' => _('Installed'),
|
||||
'Installing Extended Trial' => _('Installing Extended Trial'),
|
||||
'Installing Extended' => _('Installing Extended'),
|
||||
'Installing Recovered' => _('Installing Recovered'),
|
||||
'Installing Replaced' => _('Installing Replaced'),
|
||||
'Installing' => _('Installing'),
|
||||
'Introducing Unraid Connect' => _('Introducing Unraid Connect'),
|
||||
'Invalid API Key Format' => _('Invalid API Key Format'),
|
||||
'Invalid API Key' => _('Invalid API Key'),
|
||||
'Invalid installation' => _('Invalid installation'),
|
||||
'Keyfile required to check replacement status' => _('Keyfile required to check replacement status'),
|
||||
'LAN IP {0}' => sprintf(_('LAN IP %s'), '{0}'),
|
||||
'LAN IP Copied' => _('LAN IP Copied'),
|
||||
'LAN IP' => _('LAN IP'),
|
||||
'Last checked: {0}' => sprintf(_('Last checked: %s'), '{0}'),
|
||||
'Learn more about the error' => _('Learn more about the error'),
|
||||
'Learn more and fix' => _('Learn more and fix'),
|
||||
'Learn More' => _('Learn More'),
|
||||
'Learn more' => _('Learn more'),
|
||||
'Let\'s Unleash your Hardware!' => _('Let\'s Unleash your Hardware!'),
|
||||
'License key actions' => _('License key actions'),
|
||||
'License key type' => _('License key type'),
|
||||
'License Management' => _('License Management'),
|
||||
'Loading' => _('Loading'),
|
||||
'Manage Unraid.net Account in new tab' => _('Manage Unraid.net Account in new tab'),
|
||||
'Manage Unraid.net Account' => _('Manage Unraid.net Account'),
|
||||
'Manage your license keys at any time via the My Keys section.' => _('Manage your license keys at any time via the My Keys section.'),
|
||||
'Manage Your Server Within Connect' => _('Manage Your Server Within Connect'),
|
||||
'minute' => sprintf(_('%s minute'), '{n}') . ' | ' . sprintf(_('%s minutes'), '{n}'),
|
||||
'Missing key file' => _('Missing key file'),
|
||||
'month' => sprintf(_('%s month'), '{n}') . ' | ' . sprintf(_('%s months'), '{n}'),
|
||||
'Multiple License Keys Present' => _('Multiple License Keys Present'),
|
||||
'Never ever be left without a backup of your config. If you need to change flash drives, generate a backup from Connect and be up and running in minutes.' => _('Never ever be left without a backup of your config.') . ' ' . _('If you need to change flash drives, generate a backup from Connect and be up and running in minutes.'),
|
||||
'New Version: {0}' => sprintf(_('New Version: %s'), '{0}'),
|
||||
'No downgrade available' => _('No downgrade available'),
|
||||
'No Flash' => _('No Flash'),
|
||||
'No Keyfile' => _('No Keyfile'),
|
||||
'No thanks' => _('No thanks'),
|
||||
'No USB flash configuration data' => _('No USB flash configuration data'),
|
||||
'On January 1st, 2023 SSL certificates for unraid.net were deprecated. You MUST provision a new SSL certificate to use our new myunraid.net domain. You can do this on the Settings > Management Access page.' => _('On January 1st, 2023 SSL certificates for unraid.net were deprecated. You MUST provision a new SSL certificate to use our new myunraid.net domain. You can do this on the Settings > Management Access page.'),
|
||||
'Online Flash Backup' => _('Online Flash Backup'),
|
||||
'Open a bug report' => _('Open a bug report'),
|
||||
'Open Dropdown' => _('Open Dropdown'),
|
||||
'Opens Connect in new tab' => _('Opens Connect in new tab'),
|
||||
'Original release date {0}' => sprintf(_('Original release date %s'), '{0}'),
|
||||
'Performing actions' => _('Performing actions'),
|
||||
'Please confirm the update details below' => _('Please confirm the update details below'),
|
||||
'Please fix any errors and try again.' => _('Please fix any errors and try again.'),
|
||||
'Please keep this window open while we perform some actions' => _('Please keep this window open while we perform some actions'),
|
||||
'Please keep this window open' => _('Please keep this window open'),
|
||||
'Please sign out then sign back in to refresh your API key.' => _('Please sign out then sign back in to refresh your API key.'),
|
||||
'Please wait while the page reloads to install your trial key' => _('Please wait while the page reloads to install your trial key'),
|
||||
'Plus more on the way' => _('Plus more on the way'),
|
||||
'Plus' => _('Plus'),
|
||||
'Pro' => _('Pro'),
|
||||
'Purchase Key' => _('Purchase Key'),
|
||||
'Purchase' => _('Purchase'),
|
||||
'Ready to Install Key' => _('Ready to Install Key'),
|
||||
'Ready to update Connect account configuration' => _('Ready to update Connect account configuration'),
|
||||
'Real-time Monitoring' => _('Real-time Monitoring'),
|
||||
'Reboot Now to Downgrade to {0}' => sprintf(_('Reboot Now to Downgrade to %s'), '{0}'),
|
||||
'Reboot Now to Downgrade' => _('Reboot Now to Downgrade'),
|
||||
'Reboot Now to Update to {0}' => sprintf(_('Reboot Now to Update to %s'), '{0}'),
|
||||
'Reboot Now to Update' => _('Reboot Now to Update'),
|
||||
'Reboot Required for Downgrade to {0}' => sprintf(_('Reboot Required for Downgrade to %s'), '{0}'),
|
||||
'Reboot Required for Downgrade' => _('Reboot Required for Downgrade'),
|
||||
'Reboot Required for Update to {0}' => sprintf(_('Reboot Required for Update to %s'), '{0}'),
|
||||
'Reboot Required for Update' => _('Reboot Required for Update'),
|
||||
'Rebooting will likely solve this.' => _('Rebooting will likely solve this.'),
|
||||
'Receive the latest and greatest for Unraid OS. Whether it new features, security patches, or bug fixes – keeping your server up-to-date ensures the best experience that Unraid has to offer.' => _('Receive the latest and greatest for Unraid OS.') . ' ' . _('Whether it new features, security patches, or bug fixes – keeping your server up-to-date ensures the best experience that Unraid has to offer.'),
|
||||
'Recover Key' => _('Recover Key'),
|
||||
'Recovered' => _('Recovered'),
|
||||
'Redeem Activation Code' => _('Redeem Activation Code'),
|
||||
'Registered on' => _('Registered on'),
|
||||
'Registered to' => _('Registered to'),
|
||||
'Registration key / USB Flash GUID mismatch' => _('Registration key / USB Flash GUID mismatch'),
|
||||
'Reload' => _('Reload'),
|
||||
'Remark: Unraid\'s WAN IPv4 {0} does not match your client\'s WAN IPv4 {1}.' => sprintf(_('Remark: Unraid\'s WAN IPv4 %1s does not match your client\'s WAN IPv4 %2s.'), '{0}', '{1}'),
|
||||
'Remark: your WAN IPv4 is {0}' => sprintf(_('Remark: your WAN IPv4 is %s'), '{0}'),
|
||||
'Replace Key' => _('Replace Key'),
|
||||
'Replaced' => _('Replaced'),
|
||||
'Restarting unraid-api…' => _('Restarting unraid-api…'),
|
||||
'second' => sprintf(_('%s second'), '{n}') . ' | ' . sprintf(_('%s seconds'), '{n}'),
|
||||
'Server Up Since {0}' => sprintf(_('Server Up Since %s'), '{0}'),
|
||||
'Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI. Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.' => _('Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI.') . ' ' . _('Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.'),
|
||||
'Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.' => _('Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.'),
|
||||
'Settings' => _('Settings'),
|
||||
'Sign In Failed' => _('Sign In Failed'),
|
||||
'Sign In requires the local unraid-api to be running' => _('Sign In requires the local unraid-api to be running'),
|
||||
'Sign In to utilize Unraid Connect' => _('Sign In to utilize Unraid Connect'),
|
||||
'Sign In to your Unraid.net account to get started' => _('Sign In to your Unraid.net account to get started'),
|
||||
'Sign In with Unraid.net Account' => _('Sign In with Unraid.net Account'),
|
||||
'Sign Out Failed' => _('Sign Out Failed'),
|
||||
'Sign Out of Unraid.net' => _('Sign Out of Unraid.net'),
|
||||
'Sign Out requires the local unraid-api to be running' => _('Sign Out requires the local unraid-api to be running'),
|
||||
'Signing in {0}…' => sprintf(_('Signing in %s…'), '{0}'),
|
||||
'Signing In' => _('Signing In'),
|
||||
'Signing out {0}…' => sprintf(_('Signing out %s…'), '{0}'),
|
||||
'Signing Out' => _('Signing Out'),
|
||||
'Something went wrong' => _('Something went wrong'),
|
||||
'SSL certificates for unraid.net deprecated' => _('SSL certificates for unraid.net deprecated'),
|
||||
'Stale Server' => _('Stale Server'),
|
||||
'Stale' => _('Stale'),
|
||||
'Start Free 30 Day Trial' => _('Start Free 30 Day Trial'),
|
||||
'Starting your free 30 day trial' => _('Starting your free 30 day trial'),
|
||||
'Success!' => _('Success!'),
|
||||
'Thank you for choosing Unraid OS!' => _('Thank you for choosing Unraid OS!'),
|
||||
'Thank you for installing Connect!' => _('Thank you for installing Connect!'),
|
||||
'Thank you for purchasing an Unraid {0} Key!' => sprintf(_('Thank you for purchasing an Unraid %s Key!'), '{0}'),
|
||||
'Thank you for upgrading to an Unraid {0} Key!' => sprintf(_('Thank you for upgrading to an Unraid %s Key!'), '{0}'),
|
||||
'The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.' => _('The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.'),
|
||||
'The logs may contain sensitive information so do not post them publicly.' => _('The logs may contain sensitive information so do not post them publicly.'),
|
||||
'The primary method of support for Unraid Connect is through our forums and Discord.' => _('The primary method of support for Unraid Connect is through our forums and Discord.'),
|
||||
'Then go to Tools > Registration to manually install it' => _('Then go to Tools > Registration to manually install it'),
|
||||
'This may indicate a complex network that will not work with this Remote Access solution.' => _('This may indicate a complex network that will not work with this Remote Access solution.'),
|
||||
'This update will require a reboot' => _('This update will require a reboot'),
|
||||
'Toggle on/off server accessibility with dynamic remote access. Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.' => _('Toggle on/off server accessibility with dynamic remote access.') . ' ' . _('Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.'),
|
||||
'Too Many Devices' => _('Too Many Devices'),
|
||||
'Transfer License to New Flash' => _('Transfer License to New Flash'),
|
||||
'Trial Expired, see options below' => _('Trial Expired, see options below'),
|
||||
'Trial Expired' => _('Trial Expired'),
|
||||
'Trial Key Created' => _('Trial Key Created'),
|
||||
'Trial Key Creation Failed' => _('Trial Key Creation Failed'),
|
||||
'Trial Key Expired {0}' => sprintf(_('Trial Key Expired %s'), '{0}'),
|
||||
'Trial Key Expired at {0}' => sprintf(_('Trial Key Expired at %s'), '{0}'),
|
||||
'Trial Key Expires at {0}' => sprintf(_('Trial Key Expires at %s'), '{0}'),
|
||||
'Trial Key Expires in {0}' => sprintf(_('Trial Key Expires in %s'), '{0}'),
|
||||
'Trial Requires Internet Connection' => _('Trial Requires Internet Connection'),
|
||||
'Trial' => _('Trial'),
|
||||
'Unable to check for OS updates' => _('Unable to check for OS updates'),
|
||||
'Unable to fetch client WAN IPv4' => _('Unable to fetch client WAN IPv4'),
|
||||
'Unable to open release notes' => _('Unable to open release notes'),
|
||||
'Unknown error' => _('Unknown error'),
|
||||
'unlimited' => _('unlimited'),
|
||||
'Unraid {0} Available' => sprintf(_('Unraid %s Available'), '{0}'),
|
||||
'Unraid {0} Update Available' => sprintf(_('Unraid %s Update Available'), '{0}'),
|
||||
'Unraid {0}' => sprintf(_('Unraid %s'), '{0}'),
|
||||
'Unraid Connect Error' => _('Unraid Connect Error'),
|
||||
'Unraid Connect Forums' => _('Unraid Connect Forums'),
|
||||
'Unraid Connect Install Failed' => _('Unraid Connect Install Failed'),
|
||||
'Unraid Contact Page' => _('Unraid Contact Page'),
|
||||
'Unraid Discord' => _('Unraid Discord'),
|
||||
'Unraid logo animating with a wave like effect' => _('Unraid logo animating with a wave like effect'),
|
||||
'Unraid OS {0} Released' => sprintf(_('Unraid OS %s Released'), '{0}'),
|
||||
'Unraid OS {0} Update Available' => sprintf(_('Unraid OS %s Update Available'), '{0}'),
|
||||
'Unraid OS Update Available' => _('Unraid OS Update Available'),
|
||||
'unraid-api is offline' => _('unraid-api is offline'),
|
||||
'Up-to-date' => _('Up-to-date'),
|
||||
'Update Available' => _('Update Available'),
|
||||
'Update Unraid OS confirmation required' => _('Update Unraid OS confirmation required'),
|
||||
'Update Unraid OS' => _('Update Unraid OS'),
|
||||
'Updating 3rd party drivers' => _('Updating 3rd party drivers'),
|
||||
'Upgrade Key' => _('Upgrade Key'),
|
||||
'Upgrade' => _('Upgrade'),
|
||||
'Uptime {0}' => sprintf(_('Uptime %s'), '{0}'),
|
||||
'USB Flash device error' => _('USB Flash device error'),
|
||||
'USB Flash has no serial number' => _('USB Flash has no serial number'),
|
||||
'Version available for restore {0}' => sprintf(_('Version available for restore %s'), '{0}'),
|
||||
'Version: {0}' => sprintf(_('Version: %s'), '{0}'),
|
||||
'View Available Updates' => _('View Available Updates'),
|
||||
'View Changelog & Update' => _('View Changelog & Update'),
|
||||
'View Changelog for {0}' => sprintf(_('View Changelog for %s'), '{0}'),
|
||||
'View Changelog' => _('View Changelog'),
|
||||
'View release notes' => _('View release notes'),
|
||||
'We recommend backing up your USB Flash Boot Device before starting the update.' => _('We recommend backing up your USB Flash Boot Device before starting the update.'),
|
||||
'year' => sprintf(_('%s year'), '{n}') . ' | ' . sprintf(_('%s years'), '{n}'),
|
||||
'You can also manually create a new backup by clicking the Create Flash Backup button.' => _('You can also manually create a new backup by clicking the Create Flash Backup button.'),
|
||||
'You can manually create a backup by clicking the Create Flash Backup button.' => _('You can manually create a backup by clicking the Create Flash Backup button.'),
|
||||
'You have already activated the Flash Backup feature via the Unraid Connect plugin.' => _('You have already activated the Flash Backup feature via the Unraid Connect plugin.'),
|
||||
'You have exceeded the number of devices allowed for your license. Please remove a device before adding another.' => _('You have exceeded the number of devices allowed for your license. Please remove a device before adding another.'),
|
||||
'You have not activated the Flash Backup feature via the Unraid Connect plugin.' => _('You have not activated the Flash Backup feature via the Unraid Connect plugin.'),
|
||||
'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 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!'),
|
||||
];
|
||||
}
|
||||
|
||||
public function getTranslations()
|
||||
{
|
||||
return $this->translations ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $urlEncode {bool}
|
||||
* @return string
|
||||
*/
|
||||
public function getTranslationsJson($urlEncode = false)
|
||||
{
|
||||
if ($urlEncode) {
|
||||
return rawurlencode(json_encode($this->getTranslations(), JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return json_encode($this->getTranslations(), JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
|
||||
{
|
||||
".nuxt/nuxt-custom-elements/entries/unraid-components.client.css": {
|
||||
"file": "_nuxt/unraid-components.client-fad7c220.css",
|
||||
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.css"
|
||||
},
|
||||
".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs": {
|
||||
"css": [
|
||||
"_nuxt/unraid-components.client-fad7c220.css"
|
||||
],
|
||||
"file": "_nuxt/unraid-components.client-cd1b3939.js",
|
||||
"isEntry": true,
|
||||
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
173
emhttp/plugins/dynamix.plugin.manager/Downgrade.page
Normal file
173
emhttp/plugins/dynamix.plugin.manager/Downgrade.page
Normal file
@@ -0,0 +1,173 @@
|
||||
Menu="About:20"
|
||||
Title="Downgrade OS"
|
||||
Icon="icon-update"
|
||||
Tag="upload"
|
||||
---
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
// Create an instance of the RebootDetails class
|
||||
$rebootDetails = new RebootDetails();
|
||||
/**
|
||||
* @note icon-update is rotated via CSS in myservers1.php
|
||||
*
|
||||
* If /boot/previous/bzroot exists, then the user has the option to downgrade to the previous version.
|
||||
* Parse the text file /boot/previous/changes.txt to get the version number of the previous version.
|
||||
* Then we move some files around and reboot.
|
||||
*/
|
||||
$restoreVersion = $restoreBranch = $restoreVersionReleaseDate = 'unknown';
|
||||
$restoreExists = file_exists('/boot/previous/bzroot');
|
||||
$restoreChangelogPath = '/boot/previous/changes.txt';
|
||||
|
||||
$serverNameEscaped = htmlspecialchars(str_replace(' ', '_', strtolower($var['NAME'])));
|
||||
|
||||
if (file_exists($restoreChangelogPath)) {
|
||||
exec("head -n4 $restoreChangelogPath", $rows);
|
||||
foreach ($rows as $row) {
|
||||
$i = stripos($row,'version');
|
||||
if ($i !== false) {
|
||||
[$restoreVersion, $restoreVersionReleaseDate] = explode(' ', trim(substr($row, $i+7)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
$restoreBranch = strpos($restoreVersion, 'rc') !== false
|
||||
? _('Next')
|
||||
: (strpos($restoreVersion, 'beta') !== false
|
||||
? _('Beta')
|
||||
: _('Stable'));
|
||||
}
|
||||
?>
|
||||
|
||||
<script>
|
||||
const nchan_diagnostics = new NchanSubscriber('/sub/diagnostics', { subscriber: 'websocket' });
|
||||
const reportUrl = new URL('https://forums.unraid.net/bug-reports/');
|
||||
let diagnosticsFile = '';
|
||||
|
||||
nchan_diagnostics.on('message', function(data) {
|
||||
if (data == '_DONE_') {
|
||||
nchan_diagnostics.stop();
|
||||
$('.sweet-alert').hide('fast').removeClass('nchan');
|
||||
swal.close();
|
||||
$('div.spinner').show('slow');
|
||||
location = diagnosticsFile;
|
||||
|
||||
setTimeout(() => {
|
||||
cleanupDiagnostics();
|
||||
reportAfterDiagnosticsDownload();
|
||||
}, 2000);
|
||||
} else if (data) {
|
||||
let box = $('pre#swaltext');
|
||||
box.html(box.html() + '<br>' + data).scrollTop(box[0].scrollHeight);
|
||||
}
|
||||
});
|
||||
|
||||
function downloadDiagnostics() {
|
||||
const tzoffset = (new Date()).getTimezoneOffset() * 60000; // offset in milliseconds
|
||||
const localISOTime = (new Date(Date.now() - tzoffset));
|
||||
const year = localISOTime.getFullYear();
|
||||
const month = String(localISOTime.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(localISOTime.getDate()).padStart(2, '0');
|
||||
const hours = String(localISOTime.getHours()).padStart(2, '0');
|
||||
const minutes = String(localISOTime.getMinutes()).padStart(2, '0');
|
||||
const dateOutput = `${year}${month}${day}_${hours}${minutes}`;
|
||||
const zipName = '<?=$serverNameEscaped?>-diagnostics-' + dateOutput + '.zip';
|
||||
|
||||
nchan_diagnostics.start();
|
||||
|
||||
$.post(
|
||||
'/webGui/include/Download.php',
|
||||
{
|
||||
cmd: 'diag',
|
||||
file: zipName,
|
||||
anonymize: '',
|
||||
},
|
||||
function(zip) {
|
||||
if (!zip) {
|
||||
return nchan_diagnostics.stop();
|
||||
}
|
||||
|
||||
diagnosticsFile = zip;
|
||||
swal({
|
||||
title: "_(Downloading)_...",
|
||||
text: "/boot/logs" + zip + "<hr><pre id='swaltext'></pre>",
|
||||
html: true,
|
||||
animation: 'none',
|
||||
showConfirmButton: false,
|
||||
});
|
||||
$('.sweet-alert').addClass('nchan');
|
||||
$('button.confirm').prop('disabled', true);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function reportAfterDiagnosticsDownload() {
|
||||
$('div.spinner').hide('fast');
|
||||
swal({
|
||||
title: "_(Open a bug report)_",
|
||||
text: "_(Create a bug report on our forums with a description of the issue along with your diagsnotics)_",
|
||||
html: true,
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "<?= _('Create Bug Report') ?>",
|
||||
cancelButtonText: "<?= _('Close') ?>",
|
||||
}, function(confirm) {
|
||||
if (!confirm) {
|
||||
return false;
|
||||
}
|
||||
window.open(reportUrl, '_blank');
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupDiagnostics() {
|
||||
if (document.hasFocus()) {
|
||||
return $.post('/webGui/include/Download.php', { cmd: 'delete', file: diagnosticsFile });
|
||||
}
|
||||
setTimeout(cleanupDiagnostics, 2000);
|
||||
}
|
||||
|
||||
function startDowngrade() {
|
||||
$('div.spinner').show('slow');
|
||||
|
||||
$.get(
|
||||
'/plugins/dynamix.plugin.manager/include/Downgrade.php',
|
||||
{
|
||||
version: '<?=$restoreVersion?>',
|
||||
},
|
||||
function() {
|
||||
refresh();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function confirmDowngrade() {
|
||||
swal({
|
||||
title: "_(Confirm Downgrade)_",
|
||||
text: "<?= $restoreVersion ?><br>_(A reboot will be required)_",
|
||||
html: true,
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "<?= _('Confirm') ?>",
|
||||
cancelButtonText: "<?= _('Cancel') ?>",
|
||||
}, function(confirm) {
|
||||
if (!confirm) {
|
||||
return false;
|
||||
}
|
||||
startDowngrade();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-downgrade-os
|
||||
reboot-version="<?= $rebootDetails->getRebootVersion() ?>"
|
||||
restore-version="<?= $restoreExists && $restoreVersion != 'unknown' ? $restoreVersion : '' ?>"
|
||||
restore-release-date="<?= $restoreExists && $restoreVersionReleaseDate != 'unknown' ? $restoreVersionReleaseDate : '' ?>"></unraid-downgrade-os>
|
||||
</unraid-i18n-host>
|
@@ -1,11 +1,10 @@
|
||||
Menu="About"
|
||||
Menu="About:10"
|
||||
Title="Update OS"
|
||||
Icon="icon-update"
|
||||
Tag="upload"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2022, Lime Technology
|
||||
* Copyright 2012-2022, Bergware International.
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -14,186 +13,38 @@ Tag="upload"
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
$rebootDetails = new RebootDetails();
|
||||
?>
|
||||
<?
|
||||
$version = $branch = $date = _('unknown');
|
||||
$bzroot = file_exists('/boot/previous/bzroot');
|
||||
$check = $notify['unraidos'] ? 0 : 1;
|
||||
$changes = '/boot/previous/changes.txt';
|
||||
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
|
||||
|
||||
if (file_exists($changes)) {
|
||||
exec("head -n4 $changes",$rows);
|
||||
foreach ($rows as $row) {
|
||||
$i = stripos($row,'version');
|
||||
if ($i !== false) {
|
||||
[$version,$date] = explode(' ',trim(substr($row,$i+7)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
$branch = strpos($version,'rc')!==false ? _('Next') : (strpos($version,'beta')!==false ? _('Beta') : _('Stable'));
|
||||
}
|
||||
$reboot = preg_match("/^\*\*(REBOOT REQUIRED|DOWNGRADE)/",@file_get_contents("$docroot/plugins/unRAIDServer/README.md",false,null,0,20));
|
||||
?>
|
||||
<style>
|
||||
ul,li{margin:0;padding-top:0;padding-bottom:0}
|
||||
pre.pre{margin:30px 0}
|
||||
pre>p{margin:0;padding:0}
|
||||
pre#swaltext{height:600px!important}
|
||||
@media (max-width:960px){pre#swaltext{height:400px!important}}
|
||||
@media (max-width:960px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
|
||||
@media (max-height:768px){pre#swaltext{height:400px!important}}
|
||||
@media (max-height:768px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
|
||||
input[value="_(Install)_"],input[value="_(Update)_"],input[value="_(Restore)_"]{margin:0}
|
||||
<?if ($themes1):?>
|
||||
span.vhshift{margin-top:13px!important}
|
||||
<?endif;?>
|
||||
</style>
|
||||
|
||||
<script>
|
||||
var diagnosticsFile = "";
|
||||
var nchan_diagnostics = new NchanSubscriber('/sub/diagnostics',{subscriber:'websocket'});
|
||||
var original = null;
|
||||
const args = {};
|
||||
|
||||
nchan_diagnostics.on('message', function(data) {
|
||||
if (data == '_DONE_') {
|
||||
nchan_diagnostics.stop();
|
||||
$('.sweet-alert').hide('fast').removeClass('nchan');
|
||||
swal.close();
|
||||
location = diagnosticsFile;
|
||||
setTimeout(cleanUp,4000);
|
||||
} else if (data) {
|
||||
let box = $('pre#swaltext');
|
||||
box.html(box.html()+'<br>'+data).scrollTop(box[0].scrollHeight);
|
||||
}
|
||||
});
|
||||
|
||||
function openInstall(cmd,title,plg) {
|
||||
if (cmd == null) {
|
||||
openPlugin(args.cmd,args.title,args.plg);
|
||||
return;
|
||||
}
|
||||
args.cmd = cmd;
|
||||
args.title = title;
|
||||
args.plg = plg;
|
||||
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{cmd:'alert'},function(data) {
|
||||
if (data==0) {
|
||||
// no alert message - proceed with update
|
||||
setTimeout(openInstall);
|
||||
} else {
|
||||
// show alert message and ask for confirmation
|
||||
openAlert("showchanges <?=$alerts?>","_(Alert Message)_",'openInstall');
|
||||
}
|
||||
});
|
||||
}
|
||||
function update_table(branch) {
|
||||
if (original) {
|
||||
if (branch != original) branch = '';
|
||||
} else {
|
||||
if (branch) original = branch;
|
||||
}
|
||||
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{system:true,branch:branch},function(data) {
|
||||
data = data.split('\0');
|
||||
updateInfo(data[0]);
|
||||
$('#os_table').trigger('update');
|
||||
});
|
||||
}
|
||||
function downgrade() {
|
||||
swal({title:"_(Diagnostics)_",text:"_(Please provide diagnostics when experiencing problems)_<br>_(Post these in the forums)_",html:true,type:'warning',showCancelButton:true,confirmButtonText:"<?=_('Diagnostics')?>",cancelButtonText:"<?=_('Restore')?>"},function(diag){
|
||||
if (diag) {
|
||||
// get diagnostics and then downgrade
|
||||
setTimeout(function(){diagnostics(zipfile());},250);
|
||||
} else {
|
||||
// downgrade immediately
|
||||
$.get('/plugins/dynamix.plugin.manager/include/Downgrade.php',{version:'<?=$version?>'},function(){refresh();});
|
||||
}
|
||||
});
|
||||
}
|
||||
function updateInfo(data) {
|
||||
var updates = data.split('\n');
|
||||
for (var n=0,update; update=updates[n]; n++) {
|
||||
var fields = update.split('\r');
|
||||
for (var i=0,field; field=fields[i]; i++) {
|
||||
var row = field.split('::');
|
||||
$('#'+row[0]).attr('data',row[1]).html(row[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function initlist() {
|
||||
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{init:true,system:true,check:<?=$check?>},function(data) {
|
||||
$('#os_list').html(data);
|
||||
<?if ($bzroot):?>
|
||||
$('#previous').show();
|
||||
<?endif;?>
|
||||
loadlist();
|
||||
});
|
||||
}
|
||||
function warning (data) {
|
||||
$('#change_branch').prop('disabled',true);
|
||||
return data.replace('green','orange').replace("<?=_('up-to-date')?>","<?=_('Reboot')?>").replace('checking','warning');
|
||||
}
|
||||
function loadlist(id,check) {
|
||||
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{system:true,audit:id,check:check||<?=$check?>},function(data) {
|
||||
var list = $('#os_list');
|
||||
if (id) {
|
||||
var cmd = id.split(':');
|
||||
var tr = 'tr#'+cmd[0].replace(/[\. _]/g,'');
|
||||
switch (cmd[1]) {
|
||||
case 'update' : data = warning(data);
|
||||
case 'return' : updateInfo(data); break;
|
||||
case 'install': list.find(tr).remove(); list.append(warning(data)); break;
|
||||
}
|
||||
} else {
|
||||
<?if (!$reboot):?>
|
||||
updateInfo(data);
|
||||
<?else:?>
|
||||
updateInfo(warning(data));
|
||||
<?endif;?>
|
||||
}
|
||||
$('#os_table').trigger('update');
|
||||
$('#checkos').prop('disabled',false);
|
||||
<?if ($reboot):?>
|
||||
$('#change_branch').prop('disabled',true);
|
||||
<?endif;?>
|
||||
});
|
||||
}
|
||||
function cleanUp() {
|
||||
function cleanUpFlashBackup(zip) {
|
||||
if (document.hasFocus()) {
|
||||
$.post('/webGui/include/Download.php',{cmd:'delete',file:diagnosticsFile},function(){
|
||||
$.get('/plugins/dynamix.plugin.manager/include/Downgrade.php',{version:'<?=$version?>'},function(){refresh();});
|
||||
});
|
||||
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_").prop('disabled',false);
|
||||
$('div.spinner').hide('slow');
|
||||
$('#pleaseWait').hide('slow');
|
||||
$.post('/webGui/include/Download.php',{cmd:'unlink',file:zip});
|
||||
} else {
|
||||
setTimeout(cleanUp,2000);
|
||||
setTimeout(function(){cleanUpFlashBackup(zip);},2000);
|
||||
}
|
||||
}
|
||||
function zipfile(){
|
||||
var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
|
||||
var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0,-1);
|
||||
return '<?=$zip?>-diagnostics-'+localISOTime.substr(0,16).replace(/[-:]/g,'').replace('T','-')+'.zip';
|
||||
}
|
||||
function diagnostics(file) {
|
||||
nchan_diagnostics.start();
|
||||
$.post('/webGui/include/Download.php',{cmd:'diag',file:file,anonymize:''},function(zip) {
|
||||
function flashBackup() {
|
||||
$('input[value="_(Flash backup)_"]').val('_(Creating Flash backup)_...').prop('disabled',true);
|
||||
$('div.spinner').show('slow');
|
||||
$('#pleaseWait').show('slow');
|
||||
$.post('/webGui/include/Download.php',{cmd:'backup'},function(zip) {
|
||||
if (zip) {
|
||||
diagnosticsFile = zip;
|
||||
swal({title:"_(Downloading)_...",text:"/boot/logs"+zip+"<hr><pre id='swaltext'></pre>",html:true,animation:'none',showConfirmButton:false});
|
||||
$('.sweet-alert').addClass('nchan');
|
||||
$('button.confirm').prop('disabled',true);
|
||||
location = '/'+zip;
|
||||
setTimeout(function(){cleanUpFlashBackup(zip);},6000);
|
||||
} else {
|
||||
nchan_diagnostics.stop();
|
||||
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_");
|
||||
$('div.spinner').hide('slow');
|
||||
$('#pleaseWait').hide('slow');
|
||||
swal({title:"_(Creation error)_",text:"_(Insufficient free disk space available)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
|
||||
}
|
||||
});
|
||||
}
|
||||
$(function() {
|
||||
initlist();
|
||||
$('.tabs').append("<span class='status vhshift'><input type='button' id='checkos' value=\"_(Check for Updates)_\" onclick='openPlugin(\"plugin checkos\",\"_(System Update Check)_\",\":return\")' disabled></span>");
|
||||
});
|
||||
</script>
|
||||
<table class='tablesorter plugins shift' id='os_table'>
|
||||
<thead><tr><th></th><th>_(Component)_</th><th>_(Author)_</th><th>_(Version)_</th><th>_(Status)_</th><th>_(Branch)_</th></tr></thead>
|
||||
<tbody id="os_list"><tr><td colspan="6"></td></tr></tbody>
|
||||
<?if ($bzroot):?>
|
||||
<tbody id="previous" style="display:none"><tr><td><img src="/plugins/unRAIDServer/images/unRAIDServer.png" class="list"></td><td><b>_(Unraid OS)_ (_(previous)_)</b></td><td>LimeTech</td><td><?=$version?></td><td><input type="button" value="_(Restore)_" onclick="downgrade()"></td><td><?=$branch?></td></tbody>
|
||||
<?endif;?>
|
||||
</table>
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-update-os reboot-version="<?= $rebootDetails->getRebootVersion() ?>"></unraid-update-os>
|
||||
</unraid-i18n-host>
|
||||
|
@@ -20,6 +20,9 @@ require_once "$docroot/webGui/include/Secure.php";
|
||||
$_SERVER['REQUEST_URI'] = 'plugins';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
$tmpdir="/boot/deletemedowngrade.".uniqid();
|
||||
mkdir($tmpdir);
|
||||
exec("mv -f /boot/bz* $tmpdir");
|
||||
exec("mv -f /boot/previous/* /boot");
|
||||
$version = unscript(_var($_GET,'version'));
|
||||
file_put_contents("$docroot/plugins/unRAIDServer/README.md","**"._('DOWNGRADE TO VERSION')." $version**");
|
||||
|
270
emhttp/plugins/dynamix.plugin.manager/include/UnraidCheck.php
Normal file
270
emhttp/plugins/dynamix.plugin.manager/include/UnraidCheck.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* Abstracting this code into a separate file allows us to use it in multiple places without duplicating code.
|
||||
* 1. unraidcheck script can call this
|
||||
* require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
* $unraidOsCheck = new UnraidOsCheck();
|
||||
* $unraidOsCheck->checkForUpdate();
|
||||
*
|
||||
* 2. Unraid webgui web components can GET this file with action params to get updates, ignore updates, etc.
|
||||
* - EX: Unraid webgui web components can check for updates via a GET request and receive a response with the json file directly
|
||||
* - this is useful for the UPC to check for updates and display a model based on the value
|
||||
* - `/plugins/dynamix.plugin.manager/scripts/unraidcheck.php?json=true`
|
||||
* - note the json=true query param to receive a json response
|
||||
*
|
||||
* @param action {'check'|'removeAllIgnored'|'removeIgnoredVersion'|'ignoreVersion'} - the action to perform
|
||||
* @param version {string} - the version to ignore or remove
|
||||
* @param json {string} - if set to true, will return the json response from the external request
|
||||
* @param altUrl {URL} - if set, will use this url instead of the default
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
class UnraidOsCheck
|
||||
{
|
||||
private const BASE_RELEASES_URL = 'https://releases.unraid.net/os';
|
||||
private const JSON_FILE_IGNORED = '/tmp/unraidcheck/ignored.json';
|
||||
private const JSON_FILE_IGNORED_KEY = 'updateOsIgnoredReleases';
|
||||
private const JSON_FILE_RESULT = '/tmp/unraidcheck/result.json';
|
||||
private const PLG_PATH = '/var/log/plugins/unRAIDServer.plg';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
|
||||
|
||||
if ($isGetRequest && $getHasAction) {
|
||||
$this->handleGetRequestWithActions();
|
||||
}
|
||||
}
|
||||
|
||||
private function handleGetRequestWithActions()
|
||||
{
|
||||
switch ($_GET['action']) {
|
||||
case 'check':
|
||||
$this->checkForUpdate();
|
||||
break;
|
||||
|
||||
case 'removeAllIgnored':
|
||||
$this->removeAllIgnored();
|
||||
break;
|
||||
|
||||
case 'removeIgnoredVersion':
|
||||
if (isset($_GET['version'])) {
|
||||
$this->removeIgnoredVersion($_GET['version']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ignoreVersion':
|
||||
if (isset($_GET['version'])) {
|
||||
$this->ignoreVersion($_GET['version']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->respondWithError(400, "Unhandled action");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function getUnraidOSCheckResult()
|
||||
{
|
||||
if (file_exists(self::JSON_FILE_RESULT)) {
|
||||
return $this->readJsonFile(self::JSON_FILE_RESULT);
|
||||
}
|
||||
}
|
||||
|
||||
public function getIgnoredReleases()
|
||||
{
|
||||
if (!file_exists(self::JSON_FILE_IGNORED)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$ignoredData = $this->readJsonFile(self::JSON_FILE_IGNORED);
|
||||
|
||||
if (is_array($ignoredData) && array_key_exists(self::JSON_FILE_IGNORED_KEY, $ignoredData)) {
|
||||
return $ignoredData[self::JSON_FILE_IGNORED_KEY];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/** @todo clean up this method to be more extensible */
|
||||
public function checkForUpdate()
|
||||
{
|
||||
// Multi-language support
|
||||
if (!function_exists('_')) {
|
||||
function _($text) {return $text;}
|
||||
}
|
||||
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
|
||||
$params = [];
|
||||
$params['branch'] = plugin('category', self::PLG_PATH, 'stable');
|
||||
$params['current_version'] = plugin('version', self::PLG_PATH) ?: _var($var,'version');
|
||||
if (_var($var,'regExp')) $params['update_exp'] = date('Y-m-d', _var($var,'regExp')*1);
|
||||
$defaultUrl = self::BASE_RELEASES_URL;
|
||||
// pass a param of altUrl to use the provided url instead of the default
|
||||
$parsedAltUrl = (array_key_exists('altUrl',$_GET) && $_GET['altUrl']) ? $_GET['altUrl'] : null;
|
||||
// if $parsedAltUrl pass to params
|
||||
if ($parsedAltUrl) $params['altUrl'] = $parsedAltUrl;
|
||||
|
||||
$urlbase = $parsedAltUrl ?? $defaultUrl;
|
||||
$url = $urlbase.'?'.http_build_query($params);
|
||||
|
||||
$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);
|
||||
}
|
||||
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);
|
||||
$responseMutated = json_decode($response, true);
|
||||
}
|
||||
|
||||
// add params that were used for debugging
|
||||
$responseMutated['params'] = $params;
|
||||
|
||||
// store locally for UPC to access
|
||||
$this->writeJsonFile(self::JSON_FILE_RESULT, $responseMutated);
|
||||
|
||||
// if we have a query param of json=true then just output the json
|
||||
if (array_key_exists('json',$_GET) && $_GET['json']) {
|
||||
header('Content-Type: application/json');
|
||||
echo $response;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// send notification if a newer version is available and not ignored
|
||||
$isNewerVersion = array_key_exists('isNewer',$responseMutated) ? $responseMutated['isNewer'] : false;
|
||||
$isReleaseIgnored = in_array($responseMutated['version'], $this->getIgnoredReleases());
|
||||
|
||||
if ($responseMutated && $isNewerVersion && !$isReleaseIgnored) {
|
||||
$output = _var($notify,'plugin');
|
||||
$server = strtoupper(_var($var,'NAME','server'));
|
||||
$newver = (array_key_exists('version',$responseMutated) && $responseMutated['version']) ? $responseMutated['version'] : 'unknown';
|
||||
$script = '/usr/local/emhttp/webGui/scripts/notify';
|
||||
$event = "System - Unraid [$newver]";
|
||||
$subject = "Notice [$server] - Version update $newver";
|
||||
$description = "A new version of Unraid is available";
|
||||
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
private function removeAllIgnored()
|
||||
{
|
||||
if (file_exists(self::JSON_FILE_IGNORED)) {
|
||||
$this->deleteJsonFile(self::JSON_FILE_IGNORED);
|
||||
$this->respondWithSuccess([]);
|
||||
}
|
||||
// fail silently if file doesn't exist
|
||||
}
|
||||
|
||||
private function removeIgnoredVersion($removeVersion)
|
||||
{
|
||||
if ($this->isValidSemVerFormat($removeVersion)) {
|
||||
if (file_exists(self::JSON_FILE_IGNORED)) {
|
||||
$existingData = $this->readJsonFile(self::JSON_FILE_IGNORED);
|
||||
|
||||
if (isset($existingData[self::JSON_FILE_IGNORED_KEY])) {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY] = array_diff($existingData[self::JSON_FILE_IGNORED_KEY], [$removeVersion]);
|
||||
$this->writeJsonFile(self::JSON_FILE_IGNORED, $existingData);
|
||||
$this->respondWithSuccess($existingData);
|
||||
} else {
|
||||
$this->respondWithError(400, "No versions to remove in the JSON file");
|
||||
}
|
||||
} else {
|
||||
$this->respondWithError(400, "No JSON file found");
|
||||
}
|
||||
} else {
|
||||
$this->respondWithError(400, "Invalid removeVersion format");
|
||||
}
|
||||
}
|
||||
|
||||
private function ignoreVersion($version)
|
||||
{
|
||||
if ($this->isValidSemVerFormat($version)) {
|
||||
$newData = [$this::JSON_FILE_IGNORED_KEY => [$version]];
|
||||
$existingData = file_exists(self::JSON_FILE_IGNORED) ? $this->readJsonFile(self::JSON_FILE_IGNORED) : [];
|
||||
|
||||
if (isset($existingData[self::JSON_FILE_IGNORED_KEY])) {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY][] = $version;
|
||||
} else {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY] = [$version];
|
||||
}
|
||||
|
||||
$this->writeJsonFile(self::JSON_FILE_IGNORED, $existingData);
|
||||
$this->respondWithSuccess($existingData);
|
||||
} else {
|
||||
$this->respondWithError(400, "Invalid version format");
|
||||
}
|
||||
}
|
||||
|
||||
private function isValidSemVerFormat($version)
|
||||
{
|
||||
return preg_match('/^\d+\.\d+(\.\d+)?(-.+)?$/', $version);
|
||||
}
|
||||
|
||||
private function readJsonFile($file)
|
||||
{
|
||||
return @json_decode(@file_get_contents($file), true) ?? [];
|
||||
}
|
||||
|
||||
private function writeJsonFile($file, $data)
|
||||
{
|
||||
if (!is_dir(dirname($file))) { // prevents errors when directory doesn't exist
|
||||
mkdir(dirname($file));
|
||||
}
|
||||
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
private function deleteJsonFile($file)
|
||||
{
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
private function respondWithError($statusCode, $message)
|
||||
{
|
||||
http_response_code($statusCode);
|
||||
echo $message;
|
||||
}
|
||||
|
||||
private function respondWithSuccess($data)
|
||||
{
|
||||
http_response_code(200);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data, JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate and handle the request for GET requests with actions – vars are duplicated here for multi-use of this file
|
||||
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
|
||||
if ($isGetRequest && $getHasAction) {
|
||||
new UnraidOsCheck();
|
||||
}
|
@@ -24,7 +24,7 @@ function newurl($url) {
|
||||
return str_replace($oldURL,$newURL,$url);
|
||||
}
|
||||
function searchLink(&$db,$url) {
|
||||
if ($url) for ($i = 0; $i < count($db); $i++) if ($db[$i]['PluginURL']==$url) return $db[$i]['Support'];
|
||||
if ($url) for ($i = 0; $i < count($db); $i++) if ( ($db[$i]['PluginURL']??null)==$url) return $db[$i]['Support']??null;
|
||||
}
|
||||
|
||||
$type = $argv[1]??''; // plugin or language
|
||||
|
@@ -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,
|
||||
@@ -16,6 +16,7 @@ $docroot = $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
|
||||
|
@@ -357,7 +357,7 @@ function plugin($method, $plugin_file, &$error) {
|
||||
if (isset($file->attributes()->Method)) {
|
||||
if (!in_array($method, explode(" ", $file->attributes()->Method))) continue;
|
||||
} elseif ($method != 'install') continue;
|
||||
$name = $file->attributes()->Name;
|
||||
$name = $file->attributes()->Name ?: '';
|
||||
// bergware - check Unraid version dependency (if present)
|
||||
$min = $file->attributes()->Min;
|
||||
if ($min && version_compare($unraid['version'],$min,'<')) {
|
||||
|
@@ -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,
|
||||
@@ -16,7 +16,7 @@ $docroot = $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
|
||||
|
@@ -23,7 +23,7 @@ $login_locale = _var($display,'locale');
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
$file = realpath($argv[1]??'');
|
||||
$valid = ['/var/tmp/','/tmp/plugins/'];
|
||||
$valid = ['/var/tmp/','/tmp/plugins/','/boot/previous'];
|
||||
$good = false;
|
||||
|
||||
foreach ($valid as $check) if (strncmp($file,$check,strlen($check))===0) $good = true;
|
||||
|
@@ -12,35 +12,8 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
// Multi-language support
|
||||
if (!function_exists('_')) {
|
||||
function _($text) {return $text;}
|
||||
}
|
||||
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
$var = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
|
||||
$script = "$docroot/webGui/scripts/notify";
|
||||
$server = strtoupper(_var($var,'NAME','server'));
|
||||
$output = _var($notify,'plugin');
|
||||
$builtin = ['unRAIDServer'];
|
||||
|
||||
foreach ($builtin as $name) {
|
||||
$plg = "$name.plg";
|
||||
plugin('check',$plg);
|
||||
$file = "/tmp/plugins/$plg";
|
||||
$old = plugin('version', "/var/log/plugins/$plg");
|
||||
$new = plugin('version', $file);
|
||||
|
||||
// silently suppress bad download of PLG file
|
||||
if (version_compare($new,$old,'>')) {
|
||||
exec("$script -e ".escapeshellarg("System - $name [$new]")." -s ".escapeshellarg("Notice [$server] - Version update $new")." -d ".escapeshellarg("A new version of $name is available")." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
?>
|
||||
$unraidOsCheck = new UnraidOsCheck();
|
||||
$unraidOsCheck->checkForUpdate();
|
||||
|
@@ -755,6 +755,15 @@ private static $encoding = 'UTF-8';
|
||||
$arrWhitelistGPUClassIDregex = '/^(0001|03)/';
|
||||
$arrWhitelistAudioClassIDregex = '/^(0403)/';
|
||||
|
||||
# "System peripheral [0880]" "Global unichip corp. [1ac1]" "Coral Edge Tpu [089a]" -pff "Global unichip corp. [1ac1]" "Coral Edge Tpu [089a]"
|
||||
# typeid productid
|
||||
# file is csv typeid:productid
|
||||
#
|
||||
if (is_file("/boot/config/VMPCIOverride.cfg")) {
|
||||
$arrWhiteListOverride = str_getcsv(file_get_contents("/boot/config/VMPCIOverride.cfg")) ;
|
||||
}
|
||||
$arrWhiteListOverride[] = "0880:089a" ;
|
||||
|
||||
$arrValidPCIDevices = [];
|
||||
|
||||
exec("lspci -m -nn 2>/dev/null", $arrAllPCIDevices);
|
||||
@@ -769,6 +778,9 @@ private static $encoding = 'UTF-8';
|
||||
$boolBlacklisted = true;
|
||||
}
|
||||
|
||||
$overrideCheck = "{$arrMatch['typeid']}:{$arrMatch['productid']}" ;
|
||||
if (in_array($overrideCheck,$arrWhiteListOverride) ) $boolBlacklisted = false;
|
||||
|
||||
$strClass = 'other';
|
||||
if (preg_match($arrWhitelistGPUClassIDregex, $arrMatch['typeid'])) {
|
||||
$strClass = 'vga';
|
||||
@@ -954,6 +966,16 @@ private static $encoding = 'UTF-8';
|
||||
return $arrValidMachineTypes;
|
||||
}
|
||||
|
||||
function ValidateMachineType($machinetype) {
|
||||
$machinetypes=getValidMachineTypes();
|
||||
$type = substr($machinetype,0,strpos($machinetype,'-',3));
|
||||
foreach($machinetypes as $machinetypekey => $machinedetails){
|
||||
$check_type = substr($machinetypekey,0,strlen($type));
|
||||
if ($check_type == $type) break;
|
||||
}
|
||||
return($machinetypekey) ;
|
||||
}
|
||||
|
||||
function getLatestMachineType($strType = 'i440fx') {
|
||||
$arrMachineTypes = getValidMachineTypes();
|
||||
|
||||
|
@@ -82,7 +82,7 @@
|
||||
|
||||
if (auto === 'true' || auto == '1') {
|
||||
auto = true;
|
||||
connect();
|
||||
setTimeout(connect, 3000);
|
||||
}
|
||||
|
||||
function spice_error(e)
|
||||
|
@@ -48,7 +48,7 @@
|
||||
'uuid' => $lv->domain_generate_uuid(),
|
||||
'clock' => 'localtime',
|
||||
'arch' => 'x86_64',
|
||||
'machine' => 'pc',
|
||||
'machine' => 'pc-i440fx',
|
||||
'mem' => 1024 * 1024,
|
||||
'maxmem' => 1024 * 1024,
|
||||
'password' => '',
|
||||
@@ -410,6 +410,12 @@
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
<?
|
||||
if (!isset($arrValidMachineTypes[$arrConfig['domain']['machine']])) {
|
||||
$arrConfig['domain']['machine'] = ValidateMachineType($arrConfig['domain']['machine']);
|
||||
}
|
||||
?>
|
||||
|
||||
<table>
|
||||
<tr class="advanced">
|
||||
<td>_(Machine)_:</td>
|
||||
@@ -1036,7 +1042,7 @@
|
||||
<tr class="<?if ($arrGPU['id'] != 'virtual') echo 'was';?>advanced vncmodel">
|
||||
<td>_(VM Console Video Driver)_:</td>
|
||||
<td>
|
||||
<select id="vncmodel" name="gpu[<?=$i?>][model]" class="narrow" title="_(video for VNC)_">
|
||||
<select id="vncmodel" name="gpu[<?=$i?>][model]" class="narrow" title="_(video for VM Console)_">
|
||||
<?mk_dropdown_options($arrValidVNCModels, $arrGPU['model']);?>
|
||||
</select>
|
||||
</td>
|
||||
@@ -1044,12 +1050,12 @@
|
||||
|
||||
<tr class="vncpassword">
|
||||
<td>_(VM Console Password)_:</td>
|
||||
<td><input type="password" name="domain[password]" autocomplete='new-password' value="<?=$arrGPU['password']?>" title="_(password for VNC)_" placeholder="_(password for VNC)_ (_(optional)_)" /></td>
|
||||
<td><input type="password" name="domain[password]" autocomplete='new-password' value="<?=$arrGPU['password']?>" title="_(password for VM Console)_" placeholder="_(password for VM Console)_ (_(optional)_)" /></td>
|
||||
</tr>
|
||||
<tr class="<?if ($arrGPU['id'] != 'virtual') echo 'was';?>advanced vnckeymap">
|
||||
<td>_(VM Console Keyboard)_:</td>
|
||||
<td>
|
||||
<select name="gpu[<?=$i?>][keymap]" title="_(keyboard for VNC)_">
|
||||
<select name="gpu[<?=$i?>][keymap]" title="_(keyboard for VM Console)_">
|
||||
<?mk_dropdown_options($arrValidKeyMaps, $arrGPU['keymap']);?>
|
||||
</select>
|
||||
</td>
|
||||
|
@@ -537,6 +537,9 @@ function formatWarning(val) {
|
||||
<? 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>
|
||||
|
@@ -27,6 +27,9 @@ $bgcolor = in_array($display['theme'],['white','azure']) ? '#f2f2f2' : '#1c1c
|
||||
$mode = ['Disabled','Hourly','Daily','Weekly','Monthly'];
|
||||
$days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
|
||||
|
||||
function disabled_if($condition) {
|
||||
if ($condition !== false) echo ' disabled';
|
||||
}
|
||||
function sanitize(&$val) {
|
||||
$data = explode('.',str_replace([' ',','],['','.'],$val));
|
||||
$last = array_pop($data);
|
||||
@@ -597,10 +600,10 @@ _(Spin down delay)_:
|
||||
_(File system status)_:
|
||||
: <?=_(_var($disk,'fsStatus'))?>
|
||||
|
||||
<?$disabled = ((_var($var,'fsState')=="Stopped" && _var($var,'mdState')=="SWAP_DSBL") || _var($var,'fsState')=="Started" || _var($disk,'fsStatus')=='Mounted') || _var($disk,'uuid') ? "disabled" : ""?>
|
||||
<?$fsTypeImmutable = ((_var($var,'fsState')=="Stopped" && _var($var,'mdState')=="SWAP_DSBL") || _var($var,'fsState')=="Started" || _var($disk,'fsStatus')=='Mounted') || _var($disk,'uuid')?>
|
||||
<?if (diskType('Data') || _var($disk,'slots',0)==1):?>
|
||||
_(File system type)_:
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="changeFsType()" <?=$disabled?>>
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="changeFsType()" <?=disabled_if($fsTypeImmutable)?>>
|
||||
<?=mk_option(_var($disk,'fsType'), "auto", _('auto'))?>
|
||||
<?=mk_option(_var($disk,'fsType'), "xfs", _('xfs'))?>
|
||||
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
|
||||
@@ -616,39 +619,38 @@ _(File system type)_:
|
||||
|
||||
<?elseif (_var($disk,'slots',0)>1):?>
|
||||
_(File system type)_:
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'devices',0)?>,0)" <?=$disabled?>>
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'devices',0)?>,0)" <?=disabled_if($fsTypeImmutable)?>>
|
||||
<?=mk_option(_var($disk,'fsType'), "auto", _('auto'))?>
|
||||
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
|
||||
<?=mk_option(_var($disk,'fsType'), "btrfs", _('btrfs'))?>
|
||||
<?=mk_option(_var($disk,'fsType'), "luks:zfs", _('zfs')." - "._('encrypted'))?>
|
||||
<?=mk_option(_var($disk,'fsType'), "luks:btrfs", _('btrfs')." - "._('encrypted'))?>
|
||||
</select>
|
||||
<select id="diskFsProfileBTRFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
|
||||
<select id="diskFsProfileBTRFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" <?=disabled_if($fsTypeImmutable)?>>
|
||||
<?=mk_option(_var($disk,'fsProfile'),"single", _('single'))?>
|
||||
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid0", _('raid0'))?>
|
||||
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid1", _('raid1'))?>
|
||||
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid1c3", _('raid1c3'))?>
|
||||
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid1c4", _('raid1c4'))?>
|
||||
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid10", _('raid10'))?>
|
||||
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid5", _('raid5'))?>
|
||||
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid6", _('raid6'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid0", _('raid0'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid1", _('raid1'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid1c3", _('raid1c3'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid1c4", _('raid1c4'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid10", _('raid10'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid5", _('raid5'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid6", _('raid6'))?>
|
||||
</select>
|
||||
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" onchange="selectDiskFsWidth(<?=_var($disk,'devices',0)?>,0)" <?=$disabled?>>
|
||||
<?if (_var($disk,'devices',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
|
||||
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
|
||||
<?if ((_var($disk,'devices',0)%2)==0 || (_var($disk,'devices',0)%3)==0 || (_var($disk,'devices',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
|
||||
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz1", _('raidz'))?>
|
||||
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raidz2", _('raidz2'))?>
|
||||
<?if (_var($disk,'devices',0)>=5) echo mk_option(_var($disk,'fsProfile'),"raidz3", _('raidz3'))?>
|
||||
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" onchange="selectDiskFsWidth(<?=_var($disk,'devices',0)?>,0)" <?=disabled_if($fsTypeImmutable)?>>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
|
||||
<?if ($fsTypeImmutable||(_var($disk,'devices',0)%2)==0 || (_var($disk,'devices',0)%3)==0 || (_var($disk,'devices',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz1", _('raidz'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raidz2", _('raidz2'))?>
|
||||
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=5) echo mk_option(_var($disk,'fsProfile'),"raidz3", _('raidz3'))?>
|
||||
</select>
|
||||
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
|
||||
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=disabled_if($fsTypeImmutable)?>>
|
||||
</select>
|
||||
<?endif;?>
|
||||
|
||||
<div markdown="1" id="compression" style="display:none">
|
||||
_(Compression)_:
|
||||
<?$disabled = _var($disk,'fsStatus')=='Mounted' ? "disabled" : ""?>
|
||||
: <select id="diskCompression" name="diskCompression.<?=_var($disk,'idx',0)?>" <?=$disabled?>>
|
||||
: <select id="diskCompression" name="diskCompression.<?=_var($disk,'idx',0)?>" <?=disabled_if(_var($disk,'fsStatus')=='Mounted')?>>
|
||||
<?=mk_option(_var($disk,'compression'), "off", _('Off'))?>
|
||||
<?=mk_option(_var($disk,'compression'), "on", _('On'))?>
|
||||
</select>
|
||||
@@ -658,8 +660,7 @@ _(Compression)_:
|
||||
|
||||
<div markdown="1" id="autotrim" style="display:none">
|
||||
_(Autotrim)_:
|
||||
<?$disabled = _var($disk,'fsStatus')=='Mounted' ? "disabled" : ""?>
|
||||
: <select id="diskAutotrim" name="diskAutotrim.<?=_var($disk,'idx',0)?>" <?=$disabled?>>
|
||||
: <select id="diskAutotrim" name="diskAutotrim.<?=_var($disk,'idx',0)?>" <?=disabled_if(_var($disk,'fsStatus')=='Mounted')?>>
|
||||
<?=mk_option(_var($disk,'autotrim'), "on", _('On'))?>
|
||||
<?=mk_option(_var($disk,'autotrim'), "off", _('Off'))?>
|
||||
</select>
|
||||
@@ -668,8 +669,7 @@ _(Autotrim)_:
|
||||
</div>
|
||||
<?if (isPool($name)):?>
|
||||
_(Enable user share assignment)_:
|
||||
<?$disabled = _var($var,'fsState')!="Stopped" ? "disabled" : ""?>
|
||||
: <select id="shareEnabled" name="diskShareEnabled.<?=_var($disk,'idx',0)?>" onchange="freeSpace(this.value)" <?=$disabled?>>
|
||||
: <select id="shareEnabled" name="diskShareEnabled.<?=_var($disk,'idx',0)?>" onchange="freeSpace(this.value)" <?=disabled_if(_var($var,'fsState')!="Stopped")?>>
|
||||
<?=mk_option(_var($disk,'shareEnabled'), "yes", _('Yes'))?>
|
||||
<?=mk_option(_var($disk,'shareEnabled'), "no", _('No'))?>
|
||||
</select>
|
||||
|
@@ -92,9 +92,31 @@ refresh(); // automatically include new ethernet ports
|
||||
Array.prototype.same = function(){return this.sort().filter(function(v,i,o){return i&&v===o[i-1]?v:0;}).length;}
|
||||
|
||||
function prepareSettings(form) {
|
||||
var metrics = [];
|
||||
var metrics6 = [];
|
||||
var bondnics = [], brnics = [];
|
||||
for (var i=0,nic; nic=form.BONDNICS.options[i]; i++) {
|
||||
if (nic.selected) {
|
||||
bondnics.push(nic.value);
|
||||
nic.selected = false;
|
||||
}
|
||||
}
|
||||
nic = form.BONDNICS.options[0];
|
||||
nic.value = bondnics.join(',');
|
||||
nic.selected = true;
|
||||
nic.disabled = false;
|
||||
for (var i=0,nic; nic=form.BRNICS.options[i]; i++) {
|
||||
if (nic.selected) {
|
||||
brnics.push(nic.value);
|
||||
nic.selected = false;
|
||||
}
|
||||
}
|
||||
nic = form.BRNICS.options[0];
|
||||
nic.value = form.BONDING.value=='yes' ? form.BONDNAME.value : brnics.join(',');
|
||||
nic.selected = true;
|
||||
nic.disabled = false;
|
||||
if (brnics.length>1) form.BRSTP.value = 'yes';
|
||||
if ($(form).find('input[name="#arg[1]"]').val()=='none') return true;
|
||||
|
||||
var metrics = [], metrics6 = [];
|
||||
$(form).find('input[name^="METRIC:"]').each(function(){if($(this).val()>0) metrics.push($(this).val());});
|
||||
$(form).find('input[name^="METRIC6:"]').each(function(){if($(this).val()>0) metrics6.push($(this).val());});
|
||||
if (metrics.same() || metrics6.same()) {
|
||||
@@ -123,31 +145,6 @@ function prepareSettings(form) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var member = '';
|
||||
for (var i=0,item; item=form.BONDNICS.options[i]; i++) {
|
||||
if (item.selected) {
|
||||
if (member.length) member += ',';
|
||||
member += item.value;
|
||||
item.selected = false;
|
||||
}
|
||||
}
|
||||
item = form.BONDNICS.options[0];
|
||||
item.value = member;
|
||||
item.selected = true;
|
||||
item.disabled = false;
|
||||
var member = '';
|
||||
for (var i=0,item; item=form.BRNICS.options[i]; i++) {
|
||||
if (item.selected) {
|
||||
if (member.length) member += ',';
|
||||
member += item.value;
|
||||
item.selected = false;
|
||||
}
|
||||
}
|
||||
item = form.BRNICS.options[0];
|
||||
item.value = form.BONDING.value=='yes' ? form.BONDNAME.value : member;
|
||||
item.selected = true;
|
||||
item.disabled = false;
|
||||
if (member.indexOf(',')>0) form.BRSTP.value = 'yes';
|
||||
$(form).find('select[name^="PROTOCOL:"]').each(function() {
|
||||
var protocol = $(this).val() || 'ipv4';
|
||||
var i = $(this).attr('name').split(':')[1];
|
||||
|
@@ -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,
|
||||
@@ -56,7 +56,7 @@ $nginx = @parse_ini_file('/var/local/emhttp/nginx.ini') ?: [];
|
||||
$addr = _var($nginx,'NGINX_LANIP') ?: _var($nginx,'NGINX_LANIP6');
|
||||
$keyfile = empty(_var($var,'regFILE')) ? false : @file_get_contents(_var($var,'regFILE'));
|
||||
$cert2Issuer = '';
|
||||
$isLEcert = false;
|
||||
$isWildcardCert = false;
|
||||
if ($keyfile !== false) $keyfile = base64_encode($keyfile);
|
||||
|
||||
// self-signed or user-provided cert
|
||||
@@ -75,32 +75,27 @@ 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) {
|
||||
$cert2Subject = exec("/usr/bin/openssl x509 -in $cert2File -noout -subject -nameopt multiline 2>/dev/null|sed -n 's/ *commonName *= //p'");
|
||||
$cert2Issuer = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Issuer: //p'");
|
||||
$cert2Expires = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Not After : //p'");
|
||||
$isLegacyCert = preg_match('/.*\.unraid\.net$/', $cert2Subject);
|
||||
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', $cert2Subject);
|
||||
$isLEcert = $isLegacyCert || $isWildcardCert;
|
||||
$subject2URL = $cert2Subject;
|
||||
$dnsValid = false;
|
||||
$dnsRebindingProtection = false;
|
||||
if ($isWildcardCert) {
|
||||
if (!$addr)
|
||||
// if eth0 doesn't have an IP address, then show noip.hash.myunraid.net as a placeholder url
|
||||
$subject2URL = str_replace("*", 'noip', $subject2URL);
|
||||
elseif (strpos($addr, ":") === false)
|
||||
$subject2URL = str_replace("*", str_replace(".", "-", $addr), $subject2URL);
|
||||
else
|
||||
$subject2URL = str_replace("*", str_replace(":", "-", $addr), $subject2URL);
|
||||
}
|
||||
if ($isLEcert) {
|
||||
exec("openssl x509 -checkend 2592000 -noout -in $cert2File 2>/dev/null", $arrout, $retval_expired);
|
||||
if (!$addr) {
|
||||
// if eth0 doesn't have an IP address, then show noip.hash.myunraid.net as a placeholder url
|
||||
$subject2URL = str_replace("*", 'noip', $subject2URL);
|
||||
$dnsValid = false;
|
||||
$dnsRebindingProtection = false;
|
||||
} elseif (strpos($addr, ":") === false) {
|
||||
// eth0 is IPv4
|
||||
$subject2URL = str_replace("*", str_replace(".", "-", $addr), $subject2URL);
|
||||
$rebindtest_ip = exec("host -4 -t A rebindtest4.myunraid.net 2>/dev/null|awk '{print \$4}'");
|
||||
$dnsRebindingProtection = ($rebindtest_ip != "192.168.42.42");
|
||||
if (!$dnsRebindingProtection) {
|
||||
@@ -108,6 +103,8 @@ if ($cert2Present) {
|
||||
$dnsValid = $cert_ip==$addr;
|
||||
}
|
||||
} else {
|
||||
// eth0 is IPv6
|
||||
$subject2URL = str_replace("*", str_replace(":", "-", $addr), $subject2URL);
|
||||
$rebindtest_ip = exec("host -6 -t AAAA rebindtest6.myunraid.net 2>/dev/null|awk '{print \$4}'");
|
||||
// more: restore this after TTL expires
|
||||
// $dnsRebindingProtection = ($rebindtest_ip != "fd42::42");
|
||||
@@ -120,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}/";
|
||||
@@ -166,14 +163,11 @@ case 'auto': // aka strict
|
||||
}
|
||||
|
||||
$cert_time_format = $display['date'].($display['date']!='%c' ? ', '.str_replace(['%M','%R'],['%M:%S','%R:%S'],$display['time']):'');
|
||||
$provisionlabel = $isLEcert ? _('Renew') : _('Provision');
|
||||
$disabled_provision = $keyfile===false || ($isLEcert && $retval_expired===0) || !$addr ? 'disabled' : '';
|
||||
$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_upgrade = !$addr ? 'disabled' : '';
|
||||
$disabled_updatedns = $keyfile!==false && $isLEcert ? '' : 'disabled';
|
||||
$disabled_delete = $cert2Present && $var['USE_SSL']!='auto' ? '' : 'disabled';
|
||||
$disabled_auto = $isLEcert && !$dnsRebindingProtection && $dnsValid ? '' : 'disabled';
|
||||
$upgradelabel = _('Upgrade Cert');
|
||||
$disabled_auto = $isWildcardCert && !$dnsRebindingProtection && $dnsValid ? '' : 'disabled';
|
||||
|
||||
// Get ports in use
|
||||
$portsInUse = [];
|
||||
@@ -200,23 +194,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 = [];
|
||||
@@ -370,12 +347,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:
|
||||
@@ -442,12 +417,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?>
|
||||
|
||||
<?if ($cert2Present && $isLegacyCert):?>
|
||||
|
||||
: <button type="submit" name="changePorts" value="Upgrade" <?=$disabled_upgrade?>><?=$upgradelabel?></button>
|
||||
<?endif;?>
|
||||
: <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:
|
||||
|
||||
|
@@ -225,7 +225,6 @@ function readSMB() {
|
||||
$.get('/webGui/include/ProtocolData.php',{protocol:'smb',name:name},function(json) {
|
||||
var data = $.parseJSON(json);
|
||||
form.shareExport.value = data.export;
|
||||
form.shareFruit.value = data.fruit;
|
||||
form.shareSecurity.value = data.security;
|
||||
});
|
||||
$(form).find('select').trigger('change');
|
||||
@@ -245,7 +244,6 @@ function writeSMB(data,n,i) {
|
||||
data[i] = {};
|
||||
data[i]['shareName'] = $(this).val();
|
||||
data[i]['shareExport'] = '<?=addslashes(htmlspecialchars($sec[$name]['export']))?>';
|
||||
data[i]['shareFruit'] = '<?=addslashes(htmlspecialchars($sec[$name]['fruit']))?>';
|
||||
data[i]['shareSecurity'] = '<?=addslashes(htmlspecialchars($sec[$name]['security']))?>';
|
||||
data[i]['changeShareSecurity'] = 'Apply';
|
||||
i++;
|
||||
|
@@ -158,7 +158,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>" ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,19 +18,28 @@ Tag="list"
|
||||
<?
|
||||
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
|
||||
$log = '/var/log/syslog';
|
||||
$prev = '/boot/logs/syslog-previous';
|
||||
$cfg = '/boot/config/rsyslog.cfg';
|
||||
$max = 5000;
|
||||
$select = [];
|
||||
$logs = [];
|
||||
if (file_exists($cfg)) {
|
||||
$syslog = parse_ini_file($cfg);
|
||||
if (isset($syslog['local_server']) && isset($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
|
||||
if (!empty($syslog['local_server']) && !empty($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
|
||||
natsort($logs);
|
||||
$select[] = "<select onchange='showLog(this.value)'>";
|
||||
$select[] = mk_option(1,$log,'syslog');
|
||||
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
|
||||
$select[] = "</select>";
|
||||
}
|
||||
}
|
||||
if (file_exists($prev)) {
|
||||
// add syslog-previous to front of logs array
|
||||
array_unshift($logs, $prev);
|
||||
}
|
||||
if (count($logs)) {
|
||||
// add syslog to front of logs array
|
||||
array_unshift($logs, $log);
|
||||
$select[] = "<select onchange='showLog(this.value)'>";
|
||||
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
|
||||
$select[] = "</select>";
|
||||
}
|
||||
$select = implode($select);
|
||||
?>
|
||||
<style>
|
||||
|
@@ -166,6 +166,14 @@ _(Mirror syslog to flash)_:
|
||||
|
||||
:syslog_mirror_flash_help:
|
||||
|
||||
_(Copy syslog to flash on shutdown)_:
|
||||
: <select name="syslog_shutdown">
|
||||
<?=mk_option(_var($syslog,'syslog_shutdown'), "", _("Yes"))?>
|
||||
<?=mk_option(_var($syslog,'syslog_shutdown'), "1", _("No"))?>
|
||||
</select>
|
||||
|
||||
:syslog_shutdown_flash_help:
|
||||
|
||||
|
||||
: <input type="button" value="_(Apply)_" onclick='validatePort(this.form)' disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
</form>
|
||||
|
@@ -138,21 +138,22 @@ $server = ipaddr($ethX);
|
||||
$dnsserver = _var($$ethX,'DNS_SERVER1');
|
||||
|
||||
$link = iflink($ethX);
|
||||
$vhost = str_replace(['eth','br','bond'],'vhost',$link);
|
||||
$postUp0 = "$script add $link WireGuard-<wg> $server <port> <port> udp";
|
||||
$postUp1 = "logger -t wireguard 'Tunnel WireGuard-<wg> started';$services";
|
||||
$postUp2 = "iptables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE";
|
||||
$postUp2 = "iptables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE;iptables -t nat -A POSTROUTING -s <source> -o $vhost -j MASQUERADE";
|
||||
$postUp3 = "iptables -N WIREGUARD_DROP_<WG>;iptables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
|
||||
$postUpX = "iptables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
|
||||
$postUpZ = "iptables -A WIREGUARD_DROP_<WG> -s <source> -j ACCEPT;iptables -A WIREGUARD_DROP_<WG> -j RETURN";
|
||||
$postUp26 = "ip6tables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE";
|
||||
$postUp26 = "ip6tables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE;ip6tables -t nat -A POSTROUTING -s <source> -o $vhost -j MASQUERADE";
|
||||
$postUp36 = "ip6tables -N WIREGUARD_DROP_<WG>;ip6tables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
|
||||
$postUpX6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
|
||||
$postUpZ6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -j ACCEPT;ip6tables -A WIREGUARD_DROP_<WG> -j RETURN";
|
||||
$postDown0 = "$script del $link <port> udp";
|
||||
$postDown1 = "logger -t wireguard 'Tunnel WireGuard-<wg> stopped';$services";
|
||||
$postDown2 = "iptables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE";
|
||||
$postDown2 = "iptables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE;iptables -t nat -D POSTROUTING -s <source> -o $vhost -j MASQUERADE";
|
||||
$postDown3 = "iptables -F WIREGUARD_DROP_<WG>;iptables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>;iptables -X WIREGUARD_DROP_<WG>";
|
||||
$postDown26= "ip6tables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE";
|
||||
$postDown26= "ip6tables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE;ip6tables -t nat -D POSTROUTING -s <source> -o $vhost -j MASQUERADE";
|
||||
$postDown36= "ip6tables -F WIREGUARD_DROP_<WG>;ip6tables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>;ip6tables -X WIREGUARD_DROP_<WG>";
|
||||
|
||||
$tld = @file_get_contents("$docroot/webGui/include/tld.key")?:'';
|
||||
@@ -252,7 +253,7 @@ refresh();
|
||||
Number.prototype.long2ip = function(){return [this>>>24,this>>>16&255,this>>>8&255,this&255].join('.');}
|
||||
String.prototype.ip2long = function(){var ip=this.split('.');return (ip[0]<<24)+(ip[1]<<16)+(ip[2]<<8)+(ip[3]*1);}
|
||||
String.prototype.desc = function(){return this.substr(this.lastIndexOf('/'));}
|
||||
String.prototype.patch = function(s,t){return t?this.replace(/<source>/,s).replace(/<target>/,t):this.replace(/<source>/,s);}
|
||||
String.prototype.patch = function(s,t){return t?this.replace(/<source>/g,s).replace(/<target>/,t):this.replace(/<source>/g,s);}
|
||||
Array.prototype.bind = function(w){return (this.join(';')).replace(/<WG>/g,w).replace(/,/g,';');}
|
||||
|
||||
var xml = $.cookie('upnp')||'<?=@file_get_contents('/var/tmp/upnp')?>';
|
||||
|
BIN
emhttp/plugins/dynamix/icons/ntfy.sh.png
Normal file
BIN
emhttp/plugins/dynamix/icons/ntfy.sh.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 534 B |
@@ -9,8 +9,8 @@ if (!empty($_COOKIE['unraid_'.md5($server_name)])) {
|
||||
|
||||
// Check if the user is already logged in
|
||||
if ($_SESSION && !empty($_SESSION['unraid_user'])) {
|
||||
// If so redirect them to the start page
|
||||
header("Location: /".$var['START_PAGE']);
|
||||
// Redirect the user to the start page
|
||||
header("Location: /".$start_page);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -219,7 +219,7 @@ if (!empty($username) && !empty($password)) {
|
||||
exec("logger -t webGUI ".escapeshellarg("Successful login user {$username} from {$remote_addr}"));
|
||||
|
||||
// Redirect the user to the start page
|
||||
header("Location: /".$var['START_PAGE']);
|
||||
header("Location: /".$start_page);
|
||||
exit;
|
||||
} catch (Exception $exception) {
|
||||
// Set error message
|
||||
|
@@ -30,7 +30,8 @@ if (!empty($_POST['password']) && !empty($_POST['confirmPassword'])) {
|
||||
session_regenerate_id(true);
|
||||
session_write_close();
|
||||
|
||||
header("Location: /".$var['START_PAGE']);
|
||||
// Redirect the user to the start page
|
||||
header("Location: /".$start_page);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
@@ -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,
|
||||
@@ -383,6 +383,12 @@ function openDone(data) {
|
||||
if (data == '_DONE_') {
|
||||
$('div.spinner.fixed').hide();
|
||||
$('button.confirm').text("<?=_('Done')?>").prop('disabled',false).show();
|
||||
if ( typeof ca_done_override !== 'undefined' ) {
|
||||
if (ca_done_override == true) {
|
||||
$("button.confirm").trigger("click");
|
||||
ca_done_override = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -595,7 +601,7 @@ $.ajaxPrefilter(function(s, orig, xhr){
|
||||
<div id="header" class="<?=$display['banner']?>">
|
||||
<div class="logo">
|
||||
<a href="https://unraid.net" target="_blank"><?readfile("$docroot/webGui/images/UN-logotype-gradient.svg")?></a>
|
||||
<?=_('Version')?>: <?=_var($var,'version','?')?><?=$notes?>
|
||||
<unraid-i18n-host><unraid-header-os-version></unraid-header-os-version></unraid-i18n-host>
|
||||
</div>
|
||||
<?include "$docroot/plugins/dynamix.my.servers/include/myservers2.php"?>
|
||||
</div>
|
||||
@@ -751,7 +757,7 @@ default:
|
||||
echo "<span class='green strong'><i class='fa fa-play-circle'></i> "._('Array Started')."</span>$progress"; break;
|
||||
}
|
||||
echo "</span></span><span id='countdown'></span><span id='user-notice' class='red-text'></span>";
|
||||
echo "<span id='copyright'>Unraid® webGui ©2023, Lime Technology, Inc.";
|
||||
echo "<span id='copyright'>Unraid® webGui ©2024, Lime Technology, Inc.";
|
||||
echo " <a href='https://docs.unraid.net/category/manual' target='_blank' title=\""._('Online manual')."\"><i class='fa fa-book'></i> "._('manual')."</a>";
|
||||
echo "</span></div>";
|
||||
?>
|
||||
@@ -980,14 +986,6 @@ $(function() {
|
||||
<?if ($safemode):?>
|
||||
showNotice("<?=_('System running in')?> <b><?=('safe mode')?></b>");
|
||||
<?else:?>
|
||||
<?$readme = @file_get_contents("$docroot/plugins/unRAIDServer/README.md",false,null,0,20)?:''?>
|
||||
<?if (strpos($readme,'REBOOT REQUIRED')!==false):?>
|
||||
showUpgrade("<b><?=_('Reboot Now')?></b> <?=_('to upgrade Unraid OS')?>",true);
|
||||
<?elseif (strpos($readme,'DOWNGRADE')!==false):?>
|
||||
showUpgrade("<b><?=_('Reboot Now')?></b> <?=_('to downgrade Unraid OS')?>",true);
|
||||
<?elseif ($version = plugin_update_available('unRAIDServer',true)):?>
|
||||
showUpgrade("Unraid OS v<?=$version?> <?=_('is available')?>. <?if (is_file('/tmp/plugins/unRAIDServer.txt')):?><span class='fa fa-info-circle fa-fw big blue-text' onclick='showUpgradeChanges()' title=\"<?=_('Release Notes')?>\"></span> <?endif;?><a><?=_('Update Now')?></a>");
|
||||
<?endif;?>
|
||||
<?if (!_var($notify,'system')):?>
|
||||
addBannerWarning("<?=_('System notifications are')?> <b><?=_('disabled')?></b>. <?=_('Click')?> <a href='/Settings/Notifications'><?=_('here')?></a> <?=_('to change notification settings')?>.",true,true);
|
||||
<?endif;?>
|
||||
|
@@ -88,7 +88,7 @@ foreach ($disks as $name => $disk) {
|
||||
} else $luks = "";
|
||||
echo "<tr><td><a class='view' href=\"/$path/Browse?dir=/mnt/$name\"><i class=\"icon-u-tab\" title=\"",_('Browse')," /mnt/$name\"></i></a>";
|
||||
echo "<a class='info nohand' onclick='return false'><i class='fa fa-$orb orb $color-orb'></i><span style='left:18px'>$help</span></a>$luks<a href=\"/$path/Disk?name=$name\" onclick=\"$.cookie('one','tab1')\">",compress($name),"</a></td>";
|
||||
echo "<td>{$disk['comment']}</td>";
|
||||
echo "<td>"._var($disk,'comment')."</td>";
|
||||
echo "<td>",disk_share_settings(_var($var,'shareSMBEnabled'), $sec[$name]),"</td>";
|
||||
echo "<td>",disk_share_settings(_var($var,'shareNFSEnabled'), $sec_nfs[$name]),"</td>";
|
||||
$cmd="/webGui/scripts/disk_size&arg1=$name&arg2=ssz2";
|
||||
|
@@ -14,7 +14,7 @@ $docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
if (array_key_exists('getdiagnostics', $_GET)) {
|
||||
$anonymize = empty($_GET['anonymize']) ? '-a' : '';
|
||||
$diag_file = '/tmp/feedback_diagnostics_'.time().'.zip';
|
||||
$diag_file = '/tmp/feedback-diagnostics-'.date('Ymd-Hi').'.zip';
|
||||
exec("$docroot/webGui/scripts/diagnostics $anonymize $diag_file");
|
||||
echo base64_encode(@file_get_contents($diag_file));
|
||||
@unlink($diag_file);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<?PHP
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -8,57 +8,76 @@
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$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";
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
class KeyInstaller
|
||||
{
|
||||
private $isGetRequest;
|
||||
private $getHasUrlParam;
|
||||
|
||||
function response_complete($httpcode, $result, $cli_success_msg='') {
|
||||
global $cli;
|
||||
$mutatedResult = is_array($result) ? json_encode($result) : $result;
|
||||
if ($cli) {
|
||||
$json = @json_decode($mutatedResult,true);
|
||||
if (!empty($json['error'])) {
|
||||
echo 'Error: '.$json['error'].PHP_EOL;
|
||||
exit(1);
|
||||
public function __construct()
|
||||
{
|
||||
$this->isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$this->getHasUrlParam = $_GET !== null && !empty($_GET) && isset($_GET['url']);
|
||||
|
||||
if ($this->isGetRequest && $this->getHasUrlParam) {
|
||||
$this->installKey();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $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.
|
||||
*/
|
||||
private function responseComplete($httpcode, $result)
|
||||
{
|
||||
$mutatedResult = is_array($result) ? json_encode($result) : $result;
|
||||
|
||||
if ($this->isGetRequest && $this->getHasUrlParam) { // return JSON to the caller
|
||||
header('Content-Type: application/json');
|
||||
http_response_code($httpcode);
|
||||
exit((string)$mutatedResult);
|
||||
} else { // return the result to the caller
|
||||
return $mutatedResult;
|
||||
}
|
||||
}
|
||||
|
||||
public function installKey($keyUrl = null)
|
||||
{
|
||||
$url = unscript($keyUrl ?? _var($_GET, 'url'));
|
||||
$host = parse_url($url)['host'] ?? '';
|
||||
|
||||
if (!function_exists('_')) {
|
||||
function _($text) {return $text;}
|
||||
}
|
||||
|
||||
if ($host && in_array($host, ['keys.lime-technology.com', 'lime-technology.com'])) {
|
||||
$keyFile = basename($url);
|
||||
exec("/usr/bin/wget -q -O " . escapeshellarg("/boot/config/$keyFile") . " " . escapeshellarg($url), $output, $returnVar);
|
||||
|
||||
if ($returnVar === 0) {
|
||||
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
if (_var($var, 'mdState') == "STARTED") {
|
||||
return $this->responseComplete(200, ['status' => _('Please Stop array to complete key installation')], _('success') . ', ' . _('Please Stop array to complete key installation'));;
|
||||
} else {
|
||||
return $this->responseComplete(200, ['status' => ''], _('success'));;
|
||||
}
|
||||
} else {
|
||||
return $this->responseComplete(406, ['error' => _('download error') . " $returnVar"]);;
|
||||
}
|
||||
} else {
|
||||
return $this->responseComplete(406, ['error' => _('bad or missing key file') . ": $url"]);;
|
||||
}
|
||||
}
|
||||
exit($cli_success_msg.PHP_EOL);
|
||||
}
|
||||
header('Content-Type: application/json');
|
||||
http_response_code($httpcode);
|
||||
exit((string)$mutatedResult);
|
||||
}
|
||||
|
||||
$cli = php_sapi_name()=='cli';
|
||||
$url = unscript(_var($_GET,'url'));
|
||||
$host = parse_url($url)['host']??'';
|
||||
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$getHasUrlParam = $_GET !== null && !empty($_GET) && isset($_GET['url']);
|
||||
|
||||
if ($host && in_array($host,['keys.lime-technology.com','lime-technology.com'])) {
|
||||
$key_file = basename($url);
|
||||
exec("/usr/bin/wget -q -O ".escapeshellarg("/boot/config/$key_file")." ".escapeshellarg($url), $output, $return_var);
|
||||
if ($return_var === 0) {
|
||||
$var = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
|
||||
if (_var($var,'mdState')=="STARTED") {
|
||||
response_complete(200, array('status' => _('Please Stop array to complete key installation')), _('success').', '._('Please Stop array to complete key installation'));
|
||||
} else {
|
||||
response_complete(200, array('status' => ''), _('success'));
|
||||
}
|
||||
} else {
|
||||
response_complete(406, array('error' => _('download error') . " $return_var"));
|
||||
}
|
||||
} else {
|
||||
response_complete(406, array('error' => _('bad or missing key file') . ": $url"));
|
||||
if ($isGetRequest && $getHasUrlParam) {
|
||||
$keyInstaller = new KeyInstaller();
|
||||
$keyInstaller->installKey();
|
||||
}
|
||||
?>
|
||||
|
@@ -287,6 +287,47 @@ done
|
||||
]]>
|
||||
</Script>
|
||||
</Agent>
|
||||
<Agent>
|
||||
<Name>ntfy.sh</Name>
|
||||
<Variables>
|
||||
<Variable Help="The full server base URL including protocol and port. eg: https://ntfy.sh" Desc="Full Server Base URL" Default="FULL NTFY.SH URL">SERVER_URL</Variable>
|
||||
<Variable Help="The ntfy.sh Token to use." Desc="ntfy.sh Token" Default="YOUR NTFY.SH TOKEN">NTFY_TOKEN</Variable>
|
||||
<Variable Help="The ntfy.sh Topic to use." Desc="ntfy.sh Topic" Default="Unraid">TOPIC</Variable>
|
||||
<Variable Help="Specify the fields which are included in the title of the notification." Desc="Notification Title" Default="$SUBJECT">TITLE</Variable>
|
||||
<Variable Help="Specify the fields which are included in the message body of the notification." Desc="Notification Message" Default="$DESCRIPTION">MESSAGE</Variable>
|
||||
</Variables>
|
||||
<Script>
|
||||
<![CDATA[
|
||||
#!/bin/bash
|
||||
############
|
||||
{0}
|
||||
############
|
||||
MESSAGE=$(echo -e "$MESSAGE")
|
||||
case "$IMPORTANCE" in
|
||||
'normal' )
|
||||
PRIORITY="default"
|
||||
;;
|
||||
'warning' )
|
||||
PRIORITY="high"
|
||||
;;
|
||||
'alert' )
|
||||
PRIORITY="urgent"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Remove any trailing slash
|
||||
SERVER_URL=${SERVER_URL%/}
|
||||
|
||||
curl \
|
||||
-H "Priority: $PRIORITY" \
|
||||
-H "Icon: https://raw.githubusercontent.com/unraid/webgui/master/emhttp/plugins/dynamix.vm.manager/templates/images/unraid.png" \
|
||||
-H "Authorization: Bearer $NTFY_TOKEN" \
|
||||
-H "Title: $TITLE" \
|
||||
-d "$MESSAGE" \
|
||||
$SERVER_URL/$TOPIC
|
||||
]]>
|
||||
</Script>
|
||||
</Agent>
|
||||
<Agent>
|
||||
<Name>Prowl</Name>
|
||||
<Variables>
|
||||
|
@@ -38,13 +38,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++;
|
||||
}
|
||||
|
@@ -46,9 +46,8 @@ $certPresent = file_exists($certPath);
|
||||
if ($certPresent) {
|
||||
// renew existing cert
|
||||
$certSubject = exec("/usr/bin/openssl x509 -subject -noout -in ".escapeshellarg($certPath));
|
||||
$isLegacyCert = preg_match('/.*\.unraid\.net$/', $certSubject);
|
||||
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', $certSubject);
|
||||
if ($isLegacyCert || $isWildcardCert) {
|
||||
if ($isWildcardCert) {
|
||||
exec("/usr/bin/openssl x509 -checkend 2592000 -noout -in ".escapeshellarg($certPath), $arrout, $retval_expired);
|
||||
if ($retval_expired === 0) {
|
||||
// not within 30 days of cert expire date
|
||||
@@ -59,7 +58,6 @@ if ($certPresent) {
|
||||
response_complete(406, '{"error":"'._('Cannot renew a custom cert at').' '.$certPath.'"}');
|
||||
}
|
||||
}
|
||||
$endpoint = ($certPresent && $isLegacyCert) ? "provisioncert" : "provisionwildcard";
|
||||
|
||||
$keyfile = empty($var['regFILE']) ? false : @file_get_contents($var['regFILE']);
|
||||
if ($keyfile === false) {
|
||||
@@ -67,7 +65,7 @@ if ($keyfile === false) {
|
||||
}
|
||||
$keyfile = @base64_encode($keyfile);
|
||||
|
||||
$ch = curl_init("https://keys.lime-technology.com/account/ssl/$endpoint");
|
||||
$ch = curl_init("https://keys.lime-technology.com/account/ssl/provisionwildcard");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||||
|
@@ -1,85 +1,196 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2020, 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
<?php
|
||||
$webguiGlobals = $GLOBALS;
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = 'tools';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
class ReplaceKey
|
||||
{
|
||||
private const KEY_SERVER_URL = 'https://keys.lime-technology.com';
|
||||
|
||||
$var = parse_ini_file('state/var.ini');
|
||||
$keyfile = base64_encode(file_get_contents($var['regFILE']));
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html <?=$display['rtl']?>lang="<?=strtok($locale,'_')?:'en'?>">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="viewport" content="width=1300">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta name="referrer" content="same-origin">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-fonts.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-popup.css")?>">
|
||||
<script src="<?autov('/webGui/javascript/dynamix.js')?>"></script>
|
||||
<script>
|
||||
function replaceKey(email, guid, keyfile) {
|
||||
if (email.length) {
|
||||
var timestamp = <?=time()?>;
|
||||
$('#status_panel').slideUp('fast');
|
||||
$('#input_form').find('input').prop('disabled', true);
|
||||
// Nerds love spinners, Maybe place a spinner image next to the submit button; we'll show it now:
|
||||
$('#spinner_image').fadeIn('fast');
|
||||
private $docroot;
|
||||
private $var;
|
||||
private $guid;
|
||||
private $keyfile;
|
||||
private $regExp;
|
||||
|
||||
$.post('https://keys.lime-technology.com/account/license/transfer',{timestamp:timestamp,guid:guid,email:email,keyfile:keyfile},function(data) {
|
||||
$('#spinner_image').fadeOut('fast');
|
||||
var msg = "<p><?=_('A registration replacement key has been created for USB Flash GUID')?> <strong>"+guid+"</strong></p>" +
|
||||
"<p><?=_('An email has been sent to')?> <strong>"+email+"</strong> <?=_('containing your key file URL')?>." +
|
||||
" <?=_('When received, please paste the URL into the *Key file URL* box and')?>" +
|
||||
" <?=_('click <i>Install Key</i>')?>.</p>" +
|
||||
"<p><?=_('If you do not receive an email, please check your spam or junk-email folder')?>.</p>";
|
||||
public function __construct()
|
||||
{
|
||||
$this->docroot = $GLOBALS['docroot'] ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$('#status_panel').hide().html(msg).slideDown('fast');
|
||||
$('#input_form').fadeOut('fast');
|
||||
}).fail(function(data) {
|
||||
$('#input_form').find('input').prop('disabled', false);
|
||||
$('#spinner_image').fadeOut('fast');
|
||||
var status = data.status;
|
||||
var obj = data.responseJSON;
|
||||
var msg = "<p><?=_('Sorry, an error occurred')?> <?=_('registering USB Flash GUID')?> <strong>"+guid+"</strong><p>"+"<p><?=_('The error is')?>: "+obj.error+"</p>";
|
||||
$this->var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
$this->guid = @$this->var['regGUID'] ?? null;
|
||||
|
||||
$('#status_panel').hide().html(msg).slideDown('fast');
|
||||
});
|
||||
}
|
||||
$keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
|
||||
if ($keyfileBase64 !== false) {
|
||||
$keyfileBase64 = @base64_encode($keyfileBase64);
|
||||
$this->keyfile = str_replace(['+', '/', '='], ['-', '_', ''], trim($keyfileBase64));
|
||||
}
|
||||
|
||||
$this->regExp = @$this->var['regExp'] ?? null;
|
||||
}
|
||||
|
||||
private function request($url, $method, $payload = null, $headers = null)
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
|
||||
// Set the request method
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
// store the response in a variable instead of printing it
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
// Set the payload if present
|
||||
if ($payload !== null) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
}
|
||||
|
||||
if ($headers !== null) {
|
||||
// Set the headers
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
}
|
||||
|
||||
// Set additional options as needed
|
||||
|
||||
// Execute the request
|
||||
$response = curl_exec($ch);
|
||||
|
||||
// Check for errors
|
||||
if (curl_errno($ch)) {
|
||||
$error = [
|
||||
'heading' => 'CurlError',
|
||||
'message' => curl_error($ch),
|
||||
'level' => 'error',
|
||||
'ref' => 'curlError',
|
||||
'type' => 'request',
|
||||
];
|
||||
// @todo store error
|
||||
}
|
||||
|
||||
// Close the cURL session
|
||||
curl_close($ch);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function validateGuid()
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
|
||||
$params = [
|
||||
'guid' => $this->guid,
|
||||
'keyfile' => $this->keyfile,
|
||||
];
|
||||
|
||||
/**
|
||||
* returns {JSON}
|
||||
* hasNewerKeyfile : boolean;
|
||||
* purchaseable: true;
|
||||
* registered: false;
|
||||
* replaceable: false;
|
||||
* upgradeable: false;
|
||||
* upgradeAllowed: string[];
|
||||
* updatesRenewable: false;
|
||||
*/
|
||||
$response = $this->request(
|
||||
self::KEY_SERVER_URL . '/validate/guid',
|
||||
'POST',
|
||||
http_build_query($params),
|
||||
$headers,
|
||||
);
|
||||
|
||||
// Handle the response as needed (parsing JSON, etc.)
|
||||
$decodedResponse = json_decode($response, true);
|
||||
|
||||
if (!empty($decodedResponse)) {
|
||||
return $decodedResponse;
|
||||
}
|
||||
|
||||
// @todo save error response somewhere
|
||||
return [];
|
||||
}
|
||||
|
||||
private function getLatestKey()
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
|
||||
$params = [
|
||||
'keyfile' => $this->keyfile,
|
||||
];
|
||||
|
||||
/**
|
||||
* returns {JSON}
|
||||
* license: string;
|
||||
*/
|
||||
$response = $this->request(
|
||||
self::KEY_SERVER_URL . '/key/latest',
|
||||
'POST',
|
||||
http_build_query($params),
|
||||
$headers,
|
||||
);
|
||||
|
||||
// Handle the response as needed (parsing JSON, etc.)
|
||||
$decodedResponse = json_decode($response, true);
|
||||
|
||||
if (!empty($decodedResponse) && !empty($decodedResponse['license'])) {
|
||||
return $decodedResponse['license'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function installNewKey($key)
|
||||
{
|
||||
require_once "$this->docroot/webGui/include/InstallKey.php";
|
||||
|
||||
$KeyInstaller = new KeyInstaller();
|
||||
$KeyInstaller->installKey($key);
|
||||
}
|
||||
|
||||
private function writeJsonFile($file, $data)
|
||||
{
|
||||
if (!is_dir(dirname($file))) { // prevents errors when directory doesn't exist
|
||||
mkdir(dirname($file));
|
||||
}
|
||||
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
public function check()
|
||||
{
|
||||
// we don't need to check
|
||||
if (empty($this->guid) || empty($this->keyfile) || empty($this->regExp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set $isAlreadyExpired to true if regExp is in the past
|
||||
$isAlreadyExpired = $this->regExp <= time();
|
||||
// if regExp is seven days or less from now, we need to check
|
||||
$isWithinSevenDays = $this->regExp <= strtotime('+7 days');
|
||||
|
||||
$shouldCheck = $isAlreadyExpired || $isWithinSevenDays;
|
||||
if (!$shouldCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
// see if we have a new key
|
||||
$validateGuidResponse = $this->validateGuid();
|
||||
|
||||
$hasNewerKeyfile = @$validateGuidResponse['hasNewerKeyfile'] ?? false;
|
||||
if (!$hasNewerKeyfile) {
|
||||
return; // if there is no newer keyfile, we don't need to do anything
|
||||
}
|
||||
|
||||
$latestKey = $this->getLatestKey();
|
||||
if (!$latestKey) {
|
||||
// we supposedly have a new key, but didn't get it back…
|
||||
$this->writeJsonFile(
|
||||
'/tmp/ReplaceKey/error.json',
|
||||
[
|
||||
'error' => 'Failed to retrieve latest key after getting a `hasNewerKeyfile` in the validation response.',
|
||||
]
|
||||
);
|
||||
return;
|
||||
}
|
||||
$this->installNewKey($latestKey);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-top:20px;line-height:30px;margin-left:40px">
|
||||
<div id="status_panel"></div>
|
||||
<form markdown="1" id="input_form">
|
||||
|
||||
Email address: <input type="text" name="email" maxlength="1024" value="" style="width:33%">
|
||||
|
||||
<input type="button" value="Replace Key" onclick="replaceKey(this.form.email.value.trim(), '<?=$var['flashGUID']?>', '<?=$keyfile?>')">
|
||||
|
||||
<p>A link to your replacement key will be delivered to this email address.
|
||||
|
||||
<p><strong>Note:</strong>
|
||||
Once a replacement key is generated, your old USB Flash device will be <b>blacklisted</b>.
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -38,6 +38,9 @@ function duration(&$hrs) {
|
||||
$age = date_diff($poh,$now);
|
||||
$hrs = "$hrs (".($age->y?"{$age->y}y, ":"").($age->m?"{$age->m}m, ":"").($age->d?"{$age->d}d, ":"")."{$age->h}h)";
|
||||
}
|
||||
function blocks_size(&$blks,$blk_size) {
|
||||
$blks = "$blks (".my_scale($blks*$blk_size,$unit)." $unit)";
|
||||
}
|
||||
function append(&$ref, &$info) {
|
||||
if ($info) $ref .= ($ref ? " " : "").$info;
|
||||
}
|
||||
@@ -61,6 +64,7 @@ case "attributes":
|
||||
$max = ($disk['maxTemp'] ?? $display['max'] ?? 0) ?: 0;
|
||||
$hot = ($disk['hotTemp'] ?? $display['hot'] ?? 0) ?: 0;
|
||||
$top = $_POST['top'] ?? 120;
|
||||
$ssd_remaining = NULL;
|
||||
$empty = true;
|
||||
exec("smartctl -n standby -A $type ".escapeshellarg("/dev/$port"),$output);
|
||||
// remove empty rows
|
||||
@@ -82,6 +86,8 @@ case "attributes":
|
||||
}
|
||||
if ($info[8]=='-') $info[8] = 'Never';
|
||||
if ($info[0]==9 && is_numeric(size($info[9]))) duration($info[9]);
|
||||
if (str_starts_with($info[1], 'Total_LBAs_')) blocks_size($info[9],512); // Assumes 512 byte sectors
|
||||
if (str_ends_with($info[1], '_32MiB')) blocks_size($info[9],32*1024*1024);
|
||||
echo "<tr{$color}>".implode('',array_map('normalize', $info))."</tr>";
|
||||
$empty = false;
|
||||
}
|
||||
@@ -100,11 +106,38 @@ case "attributes":
|
||||
case 'Power on hours':
|
||||
if (is_numeric(size($value))) duration($value);
|
||||
break;
|
||||
case 'Percentage used':
|
||||
$ssd_remaining = 100 - str_replace('%', '', $value);
|
||||
break;
|
||||
}
|
||||
if (str_ends_with($name, ', hours') && str_starts_with($value, 'minutes ')) {
|
||||
$name = substr($name, 0, -7);
|
||||
$value = substr($value, 8);
|
||||
if (is_numeric(size($value))) duration($value);
|
||||
}
|
||||
echo "<tr{$color}><td>-</td><td>$name</td><td colspan='8'>$value</td></tr>";
|
||||
$empty = false;
|
||||
}
|
||||
}
|
||||
if (is_null($ssd_remaining)) {
|
||||
// Try to look up SSD's 'Percentage Used Endurance Indicator' with special command
|
||||
exec("smartctl -n standby -l ssd $type ".escapeshellarg("/dev/$port"), $ssd_out);
|
||||
$ssd_out = array_filter($ssd_out);
|
||||
foreach ($ssd_out as $row) {
|
||||
if (str_ends_with($row, 'Percentage Used Endurance Indicator')) {
|
||||
// Probably a SATA SSD
|
||||
$info = explode(' ', trim(preg_replace('/\s+/',' ',$row)), 6);
|
||||
$ssd_remaining = 100 - $info[3];
|
||||
} elseif (str_starts_with($row, 'Percentage used endurance indicator:')) {
|
||||
// Probably a SAS SSD
|
||||
[$name,$value] = array_map('trim',explode(':', $row));
|
||||
$ssd_remaining = 100 - str_replace('%','',$value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!is_null($ssd_remaining)) {
|
||||
echo "<tr><td>-</td><td>SSD endurance remaining</td><td colspan='8'>$ssd_remaining %</td></tr>";
|
||||
}
|
||||
if ($empty) echo "<tr><td colspan='10' style='text-align:center;padding-top:12px'>"._('Attributes not available')."</td></tr>";
|
||||
break;
|
||||
case "capabilities":
|
||||
@@ -229,10 +262,10 @@ case "stop":
|
||||
exec("smartctl -X $type ".escapeshellarg("/dev/$port"));
|
||||
break;
|
||||
case "update":
|
||||
if ($disk["transport"] == "scsi") {
|
||||
if ($disk["transport"] == "scsi" || $disk["transport"] == "nvme") {
|
||||
$progress = exec("smartctl -n standby -l selftest $type ".escapeshellarg("/dev/$port")."|grep -Pom1 '\d+%'");
|
||||
if ($progress) {
|
||||
echo "<span class='big'><i class='fa fa-spinner fa-pulse'></i> "._('self-test in progress').", ".(100-substr($progress,0,-1))."% "._('complete')."</span>";
|
||||
if ($disk["transport"] == "nvme") echo "<span class='big'><i class='fa fa-spinner fa-pulse'></i> "._('self-test in progress').", ".(substr($progress,0,-1))."% "._('complete')."</span>"; else echo "<span class='big'><i class='fa fa-spinner fa-pulse'></i> "._('self-test in progress').", ".(100-substr($progress,0,-1))."% "._('complete')."</span>";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@@ -76,7 +76,7 @@ switch ($_POST['table']) {
|
||||
} 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>" ;
|
||||
}
|
||||
}
|
||||
$html .= "<td>$modname$supporthtml</td>" ;
|
||||
|
@@ -24,7 +24,7 @@ $lsmod = shell_exec("lsmod") ;
|
||||
$supportpage = true;
|
||||
$modtoplgfile = "/tmp/modulestoplg.json" ;
|
||||
$sysdrvfile = "/tmp/sysdrivers.json" ;
|
||||
$arrModtoPlg = json_decode(file_get_contents("/tmp/modulestoplg.json") ,TRUE) ;
|
||||
$arrModtoPlg = file_exists($modtoplgfile) ? json_decode(file_get_contents($modtoplgfile), true) : '';
|
||||
file_put_contents("/tmp/sysdrivers.init","1") ;
|
||||
SysDriverslog("SysDrivers Build Starting") ;
|
||||
modtoplg() ;
|
||||
|
@@ -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,
|
||||
@@ -11,354 +11,16 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = 'settings';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/webGui/include/Helpers.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);
|
||||
}
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
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 = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
|
||||
$nginx = @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 = file_exists($myservers_flash_cfg_path) ? @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);
|
||||
?>
|
||||
|
@@ -74,14 +74,14 @@ function ipaddr($ethX='eth0', $prot=4) {
|
||||
global $$ethX;
|
||||
switch (_var($$ethX,'PROTOCOL:0')) {
|
||||
case 'ipv4':
|
||||
return $$ethX['IPADDR:0'];
|
||||
return _var($$ethX,'IPADDR:0');
|
||||
case 'ipv6':
|
||||
return $$ethX['IPADDR6:0'];
|
||||
return _var($$ethX,'IPADDR6:0');
|
||||
case 'ipv4+ipv6':
|
||||
switch ($prot) {
|
||||
case 4: return $$ethX['IPADDR:0'];
|
||||
case 6: return $$ethX['IPADDR6:0'];
|
||||
default:return [$$ethX['IPADDR:0'],$$ethX['IPADDR6:0']];}
|
||||
case 4: return _var($$ethX,'IPADDR:0');
|
||||
case 6: return _var($$ethX,'IPADDR6:0');
|
||||
default:return [_var($$ethX,'IPADDR:0'),_var($$ethX,'IPADDR6:0')];}
|
||||
default:
|
||||
return _var($$ethX,'IPADDR:0');
|
||||
}
|
||||
@@ -91,4 +91,8 @@ function my_date($fmt, $time) {
|
||||
$legacy = ['%c' => 'D j M Y h:i:s A T','%A' => 'l','%Y' => 'Y','%B' => 'F','%e' => 'j','%d' => 'd','%m' => 'm','%I' => 'h','%H' => 'H','%M' => 'i','%S' => 's','%p' => 'a','%R' => 'H:i', '%F' => 'Y-m-d', '%T' => 'H:i:s'];
|
||||
return date(strtr($fmt,$legacy), $time);
|
||||
}
|
||||
// ensure params passed to logger are properly escaped
|
||||
function my_logger($message, $logger='webgui') {
|
||||
exec('logger -t '.escapeshellarg($logger).' -- '.escapeshellarg($message));
|
||||
}
|
||||
?>
|
||||
|
@@ -54,7 +54,7 @@ Q.find=(function(){var aP=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][
|
||||
!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof exports?module.exports=e(require("jquery")):e(jQuery)}(function(p){var o=/\+/g;function f(e){return m.raw?e:encodeURIComponent(e)}function l(e,n){e=m.raw?e:function(e){0===e.indexOf('"')&&(e=e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return e=decodeURIComponent(e.replace(o," ")),m.json?JSON.parse(e):e}catch(e){}}(e);return p.isFunction(n)?n(e):e}var m=p.cookie=function(e,n,o){var i,t;if(1<arguments.length&&!p.isFunction(n))return"number"==typeof(o=p.extend({},m.defaults,o)).expires&&(t=o.expires,(i=o.expires=new Date).setMilliseconds(i.getMilliseconds()+864e5*t)),document.cookie=[f(e),"=",(t=n,f(m.json?JSON.stringify(t):String(t))),o.expires?"; expires="+o.expires.toUTCString():"",o.path?"; path="+o.path:"",o.domain?"; domain="+o.domain:"",o.samesite?"; samesite="+o.samesite:"",o.secure?"; secure":""].join("");for(var r=e?void 0:{},s=document.cookie?document.cookie.split("; "):[],c=0,a=s.length;c<a;c++){var u=s[c].split("="),d=(d=u.shift(),m.raw?d:decodeURIComponent(d)),u=u.join("=");if(e===d){r=l(u,n);break}e||void 0===(u=l(u))||(r[d]=u)}return r};m.defaults={path:"/",samesite:"lax"},p.removeCookie=function(e,n){return n=p.extend({},m.defaults,n),p.cookie(e,"",p.extend({},n,{expires:-1})),!p.cookie(e)}});
|
||||
|
||||
/* shortcuts - v2.01.B, copyright Binny V A NOT UPDATED */
|
||||
shortcut={all_shortcuts:{},add:function(l,p,i){var e={type:"keydown",propagate:!1,disable_in_input:!1,target:document,keycode:!1};if(i)for(var t in e)void 0===i[t]&&(i[t]=e[t]);else i=e;var a=i.target;"string"==typeof i.target&&(a=document.getElementById(i.target));l=l.toLowerCase();function r(e){var t;if(e=e||window.event,!i.disable_in_input||(e.target?t=e.target:e.srcElement&&(t=e.srcElement),3==t.nodeType&&(t=t.parentNode),"INPUT"!=t.tagName&&"TEXTAREA"!=t.tagName)){e.keyCode?code=e.keyCode:e.which&&(code=e.which);var a=String.fromCharCode(code).toLowerCase();188==code&&(a=","),190==code&&(a=".");var r=l.split("+"),n=0,s={"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")","-":"_","=":"+",";":":","'":'"',",":"<",".":">","/":"?","\\":"|"},o={esc:27,escape:27,tab:9,space:32,return:13,enter:13,backspace:8,scrolllock:145,scroll_lock:145,scroll:145,capslock:20,caps_lock:20,caps:20,numlock:144,num_lock:144,num:144,pause:19,break:19,insert:45,home:36,delete:46,end:35,pageup:33,page_up:33,pu:33,pagedown:34,page_down:34,pd:34,left:37,up:38,right:39,down:40,f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123},d={shift:{wanted:!1,pressed:!1},ctrl:{wanted:!1,pressed:!1},alt:{wanted:!1,pressed:!1},meta:{wanted:!1,pressed:!1}};e.ctrlKey&&(d.ctrl.pressed=!0),e.shiftKey&&(d.shift.pressed=!0),e.altKey&&(d.alt.pressed=!0),e.metaKey&&(d.meta.pressed=!0);for(var c=0;k=r[c],c<r.length;c++)"ctrl"==k||"control"==k?(n++,d.ctrl.wanted=!0):"shift"==k?(n++,d.shift.wanted=!0):"alt"==k?(n++,d.alt.wanted=!0):"meta"==k?(n++,d.meta.wanted=!0):1<k.length?o[k]==code&&n++:i.keycode?i.keycode==code&&n++:a==k?n++:s[a]&&e.shiftKey&&(a=s[a])==k&&n++;return n!=r.length||d.ctrl.pressed!=d.ctrl.wanted||d.shift.pressed!=d.shift.wanted||d.alt.pressed!=d.alt.wanted||d.meta.pressed!=d.meta.wanted||(p(e),i.propagate)?void 0:(e.cancelBubble=!0,e.returnValue=!1,e.stopPropagation&&(e.stopPropagation(),e.preventDefault()),!1)}}this.all_shortcuts[l]={callback:r,target:a,event:i.type},a.addEventListener?a.addEventListener(i.type,r,!1):a.attachEvent?a.attachEvent("on"+i.type,r):a["on"+i.type]=r},remove:function(e){e=e.toLowerCase();var t=this.all_shortcuts[e];if(delete this.all_shortcuts[e],t){var a=t.event,r=t.target,n=t.callback;r.detachEvent?r.detachEvent("on"+a,n):r.removeEventListener?r.removeEventListener(a,n,!1):r["on"+a]=!1}}};
|
||||
|
||||
/* Modified by Andrew Zawadzki - Changed variable code to be codeAZ due to conflict with const code in vue */
|
||||
shortcut={all_shortcuts:{},add:function(l,p,i){var e={type:"keydown",propagate:!1,disable_in_input:!1,target:document,keycode:!1};if(i)for(var t in e)void 0===i[t]&&(i[t]=e[t]);else i=e;var a=i.target;"string"==typeof i.target&&(a=document.getElementById(i.target));l=l.toLowerCase();function r(e){var t;if(e=e||window.event,!i.disable_in_input||(e.target?t=e.target:e.srcElement&&(t=e.srcElement),3==t.nodeType&&(t=t.parentNode),"INPUT"!=t.tagName&&"TEXTAREA"!=t.tagName)){e.keyCode?codeAZ=e.keyCode:e.which&&(codeAZ=e.which);var a=String.fromCharCode(codeAZ).toLowerCase();188==codeAZ&&(a=","),190==codeAZ&&(a=".");var r=l.split("+"),n=0,s={"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")","-":"_","=":"+",";":":","'":'"',",":"<",".":">","/":"?","\\":"|"},o={esc:27,escape:27,tab:9,space:32,return:13,enter:13,backspace:8,scrolllock:145,scroll_lock:145,scroll:145,capslock:20,caps_lock:20,caps:20,numlock:144,num_lock:144,num:144,pause:19,break:19,insert:45,home:36,delete:46,end:35,pageup:33,page_up:33,pu:33,pagedown:34,page_down:34,pd:34,left:37,up:38,right:39,down:40,f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123},d={shift:{wanted:!1,pressed:!1},ctrl:{wanted:!1,pressed:!1},alt:{wanted:!1,pressed:!1},meta:{wanted:!1,pressed:!1}};e.ctrlKey&&(d.ctrl.pressed=!0),e.shiftKey&&(d.shift.pressed=!0),e.altKey&&(d.alt.pressed=!0),e.metaKey&&(d.meta.pressed=!0);for(var c=0;k=r[c],c<r.length;c++)"ctrl"==k||"control"==k?(n++,d.ctrl.wanted=!0):"shift"==k?(n++,d.shift.wanted=!0):"alt"==k?(n++,d.alt.wanted=!0):"meta"==k?(n++,d.meta.wanted=!0):1<k.length?o[k]==codeAZ&&n++:i.keycode?i.keycode==codeAZ&&n++:a==k?n++:s[a]&&e.shiftKey&&(a=s[a])==k&&n++;return n!=r.length||d.ctrl.pressed!=d.ctrl.wanted||d.shift.pressed!=d.shift.wanted||d.alt.pressed!=d.alt.wanted||d.meta.pressed!=d.meta.wanted||(p(e),i.propagate)?void 0:(e.cancelBubble=!0,e.returnValue=!1,e.stopPropagation&&(e.stopPropagation(),e.preventDefault()),!1)}}this.all_shortcuts[l]={callback:r,target:a,event:i.type},a.addEventListener?a.addEventListener(i.type,r,!1):a.attachEvent?a.attachEvent("on"+i.type,r):a["on"+i.type]=r},remove:function(e){e=e.toLowerCase();var t=this.all_shortcuts[e];if(delete this.all_shortcuts[e],t){var a=t.event,r=t.target,n=t.callback;r.detachEvent?r.detachEvent("on"+a,n):r.removeEventListener?r.removeEventListener(a,n,!1):r["on"+a]=!1}}};
|
||||
/* readmore.js - v2.0.0, copyright Jed Foster NOT UPDATED */
|
||||
(function(c){function g(b,a){this.element=b;this.options=c.extend({},h,a);c(this.element).data("max-height",this.options.maxHeight);c(this.element).data("height-margin",this.options.heightMargin);delete this.options.maxHeight;if(this.options.embedCSS&&!k){var d=".readmore-js-toggle, .readmore-js-section { "+this.options.sectionCSS+" } .readmore-js-section { overflow: hidden; }",e=document.createElement("style");e.type="text/css";e.styleSheet?e.styleSheet.cssText=d:e.appendChild(document.createTextNode(d));document.getElementsByTagName("head")[0].appendChild(e);k=!0}this._defaults=h;this._name=f;this.init()}var f="readmore",h={speed:100,maxHeight:200,heightMargin:16,moreLink:'<a href="#">Read More</a>',lessLink:'<a href="#">Close</a>',embedCSS:!0,sectionCSS:"display: block; width: 100%;",startOpen:!1,expandedClass:"readmore-js-expanded",collapsedClass:"readmore-js-collapsed",beforeToggle:function(){},afterToggle:function(){}},k=!1;g.prototype={init:function(){var b=this;c(this.element).each(function(){var a=c(this),d=a.css("max-height").replace(/[^-\d\.]/g,"")>a.data("max-height")?a.css("max-height").replace(/[^-\d\.]/g,""):a.data("max-height"),e=a.data("height-margin");"none"!=a.css("max-height")&&a.css("max-height","none");b.setBoxHeight(a);if(a.outerHeight(!0)<=d+e)return!0;a.addClass("readmore-js-section "+b.options.collapsedClass).data("collapsedHeight",d);a.after(c(b.options.startOpen?b.options.lessLink:b.options.moreLink).on("click",function(c){b.toggleSlider(this,a,c)}).addClass("readmore-js-toggle"));b.options.startOpen||a.css({height:d})});c(window).on("resize",function(a){b.resizeBoxes()})},toggleSlider:function(b,a,d){d.preventDefault();var e=this;d=newLink=sectionClass="";var f=!1;d=c(a).data("collapsedHeight");c(a).height()<=d?(d=c(a).data("expandedHeight")+"px",newLink="lessLink",f=!0,sectionClass=e.options.expandedClass):(newLink="moreLink",sectionClass=e.options.collapsedClass);e.options.beforeToggle(b,a,f);c(a).animate({height:d},{duration:e.options.speed,complete:function(){e.options.afterToggle(b,a,f);c(b).replaceWith(c(e.options[newLink]).on("click",function(b){e.toggleSlider(this,a,b)}).addClass("readmore-js-toggle"));c(this).removeClass(e.options.collapsedClass+" "+e.options.expandedClass).addClass(sectionClass)}})},setBoxHeight:function(b){var a=b.clone().css({height:"auto",width:b.width(),overflow:"hidden"}).insertAfter(b),c=a.outerHeight(!0);a.remove();b.data("expandedHeight",c)},resizeBoxes:function(){var b=this;c(".readmore-js-section").each(function(){var a=c(this);b.setBoxHeight(a);(a.height()>a.data("expandedHeight")||a.hasClass(b.options.expandedClass)&&a.height()<a.data("expandedHeight"))&&a.css("height",a.data("expandedHeight"))})},destroy:function(){var b=this;c(this.element).each(function(){var a=c(this);a.removeClass("readmore-js-section "+b.options.collapsedClass+" "+b.options.expandedClass).css({"max-height":"",height:"auto"}).next(".readmore-js-toggle").remove();a.removeData()})}};c.fn[f]=function(b){var a=arguments;if(void 0===b||"object"===typeof b)return this.each(function(){if(c.data(this,"plugin_"+f)){var a=c.data(this,"plugin_"+f);a.destroy.apply(a)}c.data(this,"plugin_"+f,new g(this,b))});if("string"===typeof b&&"_"!==b[0]&&"init"!==b)return this.each(function(){var d=c.data(this,"plugin_"+f);d instanceof g&&"function"===typeof d[b]&&d[b].apply(d,Array.prototype.slice.call(a,1))})}})(jQuery);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2021, Lime Technology
|
||||
* Copyright 2012-2021, 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,
|
||||
@@ -14,11 +14,19 @@
|
||||
<?
|
||||
$docroot = '/usr/local/emhttp';
|
||||
$notify = "$docroot/webGui/scripts/notify";
|
||||
$md5_old = -1;
|
||||
|
||||
require_once "$docroot/webGui/include/publish.php";
|
||||
|
||||
while (true) {
|
||||
publish('notify', shell_exec("$notify get"));
|
||||
$echo = shell_exec("$notify get");
|
||||
if ( $echo ) {
|
||||
$md5_new = md5($echo,true);
|
||||
if ($md5_new !== $md5_old) {
|
||||
publish('notify', $echo);
|
||||
$md5_old = $md5_new;
|
||||
}
|
||||
}
|
||||
sleep(3);
|
||||
}
|
||||
?>
|
||||
|
@@ -306,6 +306,36 @@ function geturls() {
|
||||
return str_replace("\n", "\r\n", $urls);
|
||||
}
|
||||
|
||||
// anonymize individual syslog files
|
||||
function anonymize_syslog($file) {
|
||||
global $diag, $all;
|
||||
$max = 2*1024*1024; //=2MB
|
||||
$log = "/$diag/logs/".basename($file);
|
||||
run("todos <".escapeshellarg($file)." >".escapeshellarg("$log.txt"));
|
||||
if (!$all) {
|
||||
unset($titles,$rows);
|
||||
run("grep -Po 'file: \K[^\"\\x27]+' ".escapeshellarg("$log.txt")." 2>/dev/null|sort|uniq", $titles);
|
||||
run("sed -ri 's|\b\S+@\S+\.\S+\b|email@removed.com|;s|\b(username\|password)([=:])\S+\b|\\1\\2xxx|;s|(GUID: \S)\S+(\S) |\\1..\\2 |;s|(moving \"\S\|\"/mnt/user/\S).*(\S)\"|\\1..\\2\"|' ".escapeshellarg("$log.txt"));
|
||||
run("sed -ri 's|(server: ).+(\.(my)?unraid\.net(:[0-9]+)?,)|\\1hash\\2|;s|(host: \").+(\.(my)?unraid\.net(:[0-9]+)?\")|\\1hash\\2|;s|(referrer: \"https?://).+(\.(my)?unraid\.net)|\\1hash\\2|' ".escapeshellarg("$log.txt"));
|
||||
maskIP("$log.txt");
|
||||
foreach ($titles as $mover) {
|
||||
if (!$mover) continue;
|
||||
$title = "/{$mover[0]}..".substr($mover,-1)."/...";
|
||||
run("sed -i 's/".str_replace("/","\/",$mover)."/".str_replace("/","\/",$title)."/g' ".escapeshellarg("$log.txt")." 2>/dev/null");
|
||||
//run("sed -ri 's|(file: [.>cr].*)[ /]$mover/.*$|\\1 file: $title|' ".escapeshellarg("$log.txt")." 2>/dev/null");
|
||||
}
|
||||
run("grep -n ' cache_dirs: -' ".escapeshellarg("$log.txt")." 2>/dev/null|cut -d: -f1", $rows);
|
||||
for ($i = 0; $i < count($rows); $i += 2) for ($row = $rows[$i]+1; $row < $rows[$i+1]; $row++) run("sed -ri '$row s|(cache_dirs: \S).*(\S)|\\1..\\2|' ".escapeshellarg("$log.txt")." 2>/dev/null");
|
||||
}
|
||||
// replace consecutive repeated lines in syslog
|
||||
run("awk -i inplace '{if(s!=substr(\$0,17)){if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\";print;x=0}else{x++}s=substr(\$0,17)}END{if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\"}' ".escapeshellarg("$log.txt"));
|
||||
// remove SHA256 hashes
|
||||
run("sed -ri 's/(SHA256:).+[^\s\b]/SHA256:***REMOVED***/gm' $log.txt");
|
||||
// truncate syslog if too big
|
||||
if (basename($file)=='syslog' && filesize($file)>=$max) run("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
|
||||
run("truncate -s '<$max' ".escapeshellarg("$log.txt"));
|
||||
}
|
||||
|
||||
// diagnostics start
|
||||
run("mkdir -p /boot/logs");
|
||||
|
||||
@@ -612,32 +642,11 @@ foreach ($all_xml as $xml) {
|
||||
}
|
||||
|
||||
// copy syslog information (anonymize if applicable)
|
||||
$max = 2*1024*1024; //=2MB
|
||||
foreach (glob("/var/log/syslog*") as $file) {
|
||||
$log = "/$diag/logs/".basename($file);
|
||||
run("todos <".escapeshellarg($file)." >".escapeshellarg("$log.txt"));
|
||||
if (!$all) {
|
||||
unset($titles,$rows);
|
||||
run("grep -Po 'file: \K[^\"\\x27]+' ".escapeshellarg("$log.txt")." 2>/dev/null|sort|uniq", $titles);
|
||||
run("sed -ri 's|\b\S+@\S+\.\S+\b|email@removed.com|;s|\b(username\|password)([=:])\S+\b|\\1\\2xxx|;s|(GUID: \S)\S+(\S) |\\1..\\2 |;s|(moving \"\S\|\"/mnt/user/\S).*(\S)\"|\\1..\\2\"|' ".escapeshellarg("$log.txt"));
|
||||
run("sed -ri 's|(server: ).+(\.(my)?unraid\.net(:[0-9]+)?,)|\\1hash\\2|;s|(host: \").+(\.(my)?unraid\.net(:[0-9]+)?\")|\\1hash\\2|;s|(referrer: \"https?://).+(\.(my)?unraid\.net)|\\1hash\\2|' ".escapeshellarg("$log.txt"));
|
||||
maskIP("$log.txt");
|
||||
foreach ($titles as $mover) {
|
||||
if (!$mover) continue;
|
||||
$title = "/{$mover[0]}..".substr($mover,-1)."/...";
|
||||
run("sed -i 's/".str_replace("/","\/",$mover)."/".str_replace("/","\/",$title)."/g' ".escapeshellarg("$log.txt")." 2>/dev/null");
|
||||
//run("sed -ri 's|(file: [.>cr].*)[ /]$mover/.*$|\\1 file: $title|' ".escapeshellarg("$log.txt")." 2>/dev/null");
|
||||
}
|
||||
run("grep -n ' cache_dirs: -' ".escapeshellarg("$log.txt")." 2>/dev/null|cut -d: -f1", $rows);
|
||||
for ($i = 0; $i < count($rows); $i += 2) for ($row = $rows[$i]+1; $row < $rows[$i+1]; $row++) run("sed -ri '$row s|(cache_dirs: \S).*(\S)|\\1..\\2|' ".escapeshellarg("$log.txt")." 2>/dev/null");
|
||||
}
|
||||
// replace consecutive repeated lines in syslog
|
||||
run("awk -i inplace '{if(s!=substr(\$0,17)){if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\";print;x=0}else{x++}s=substr(\$0,17)}END{if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\"}' ".escapeshellarg("$log.txt"));
|
||||
// remove SHA256 hashes
|
||||
run("sed -ri 's/(SHA256:).+[^\s\b]/SHA256:***REMOVED***/gm' $log.txt");
|
||||
// truncate syslog if too big
|
||||
if (basename($file)=='syslog' && filesize($file)>=$max) run("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
|
||||
run("truncate -s '<$max' ".escapeshellarg("$log.txt"));
|
||||
anonymize_syslog($file);
|
||||
}
|
||||
foreach (glob("/boot/logs/syslog-previous*") as $file) {
|
||||
anonymize_syslog($file);
|
||||
}
|
||||
|
||||
// copy dhcplog
|
||||
@@ -648,6 +657,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)) {
|
||||
|
@@ -209,6 +209,7 @@ $width = in_array($display['theme'], ['azure', 'gray']) ? '98.4%' : '100%';
|
||||
troubleshoot_reset();
|
||||
comment_reset();
|
||||
$('#optFeatureRequest').click();
|
||||
$('button.confirm').text("<?=_('Cancel')?>");
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
@@ -25,7 +25,7 @@ function update_wireguard($ifname) {
|
||||
$vtun = basename($wg,'.conf');
|
||||
// interface has changed?
|
||||
if (exec("grep -Pom1 ' dev $nic ' $wg")=='') {
|
||||
exec("logger -t netconfig 'updated wireguard $vtun configuration'");
|
||||
exec("logger -t netconfig -- \"updated wireguard $vtun configuration\"");
|
||||
exec("sed -ri 's/ dev (br0|bond0|eth0) / dev $nic /' $wg");
|
||||
}
|
||||
// restart active wireguard tunnels
|
||||
@@ -81,7 +81,7 @@ if ($run) {
|
||||
}
|
||||
|
||||
// create configuration file for all available interfaces
|
||||
$i = 0; $new = []; $new[] = "# Generated settings:";
|
||||
$i = 0; $new = ["# Generated settings:"];
|
||||
foreach ($ini as $name => $port) {
|
||||
$bonding = $port['BONDING']=='yes';
|
||||
$bridging = $port['BRIDGING']=='yes';
|
||||
@@ -126,8 +126,8 @@ file_put_contents($cfg,implode("\r\n",$new)."\r\n");
|
||||
// start interface with updated (new) configuration
|
||||
// don't execute when only interface description has changed
|
||||
if ($run) {
|
||||
exec("/etc/rc.d/rc.inet1 {$ifname}_start >/dev/null 2>&1");
|
||||
exec("/usr/local/sbin/create_network_ini $ifname >/dev/null 2>&1 &");
|
||||
exec("/etc/rc.d/rc.inet1 {$ifname}_start &>/dev/null");
|
||||
exec("/usr/local/sbin/create_network_ini $ifname &>/dev/null &");
|
||||
update_wireguard($ifname);
|
||||
}
|
||||
exit(0);
|
||||
|
23
emhttp/plugins/dynamix/scripts/replace_key_job
Executable file
23
emhttp/plugins/dynamix/scripts/replace_key_job
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/php -q
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/plugins/dynamix/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix/include/ReplaceKey.php";
|
||||
|
||||
$randomMinute = rand(0, 59);
|
||||
|
||||
switch (@$argv[1] ?? '') {
|
||||
case 'cron-init':
|
||||
$text = <<<EOT
|
||||
# Create replace key job:
|
||||
$randomMinute * * * * /usr/local/emhttp/plugins/dynamix/scripts/replace_key_job &> /dev/null
|
||||
|
||||
EOT;
|
||||
parse_cron_cfg("dynamix", "replace-key-job", $text);
|
||||
break;
|
||||
|
||||
default:
|
||||
$ReplaceKey = new ReplaceKey();
|
||||
$ReplaceKey->check();
|
||||
break;
|
||||
}
|
@@ -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,
|
||||
@@ -20,6 +20,7 @@ require_once "$docroot/webGui/include/Wrappers.php";
|
||||
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'));
|
||||
@@ -176,7 +177,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);
|
||||
?>
|
||||
|
@@ -2,7 +2,7 @@ html{font-family:clear-sans;font-size:62.5%;height:100%}
|
||||
body{font-size:1.3rem;color:#606e7f;background-color:#e4e2e4;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
|
||||
@media (max-width:1280px){#template{min-width:1260px;max-width:1260px;margin:0}}
|
||||
@media (min-width:1281px){#template{min-width:1260px;margin:0}}
|
||||
@media (min-width:1921px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
|
||||
@media (min-width:1920px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
|
||||
img{border:none;text-decoration:none;vertical-align:middle}
|
||||
p{text-align:left}
|
||||
p.centered{text-align:left}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
html{font-family:clear-sans;font-size:62.5%;height:100%}
|
||||
body{font-size:1.3rem;color:#f2f2f2;background-color:#1c1b1b;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
|
||||
@media (max-width:1280px){#templsate{min-width:1260px;max-width:1260px;margin:0}}
|
||||
@media (max-width:1280px){#template{min-width:1260px;max-width:1260px;margin:0}}
|
||||
@media (min-width:1281px){#template{min-width:1260px;margin:0 10px}}
|
||||
@media (min-width:1921px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
|
||||
@media (min-width:1920px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
|
||||
img{border:none;text-decoration:none;vertical-align:middle}
|
||||
p{text-align:justify}
|
||||
p.centered{text-align:left}
|
||||
|
@@ -2,7 +2,7 @@ html{font-family:clear-sans;font-size:62.5%;height:100%}
|
||||
body{font-size:1.3rem;color:#606e7f;background-color:#1b1d1b;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
|
||||
@media (max-width:1280px){#template{min-width:1260px;max-width:1260px;margin:0}}
|
||||
@media (min-width:1281px){#template{min-width:1260px;margin:0}}
|
||||
@media (min-width:1921px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
|
||||
@media (min-width:1920px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
|
||||
img{border:none;text-decoration:none;vertical-align:middle}
|
||||
p{text-align:left}
|
||||
p.centered{text-align:left}
|
||||
|
@@ -2,7 +2,7 @@ html{font-family:clear-sans;font-size:62.5%;height:100%}
|
||||
body{font-size:1.3rem;color:#1c1b1b;background-color:#f2f2f2;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
|
||||
@media (max-width:1280px){#template{min-width:1260px;max-width:1260px;margin:0}}
|
||||
@media (min-width:1281px){#template{min-width:1260px;margin:0 10px}}
|
||||
@media (min-width:1921px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
|
||||
@media (min-width:1920px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
|
||||
img{border:none;text-decoration:none;vertical-align:middle}
|
||||
p{text-align:justify}
|
||||
p.centered{text-align:left}
|
||||
|
@@ -49,7 +49,7 @@ if (isset($_POST['#file'])) {
|
||||
$cleanup = isset($_POST['#cleanup']);
|
||||
$default = ($file && isset($_POST['#default'])) ? @parse_ini_file("$docroot/plugins/".basename(dirname($file))."/default.cfg", $section) : [];
|
||||
|
||||
$keys = @parse_ini_file($file, $section) ?: [];
|
||||
$keys = is_file($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'])) {
|
||||
|
@@ -22,6 +22,7 @@ DOCKER_PIDFILE=/var/run/$DOCKERD.pid
|
||||
DOCKER_LOG=/var/log/docker.log
|
||||
DOCKER_ROOT=/var/lib/docker
|
||||
DOCKER_CFG=/boot/config/docker.cfg
|
||||
DOCKER_TIMEOUT=$(awk -F'"' '/^DOCKER_TIMEOUT=/{print $2}' $DOCKER_CFG 2>/dev/null)
|
||||
STOCK="eth br bond"
|
||||
|
||||
# network file references
|
||||
@@ -40,7 +41,8 @@ if [[ -f $DOCKER_CFG ]]; then
|
||||
elif [[ -e $SYSTEM/${NIC/eth/bond} ]]; then
|
||||
NIC=${NIC/eth/bond}
|
||||
fi
|
||||
if ! grep -qPm1 "_${NIC^^}(_[0-9]+)?=" $DOCKER_CFG; then
|
||||
CFG=($(grep -Pom2 "_SUBNET_|_${NIC^^}(_[0-9]+)?=" $DOCKER_CFG))
|
||||
if [[ ${CFG[0]} == _SUBNET_ && -z ${CFG[1]} ]]; then
|
||||
# interface has changed, update configuration
|
||||
X=${NIC//[^0-9]/}
|
||||
sed -ri "s/_(BR|BOND|ETH)$X(_[0-9]+)?=/_${NIC^^}\2=/; s/(br|bond|eth)$X(\.[0-9]+)? /$NIC\2 /g" $DOCKER_CFG
|
||||
@@ -117,46 +119,6 @@ running_containers(){
|
||||
docker ps --format='{{.Names}}' 2>/dev/null
|
||||
}
|
||||
|
||||
max6() {
|
||||
# ipv6 addresses in long notation
|
||||
f=:ffff:
|
||||
for x in $*; do
|
||||
read a m < <(IFS=/; echo $x)
|
||||
[[ $a =~ $f && $a =~ '.' ]] && b=${a#*$f} a=${a%$f*}$f:0 || b=
|
||||
c=${a//[^:]/}
|
||||
[[ ${a:0:1} == : ]] && a=0${a}
|
||||
[[ ${a:${#a}-1} == : ]] && a=${a}0
|
||||
a=${a/::/:$(for((i=1;i<=$((8-${#c}));i++)); do printf "0:"; done)}
|
||||
d= a=$(for q in ${a//:/ }; do printf "$d%04x" "0x$q"; d=:; done)
|
||||
[[ -n $b ]] && d= a=${a%$f*}${f}$(for q in ${b//./ }; do printf "$d%03x" "0x$q"; d=.; done)
|
||||
[[ -z $m ]] && echo $a || echo $a/$m
|
||||
done
|
||||
}
|
||||
|
||||
min6() {
|
||||
# ipv6 address in short notation
|
||||
f=:ffff:
|
||||
[[ -n $1 ]] && read a m < <(IFS=/; echo $1) || return
|
||||
[[ $a =~ $f && $a =~ '.' ]] && b=${a#*$f} a=${a%$f*}$f || b=
|
||||
d= a=:$(for q in ${a//:/ }; do printf "$d%x" "0x$q"; d=:; done)
|
||||
a=${a/$(grep -Po ':(0(:|$)){2,8}' <<< $a|sort|tail -1)/::}
|
||||
[[ ${a:0:2} != :: ]] && a=${a:1}
|
||||
[[ -n $b ]] && d= a=${a%$f*}:$(for q in ${b//./ }; do printf "$d%x" "0x$q"; d=.; done)
|
||||
[[ -z $m ]] && echo $a || echo $a/$m
|
||||
}
|
||||
|
||||
wipe() {
|
||||
wet=($*)
|
||||
# remove temporary (privacy extensions) and host ipv6 addresses
|
||||
for tmp in $(ip -br -6 addr show scope global temporary dev $wet 2>/dev/null|awk '{$1=$2="";print}'); do
|
||||
for i in ${!wet[@]}; do
|
||||
[[ ${wet[$i]} == $tmp || (${wet[$i]} =~ '::' && ${wet[$i]#*/} == 128) ]] && unset 'wet[i]'
|
||||
done
|
||||
done
|
||||
# return cleaned-up list without interface name
|
||||
echo ${wet[@]/$wet}
|
||||
}
|
||||
|
||||
# Network driver
|
||||
driver() {
|
||||
# user selection when bridge is enabled
|
||||
@@ -221,11 +183,12 @@ add_route(){
|
||||
local CT=($(docker inspect --format='{{.State.Pid}} {{.NetworkSettings.Networks}}' $1))
|
||||
local PID=${CT[0]}
|
||||
local NET=${CT[1]#*[}
|
||||
if [[ $PID -gt 0 && ${NET%%:*} == br0 ]]; then
|
||||
local LAN=${NET%:*}
|
||||
if [[ $PID -gt 0 && "eth0 br0 bond0" =~ $LAN ]]; then
|
||||
local THISIP=$(sed -n '/^\[eth0\]$/,/^TYPE/p' $INI|grep -Pom1 '^IPADDR:0="\K[^"]+')
|
||||
for CFG in /etc/wireguard/wg*.cfg ; do
|
||||
local NETWORK=$(grep -Pom1 '^Network:0="\K[^"]+' $CFG)
|
||||
[[ -n $NETWORK ]] && nsenter -n -t $PID ip -4 route add $NETWORK via $THISIP dev br0 2>/dev/null
|
||||
[[ -n $NETWORK ]] && nsenter -n -t $PID ip -4 route add $NETWORK via $THISIP dev $LAN 2>/dev/null
|
||||
done
|
||||
fi
|
||||
}
|
||||
@@ -347,7 +310,8 @@ start_network(){
|
||||
GATEWAY=$(ip -4 route show default dev $NETWORK|awk '{print $3;exit}')
|
||||
fi
|
||||
SUBNET6=; GATEWAY6=; SERVER6=; RANGE6=;
|
||||
IPV6=$(min6 $(max6 $(wipe $(ip -br -6 addr show $NETWORK scope global|awk '{$2="";print;exit}'))|sort|head -1))
|
||||
IPV6=$(ip -br -6 addr show $NETWORK scope global mngtmpaddr|awk '{print $3;exit}')
|
||||
[[ -z $IPV6 ]] && IPV6=$(ip -br -6 addr show $NETWORK scope global permanent|awk '{print $3;exit}')
|
||||
if [[ -n $IPV6 ]]; then
|
||||
# get IPV6 subnet, preset to /64 if single host address is given
|
||||
[[ ${IPV6#*/} == 128 ]] && SUBNET6=$(echo $IPV6|sed -r 's/^([^:]+):([^:]+):([^:]+):([^:]+).*$/\1:\2:\3:\4::\/64/') || SUBNET6=$(ip -6 route show $IPV6 dev $NETWORK|awk '{print $1;exit}')
|
||||
@@ -542,7 +506,9 @@ start_containers(){
|
||||
|
||||
# Stop containers
|
||||
stop_containers(){
|
||||
[[ ! -z $(running_containers) ]] && docker stop $(running_containers) >/dev/null
|
||||
[[ -n $(running_containers) ]] && docker stop --time=${DOCKER_TIMEOUT:-10} $(running_containers) >/dev/null
|
||||
# Kill containers if still running
|
||||
docker kill $(docker ps -q) 2>/dev/null
|
||||
}
|
||||
|
||||
# Start docker
|
||||
@@ -573,23 +539,35 @@ stop_docker(){
|
||||
echo "stopping $DOCKERD ..."
|
||||
# If there is no PID file, ignore this request...
|
||||
if [[ -r $DOCKER_PIDFILE ]]; then
|
||||
# Try to stop dockerd gracefully
|
||||
kill $(docker_pid) 2>/dev/null
|
||||
local TIMER=15
|
||||
# must ensure daemon has exited
|
||||
for n in {1..15}; do
|
||||
while [[ $TIMER -gt 0 ]]; do
|
||||
sleep 1
|
||||
if [[ $(ps -p $(docker_pid) -o comm= 2>/dev/null) != $DOCKERD ]]; then
|
||||
rm -f $DOCKER_PIDFILE
|
||||
# tear down the bridge
|
||||
if ip link show docker0 >/dev/null 2>&1; then
|
||||
if [[ -e $SYSTEM/docker0 ]]; then
|
||||
ip link set docker0 down
|
||||
ip link del docker0
|
||||
fi
|
||||
return
|
||||
# signal succesful stop
|
||||
TIMER=-1
|
||||
else
|
||||
# show waiting message
|
||||
echo "$DAEMON... Waiting to die."
|
||||
((TIMER--))
|
||||
fi
|
||||
echo "waiting for docker to die ..."
|
||||
done
|
||||
echo "docker will not die!"
|
||||
exit 1
|
||||
if [[ $TIMER -eq 0 ]]; then
|
||||
echo "Error: process will not die!"
|
||||
# Send SIGKILL to dockerd
|
||||
kill -SIGKILL $(docker_pid) 2>/dev/null
|
||||
# Remove .sock and .pid
|
||||
rm -f /var/run/docker.sock $DOCKER_PIDFILE
|
||||
echo "$DAEMON... Killed."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
@@ -56,6 +56,16 @@
|
||||
# - added macvtap network creation
|
||||
# - removed unnecessary error output redirection for 'run' command
|
||||
|
||||
# Adapted by Bergware for use in Unraid OS - December 2023
|
||||
# - added interface carrier check before assigning IP address (DHCP or static)
|
||||
# - added "status" command
|
||||
# - remove leading zeros in IPv4 and IPv6 addresses
|
||||
|
||||
# Adapted by Bergware for use in Unraid OS - February 2024
|
||||
# - revised bond interface creation for linux kernel 6.1.75 and later point releases
|
||||
|
||||
# Bergware - modified for Unraid OS, February 2024
|
||||
|
||||
############################
|
||||
# READ NETWORK CONFIG FILE #
|
||||
############################
|
||||
@@ -63,10 +73,8 @@
|
||||
# get the configuration information from rc.inet1.conf
|
||||
. /etc/rc.d/rc.inet1.conf
|
||||
|
||||
# system network reference
|
||||
# system network references
|
||||
SYSTEM=/sys/class/net
|
||||
|
||||
# ipv6 config reference
|
||||
CONF6=/proc/sys/net/ipv6/conf
|
||||
|
||||
###########
|
||||
@@ -149,26 +157,32 @@ set_mtu(){
|
||||
fi
|
||||
}
|
||||
|
||||
# function to wait for carrier of interface
|
||||
carrier_up(){
|
||||
local n
|
||||
for n in {1..10}; do
|
||||
[[ $(cat $SYSTEM/$1/carrier 2>/dev/null) == 1 ]] && return 0 || sleep 1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# function to create bond interface
|
||||
bond_up(){
|
||||
[[ -d /proc/net/bonding ]] || modprobe bonding mode=${BONDING_MODE[$i]} miimon=${BONDING_MIIMON[$i]}
|
||||
run ip link add name ${BONDNAME[$i]} type bond mode ${BONDING_MODE[$i]} miimon ${BONDING_MIIMON[$i]}
|
||||
run ip link set ${BONDNAME[$i]} up
|
||||
set_mtu ${BONDNAME[$i]}
|
||||
PRIMARY=;
|
||||
# loop thru assigned interfaces in bond
|
||||
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
|
||||
done
|
||||
[[ -n $PRIMARY ]] && run ip link set name ${BONDNAME[$i]} type bond primary $PRIMARY
|
||||
# delay to allow bond initialization
|
||||
sleep 3
|
||||
}
|
||||
|
||||
# function to delete bond interface
|
||||
@@ -194,7 +208,6 @@ br_up(){
|
||||
BRSTP[$i]=${BRSTP[$i]/no/0}
|
||||
BRSTP[$i]=${BRSTP[$i]/yes/1}
|
||||
run ip link add name $BRIDGE type bridge stp_state ${BRSTP[$i]} forward_delay ${BRFD[$i]}
|
||||
run ip link set $BRIDGE up
|
||||
# loop thru assigned interfaces in bridge
|
||||
for BRNIC in ${BRNICS[$i]}; do
|
||||
[[ $j -eq 0 ]] && BRIF=$BRNIC || BRIF=$BRNIC.${VLANID[$i,$j]}
|
||||
@@ -347,27 +360,35 @@ ipaddr_up(){
|
||||
[[ $IP == ipv4 ]] && DHCP_OPTIONS="$DHCP_OPTIONS -4"
|
||||
[[ $IP == ipv6 ]] && DHCP_OPTIONS="$DHCP_OPTIONS -6"
|
||||
[[ $IP != ipv4 && -n $PRIV6 && -d $CONF6/$IFACE ]] && echo $PRIV6 >$CONF6/$IFACE/use_tempaddr
|
||||
log "polling up to 60 sec for DHCP server on interface $IFACE"
|
||||
if ! run timeout 60 dhcpcd -w $DHCP_OPTIONS $IFACE; then
|
||||
log "can't obtain IP address, continue polling in background on interface $IFACE"
|
||||
if carrier_up $IFACE; then
|
||||
# interface is UP
|
||||
log "interface $IFACE is UP, polling up to 60 sec for DHCP $IP server"
|
||||
if ! run timeout 60 dhcpcd -w $DHCP_OPTIONS $IFACE; then
|
||||
log "can't obtain IP address, continue polling in background on interface $IFACE"
|
||||
run dhcpcd -b $DHCP_OPTIONS $IFACE
|
||||
fi
|
||||
else
|
||||
# interface is DOWN
|
||||
log "interface $IFACE is DOWN, polling DHCP $IP server in background"
|
||||
run dhcpcd -b $DHCP_OPTIONS $IFACE
|
||||
fi
|
||||
[[ $j -eq $((${VLANS[$i]}-1)) ]] && sleep 3
|
||||
elif [[ $DHCP == no ]]; then
|
||||
# bring up interface using static IP address
|
||||
if carrier_up $IFACE; then STATE="UP"; else STATE="DOWN"; fi
|
||||
log "interface $IFACE is $STATE, setting static $IP address"
|
||||
ipv6_addr 0 1
|
||||
if [[ $IP != ipv6 ]]; then
|
||||
[[ $j -eq 0 ]] && ADDR=${IPADDR[$i]} || ADDR=${IPADDR[$i,$j]}
|
||||
if [[ -n $ADDR ]]; then
|
||||
[[ $j -eq 0 ]] && MASK=${NETMASK[$i]} || MASK=${NETMASK[$i,$j]}
|
||||
[[ -n $MASK ]] && run ip -4 addr add $ADDR/$MASK dev $IFACE metric 1
|
||||
[[ -n $MASK ]] && run ip -4 addr add $(unzero $ADDR)/$MASK dev $IFACE metric 1
|
||||
fi
|
||||
fi
|
||||
if [[ $IP != ipv4 ]]; then
|
||||
[[ $j -eq 0 ]] && ADDR6=${IPADDR6[$i]} || ADDR6=${IPADDR6[$i,$j]}
|
||||
if [[ -n $ADDR6 ]]; then
|
||||
[[ $j -eq 0 ]] && MASK6=${NETMASK6[$i]} || MASK6=${NETMASK6[$i,$j]}
|
||||
[[ -n $MASK6 ]] && run ip -6 addr add $ADDR6/$MASK6 dev $IFACE metric 1
|
||||
[[ -n $MASK6 ]] && run ip -6 addr add $(unzero6 $ADDR6)/$MASK6 dev $IFACE metric 1
|
||||
[[ -n $PRIV6 && -d $CONF6/$IFACE ]] && echo 0 >$CONF6/$IFACE/use_tempaddr
|
||||
fi
|
||||
fi
|
||||
@@ -425,8 +446,7 @@ if_up(){
|
||||
# set index of INTERFACE in array
|
||||
i=0
|
||||
while [[ $i -lt $MAXNICS ]]; do
|
||||
[[ ${IFNAME[$i]} == $1 ]] && break
|
||||
((i++))
|
||||
[[ ${IFNAME[$i]} == $1 ]] && break || ((i++))
|
||||
done
|
||||
# exit when interface is not found
|
||||
[[ $i -eq $MAXNICS ]] && break
|
||||
@@ -461,6 +481,7 @@ if_up(){
|
||||
[[ -n ${HWADDR[$i]} ]] && run ip link set $1 addr ${HWADDR[$i]}
|
||||
set_mtu $1
|
||||
fi
|
||||
run ip link set $IFACE up
|
||||
# set interface address
|
||||
[[ $i -eq 0 && $j -eq 0 ]] && MAIN=1 || MAIN=
|
||||
if [[ $IP == ipv4 ]]; then
|
||||
@@ -490,7 +511,6 @@ if_up(){
|
||||
DHCP_KEEP_RESOLV=$DHCP6_KEEP_RESOLV
|
||||
ipaddr_up
|
||||
fi
|
||||
run ip link set $IFACE up
|
||||
done
|
||||
}
|
||||
|
||||
@@ -536,10 +556,10 @@ if_down(){
|
||||
[[ $DEBUG_ETH_UP == yes ]] && log "interface $IFACE not present, can't take down"
|
||||
fi
|
||||
done
|
||||
[[ -z ${BRNICS[$i]} ]] && macvtap_down # delete macvtap interfaces
|
||||
[[ -n ${BRNICS[$i]} ]] && br_down # delete interface as bridge
|
||||
[[ -n ${VLANS[$i]} ]] && vlan_down # delete interface VLANs
|
||||
[[ -n ${BONDNICS[$i]} ]] && bond_down # delete interface as bond
|
||||
[[ -z ${BRNICS[$i]} ]] && macvtap_down # delete macvtap interfaces
|
||||
[[ -n ${BRNICS[$i]} ]] && br_down # delete interface as bridge
|
||||
[[ -n ${VLANS[$i]} ]] && vlan_down # delete interface VLANs
|
||||
[[ -n ${BONDNICS[$i]} ]] && bond_down # delete interface as bond
|
||||
}
|
||||
|
||||
#####################
|
||||
@@ -557,8 +577,8 @@ gateway_up(){
|
||||
IP=${PROTOCOL[$x]:-ipv4}
|
||||
AD=${METRIC[$x]}
|
||||
[[ -n $AD ]] && AD="metric $AD"
|
||||
EXIST=$(ip -4 route show default via $GW dev $DEV|grep "$AD ")
|
||||
[[ $IP != ipv6 && -z $EXIST ]] && run ip -4 route add default via $GW dev $DEV $AD
|
||||
EXIST=$(ip -4 route show default via $(unzero $GW) dev $DEV|grep "$AD ")
|
||||
[[ $IP != ipv6 && -z $EXIST ]] && run ip -4 route add default via $(unzero $GW) dev $DEV $AD
|
||||
done
|
||||
for GW6 in ${GATEWAY6[@]}; do
|
||||
[[ -z $GW6 ]] && continue
|
||||
@@ -569,8 +589,8 @@ gateway_up(){
|
||||
IP=${PROTOCOL[$x]:-ipv4}
|
||||
AD6=${METRIC6[$x]}
|
||||
[[ -n $AD6 ]] && AD6="metric $AD6"
|
||||
EXIST=$(ip -6 route show default via $GW6 dev $DEV|grep "$AD6 ")
|
||||
[[ $IP != ipv4 && -z $EXIST ]] && run ip -6 route add default via $GW6 dev $DEV $AD6
|
||||
EXIST=$(ip -6 route show default via $(unzero6 $GW6) dev $DEV|grep "$AD6 ")
|
||||
[[ $IP != ipv4 && -z $EXIST ]] && run ip -6 route add default via $(unzero6 $GW6) dev $DEV $AD6
|
||||
done
|
||||
}
|
||||
|
||||
@@ -616,6 +636,13 @@ stop(){
|
||||
lo_down
|
||||
}
|
||||
|
||||
# function to show network status
|
||||
status(){
|
||||
echo "INTERFACE STATE INFORMATION"
|
||||
echo "========================================================================"
|
||||
[[ $1 == ip ]] && ip -brief addr || ip -brief link
|
||||
}
|
||||
|
||||
##########################
|
||||
# STATIC ROUTE FUNCTIONS #
|
||||
##########################
|
||||
@@ -660,50 +687,54 @@ route_down(){
|
||||
### MAIN ###
|
||||
############
|
||||
|
||||
case $1 in
|
||||
case "$1" in
|
||||
start|up)
|
||||
start
|
||||
;;
|
||||
;;
|
||||
stop|down)
|
||||
stop
|
||||
;;
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
sleep 1
|
||||
start
|
||||
;;
|
||||
;;
|
||||
*_start|*_up)
|
||||
INTERFACE=$(echo $1|cut -d_ -f1)
|
||||
if_up $INTERFACE
|
||||
gateway_up
|
||||
;;
|
||||
;;
|
||||
*_stop|*_down)
|
||||
INTERFACE=$(echo $1|cut -d_ -f1)
|
||||
if_down $INTERFACE
|
||||
;;
|
||||
;;
|
||||
*_restart)
|
||||
INTERFACE=$(echo $1|cut -d_ -f1)
|
||||
if_down $INTERFACE
|
||||
sleep 1
|
||||
if_up $INTERFACE
|
||||
gateway_up
|
||||
;;
|
||||
;;
|
||||
*_add)
|
||||
INTERFACE=$(echo $1|cut -d_ -f1)
|
||||
ROUTE=$(echo $1|cut -d_ -f2)
|
||||
METRIC=$(echo $1|cut -d_ -f3)
|
||||
[[ $METRIC == add ]] && METRIC=
|
||||
route_up $INTERFACE $ROUTE $METRIC
|
||||
;;
|
||||
;;
|
||||
*_del)
|
||||
INTERFACE=$(echo $1|cut -d_ -f1)
|
||||
ROUTE=$(echo $1|cut -d_ -f2)
|
||||
METRIC=$(echo $1|cut -d_ -f3)
|
||||
[[ $METRIC == del ]] && METRIC=
|
||||
route_down $INTERFACE $ROUTE $METRIC
|
||||
;;
|
||||
# default is to bring up the entire network
|
||||
*) start
|
||||
;;
|
||||
status)
|
||||
status $2
|
||||
;;
|
||||
# default is to bring up the entire network
|
||||
*)
|
||||
start
|
||||
esac
|
||||
|
||||
# Command examples
|
||||
@@ -719,3 +750,5 @@ esac
|
||||
# rc.inet1 10.0.0.1_default_add add default route to gateway 10.0.0.1 with metric 1
|
||||
# rc.inet1 eth0_10.0.0.0/24_1_del delete specific route & metric from interface eth0
|
||||
# rc.inet1 10.0.0.1_default_del delete default route from gateway 10.0.0.1
|
||||
# rc.inet1 status show link status
|
||||
# rc.inet1 status ip show ip status
|
||||
|
@@ -7,27 +7,49 @@
|
||||
# You can configure network interfaces other than eth0,eth1... by setting
|
||||
# IFNAME[interface] to the interface's name. If IFNAME[interface] is unset
|
||||
# or empty, it is assumed you're configuring eth<interface>.
|
||||
# =============================================================================
|
||||
|
||||
# change this to "yes" for debugging output to stdout. Unfortunately,
|
||||
# /sbin/hotplug seems to disable stdout so you'll only see debugging output
|
||||
# when rc.inet1 is called directly.
|
||||
# Adapted by Bergware for use in Unraid OS - December 2023
|
||||
# - added functions to remove leading zeros in IPv4 and IPv6 addresses
|
||||
|
||||
# LimeTech - modified for Unraid OS
|
||||
# Bergware - modified for Unraid OS, December 2023
|
||||
|
||||
# change this to "yes" for debugging output to stdout.
|
||||
# Unfortunately, /sbin/hotplug seems to disable stdout so you'll only see debugging output when rc.inet1 is called directly.
|
||||
|
||||
DEBUG_ETH_UP=no
|
||||
DHCP_DEBUG=no
|
||||
|
||||
# function to remove leading zeros in IPv4 address
|
||||
unzero(){
|
||||
local M Q
|
||||
echo -n $(for Q in ${1//./ }; do printf "$M%x" "0x$Q"; M=.; done)
|
||||
}
|
||||
|
||||
# function to remove leading zeros in IPv6 address
|
||||
unzero6(){
|
||||
local A M Q
|
||||
A=${1/::/:-:}
|
||||
echo -n $(for Q in ${A//:/ }; do [[ $Q != - ]] && printf "$M%x" "0x$Q" || printf ":"; M=:; done)
|
||||
}
|
||||
|
||||
# bergware - use associative format for multi-dimensional arrays
|
||||
declare -A VLANID USE_DHCP IPADDR NETMASK GATEWAY METRIC USE_DHCP6 IPADDR6 NETMASK6 GATEWAY6 METRIC6 PRIVACY6 DESCRIPTION PROTOCOL
|
||||
|
||||
# limetech - read settings from config file
|
||||
cfg=/boot/config/network.cfg
|
||||
if [[ -s $cfg ]]; then
|
||||
source <(/usr/bin/fromdos < $cfg)
|
||||
CFG=/boot/config/network.cfg
|
||||
if [[ -s $CFG ]]; then
|
||||
. <(fromdos <$CFG)
|
||||
else
|
||||
# default legacy settings
|
||||
IPADDR=
|
||||
NETMASK=
|
||||
GATEWAY=
|
||||
PROTOCOL=ipv4
|
||||
USE_DHCP=yes
|
||||
USE_DHCP6=
|
||||
DHCP_KEEPRESOLV=no
|
||||
DHCP6_KEEPRESOLV=no
|
||||
BONDING=yes
|
||||
BRIDGING=yes
|
||||
fi
|
||||
@@ -54,27 +76,43 @@ echo -n >$RESOLV.tail
|
||||
|
||||
if [[ $DHCP_KEEPRESOLV == yes ]]; then
|
||||
echo "# Generated by rc.inet1" >>$RESOLV
|
||||
[[ -n $DNS_SERVER1 ]] && echo "nameserver $DNS_SERVER1" >>$RESOLV
|
||||
[[ -n $DNS_SERVER2 ]] && echo "nameserver $DNS_SERVER2" >>$RESOLV
|
||||
[[ -n $DNS_SERVER3 ]] && echo "nameserver $DNS_SERVER3" >>$RESOLV
|
||||
[[ -n $DNS_SERVER4 ]] && echo "nameserver $DNS_SERVER4" >>$RESOLV
|
||||
[[ -n $DNS_SERVER1 ]] && echo "nameserver $(unzero $DNS_SERVER1)" >>$RESOLV
|
||||
[[ -n $DNS_SERVER2 ]] && echo "nameserver $(unzero $DNS_SERVER2)" >>$RESOLV
|
||||
[[ -n $DNS_SERVER3 ]] && echo "nameserver $(unzero $DNS_SERVER3)" >>$RESOLV
|
||||
[[ -n $DNS_SERVER4 ]] && echo "nameserver $(unzero $DNS_SERVER4)" >>$RESOLV
|
||||
[[ $DHCP6_KEEPRESOLV == no ]] && cp -f $RESOLV $RESOLV.head
|
||||
fi
|
||||
if [[ $DHCP6_KEEPRESOLV == yes ]]; then
|
||||
[[ $DHCP_KEEPRESOLV == no ]] && echo "# Generated by rc.inet1" >>$RESOLV
|
||||
[[ -n $DNS6_SERVER1 ]] && echo "nameserver $DNS6_SERVER1" >>$RESOLV
|
||||
[[ -n $DNS6_SERVER2 ]] && echo "nameserver $DNS6_SERVER2" >>$RESOLV
|
||||
[[ -n $DNS6_SERVER3 ]] && echo "nameserver $DNS6_SERVER3" >>$RESOLV
|
||||
[[ -n $DNS6_SERVER4 ]] && echo "nameserver $DNS6_SERVER4" >>$RESOLV
|
||||
[[ -n $DNS6_SERVER1 ]] && echo "nameserver $(unzero6 $DNS6_SERVER1)" >>$RESOLV
|
||||
[[ -n $DNS6_SERVER2 ]] && echo "nameserver $(unzero6 $DNS6_SERVER2)" >>$RESOLV
|
||||
[[ -n $DNS6_SERVER3 ]] && echo "nameserver $(unzero6 $DNS6_SERVER3)" >>$RESOLV
|
||||
[[ -n $DNS6_SERVER4 ]] && echo "nameserver $(unzero6 $DNS6_SERVER4)" >>$RESOLV
|
||||
[[ $DHCP_KEEPRESOLV == no ]] && cp -f $RESOLV $RESOLV.tail
|
||||
fi
|
||||
|
||||
make_cfg(){
|
||||
[[ -s $CFG ]] && return
|
||||
for VAR in "$@"; do
|
||||
if [[ ${VAR:0:1} == '#' ]]; then
|
||||
# add comment
|
||||
echo -ne "$VAR\r\n" >>$CFG
|
||||
elif [[ ${VAR: -1} == '#' ]]; then
|
||||
# add global variable
|
||||
VAR=${VAR::-1}
|
||||
echo -ne "$VAR=\"${!VAR}\"\r\n" >>$CFG
|
||||
else
|
||||
# add interface variable
|
||||
echo -ne "$VAR[0]=\"${!VAR}\"\r\n" >>$CFG
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
if [[ -n $SYSNICS ]]; then
|
||||
# bergware - set number of interfaces as present in the system
|
||||
MAXNICS=$SYSNICS
|
||||
else
|
||||
# bergware - legacy configuration of first interface
|
||||
MAXNICS=1
|
||||
if [[ $BONDING == yes && $BRIDGING == yes ]]; then
|
||||
# both bonding and bridging selected
|
||||
BONDNAME=bond0
|
||||
@@ -86,6 +124,7 @@ else
|
||||
BRSTP=no
|
||||
BRFD=0
|
||||
IFNAME=$BRNAME
|
||||
SETTINGS="BONDNAME BONDNICS BONDING_MODE BONDING_MIIMON BRNAME BRNICS BRSTP BRFD"
|
||||
elif [[ $BONDING == yes ]]; then
|
||||
# bonding selected
|
||||
BONDNAME=bond0
|
||||
@@ -93,6 +132,7 @@ else
|
||||
BONDING_MODE=${BONDING_MODE:-1}
|
||||
BONDING_MIIMON=${BONDING_MIIMON:-100}
|
||||
IFNAME=$BONDNAME
|
||||
SETTINGS="BONDNAME BONDNICS BONDING_MODE BONDING_MIIMON"
|
||||
elif [[ $BRIDGING == yes ]]; then
|
||||
# bridging selected
|
||||
BRNAME=br0
|
||||
@@ -100,8 +140,12 @@ else
|
||||
BRSTP=no
|
||||
BRFD=0
|
||||
IFNAME=$BRNAME
|
||||
SETTINGS="BRNAME BRNICS BRSTP BRFD"
|
||||
else
|
||||
# normal interface
|
||||
IFNAME=eth0
|
||||
fi
|
||||
SYSNICS=1
|
||||
MAXNICS=$SYSNICS
|
||||
make_cfg "# Generated settings:" IFNAME DHCP_KEEPRESOLV# DHCP6_KEEPRESOLV# $SETTINGS PROTOCOL USE_DHCP USE_DHCP6 SYSNICS#
|
||||
fi
|
||||
|
@@ -47,13 +47,13 @@ scan() {
|
||||
}
|
||||
|
||||
good() {
|
||||
data=;
|
||||
data=
|
||||
for i in ${bind[@]}; do
|
||||
[[ $i == $1 || ${1:0:4} == fe80 ]] && data=$1
|
||||
[[ $i == $1 || $1 == 0 || ${1:0:4} == fe80 ]] && data=1
|
||||
done
|
||||
if [[ -n $2 ]]; then
|
||||
for i in ${nets[@]}; do
|
||||
[[ $i == $2 || ${2:0:4} == fe80 ]] && data=$2
|
||||
[[ $i == $2 || $2 == 0 || ${2:0:4} == fe80 ]] && data=2
|
||||
done
|
||||
fi
|
||||
echo $data
|
||||
@@ -90,7 +90,7 @@ min6() {
|
||||
wipe() {
|
||||
wet=($*)
|
||||
# remove temporary (privacy extensions) and host ipv6 addresses
|
||||
for tmp in $(ip -br -6 addr show scope global temporary dev $wet 2>/dev/null|awk '{$1=$2="";print}'); do
|
||||
for tmp in $(ip -br -6 addr show scope global temporary dev $wet 2>/dev/null|sed -r 's/metric [0-9]+//g'|awk '{$1=$2="";print}'); do
|
||||
for i in ${!wet[@]}; do
|
||||
[[ ${wet[$i]} == $tmp || (${wet[$i]} =~ '::' && ${wet[$i]#*/} == 128) ]] && unset 'wet[i]'
|
||||
done
|
||||
@@ -107,7 +107,7 @@ show() {
|
||||
case $# in
|
||||
1) ip -br addr show scope global to $1 2>/dev/null|awk '{print $1;exit}';;
|
||||
2) ip -br addr show scope global $1 $2 2>/dev/null|awk '{print $3;exit}';;
|
||||
3) if [[ $1 == -6 ]]; then main $(ip -br -6 addr show scope global $2 $3 2>/dev/null|awk '{$2="";print;exit}'); else ip -br -4 addr show scope global $2 $3 2>/dev/null|awk '{print $3;exit}'; fi;;
|
||||
3) if [[ $1 == -6 ]]; then main $(ip -br -6 addr show scope global $2 $3 2>/dev/null|sed -r 's/metric [0-9]+//g'|awk '{$2="";print;exit}'); else ip -br -4 addr show scope global $2 $3 2>/dev/null|awk '{print $3;exit}'; fi;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -195,9 +195,9 @@ check() {
|
||||
# exclude wireguard VPN docker tunnels
|
||||
[[ ${net:0:2} == wg && $(grep -Pom1 '^TYPE:1="\K[^"]+' $WIREGUARD/$net.cfg) == 8 ]] && continue
|
||||
net1=$(sub ${net[1]})
|
||||
if [[ "avahi show" =~ $CALLER ]]; then
|
||||
if [[ "avahi show" =~ "$CALLER" ]]; then
|
||||
[[ -n $net && -n $net1 && -z $(good $net $net1) ]] && bind+=($net)
|
||||
[[ -n $net1 ]] && ipv4=yes nets+=($net1)
|
||||
[[ -n $net1 && $net1 != 0 ]] && ipv4=yes nets+=($net1)
|
||||
else
|
||||
[[ -n $net1 && -z $(good $net1) ]] && ipv4=yes bind+=($net1)
|
||||
fi
|
||||
@@ -211,26 +211,22 @@ check() {
|
||||
# exclude wireguard VPN docker tunnels
|
||||
[[ ${net:0:2} == wg && $(grep -Pom1 '^TYPE:1="\K[^"]+' $WIREGUARD/$net.cfg) == 8 ]] && continue
|
||||
net1=$(sub $(main ${net[@]}))
|
||||
if [[ "avahi show" =~ $CALLER ]]; then
|
||||
if [[ "avahi show" =~ "$CALLER" ]]; then
|
||||
[[ -n $net && -n $net1 && -z $(good $net $net1) ]] && bind+=($net)
|
||||
[[ -n $net1 ]] && ipv6=yes nets+=($net1)
|
||||
[[ -n $net1 && $net1 != 0 ]] && ipv6=yes nets+=($net1)
|
||||
else
|
||||
[[ -z $deny6 && -n $net1 && -z $(good $net1) ]] && ipv6=yes bind+=($net1)
|
||||
fi
|
||||
done <<< $(ip -br -6 addr show scope global|awk '/^(br|bond|eth|wg)[0-9]+(\.[0-9]+)?/{$2="";print}'|sort)
|
||||
done <<< $(ip -br -6 addr show scope global|sed -r 's/metric [0-9]+//g'|awk '/^(br|bond|eth|wg)[0-9]+(\.[0-9]+)?/{$2="";print}'|sort)
|
||||
# add loopback interface
|
||||
if [[ "smb nfs" =~ $CALLER ]]; then
|
||||
if [[ "smb nfs" =~ "$CALLER" ]]; then
|
||||
[[ $ipv4 == yes ]] && bind+=(127.0.0.1)
|
||||
[[ $ipv6 == yes ]] && bind+=(::1)
|
||||
fi
|
||||
# add user defined interfaces
|
||||
if [[ -f $EXTRA ]]; then
|
||||
. <(/usr/bin/fromdos <$EXTRA)
|
||||
if [[ "avahi show" =~ $CALLER ]]; then
|
||||
extra_name
|
||||
else
|
||||
extra_addr
|
||||
fi
|
||||
. <(fromdos <$EXTRA)
|
||||
[[ "avahi show" =~ "$CALLER" ]] && extra_name || extra_addr
|
||||
fi
|
||||
if [[ $CALLER == ssh ]]; then
|
||||
# bind stays array
|
||||
|
@@ -172,17 +172,23 @@ start_libvirtd() {
|
||||
echo "no image mounted at /etc/libvirt"
|
||||
exit 1
|
||||
fi
|
||||
# convert libvirt 1.3.1 w/ eric's hyperv vendor id patch to how libvirt does it in libvirt 1.3.3+
|
||||
sed -ri "s/<vendor id='none'\/>/<vendor_id state='on' value='none'\/>/g" /etc/libvirt/qemu/*.xml &> /dev/null
|
||||
# remove <locked/> from xml because libvirt + virlogd + virlockd has an issue with locked
|
||||
sed -ri "s/<locked\/>//g" /etc/libvirt/qemu/*.xml &> /dev/null
|
||||
# Remove "<watchdog model='itco' action='reset'/>" if reverting from later release.
|
||||
. /etc/unraid-version
|
||||
if [[ $(version $version) -le $(version "6.12") ]]; then
|
||||
sed -ri "/<watchdog model='itco' action='reset'\/>/d" /etc/libvirt/qemu/*.xml &> /dev/null
|
||||
fi
|
||||
[[ $(version $version) -le $(version "6.12") ]] && LEGACY=1 || LEGACY=
|
||||
# update interface section((s) of VM configuration files
|
||||
for XML in /etc/libvirt/qemu/*.xml; do
|
||||
[[ -f "$XML" ]] || continue
|
||||
if grep -qm1 "<vendor_id='none'/>" "$XML"; then
|
||||
# convert libvirt 1.3.1 w/ eric's hyperv vendor id patch to how libvirt does it in libvirt 1.3.3+
|
||||
sed -ri "s/<vendor id='none'\/>/<vendor_id state='on' value='none'\/>/g" "$XML"
|
||||
fi
|
||||
if grep -qm1 "<locked/>" "$XML"; then
|
||||
# remove <locked/> from xml because libvirt + virlogd + virlockd has an issue with locked
|
||||
sed -ri "/<locked\/>/d" "$file"
|
||||
fi
|
||||
if [[ -n $LEGACY ]] && grep -qm1 "<watchdog model='itco' action='reset'/>" "$XML"; then
|
||||
# Remove "<watchdog model='itco' action='reset'/>" if reverting from later release.
|
||||
sed -ri "/<watchdog model='itco' action='reset'\/>/d" "$XML"
|
||||
fi
|
||||
# get all interface sections
|
||||
ROW=($(grep -nhP '<interface type=' "$XML"|grep -Pom1 '^[0-9]+'))
|
||||
# get all source sections
|
||||
@@ -193,13 +199,17 @@ start_libvirtd() {
|
||||
if [[ ! -e $SYSTEM/$DEV ]]; then
|
||||
NAME=${DEV//[0-9.]/}
|
||||
if [[ $NAME == br ]]; then
|
||||
# change to macvtap
|
||||
logger -t $(basename $0) "change $DEV to macvtap in $XML"
|
||||
sed -ri "${ROW[$i]} s/<interface type='bridge'>/<interface type='direct' trustGuestRxFilters='yes'>/; $ROW2 s/<source bridge='$DEV'\/>/<source dev='${DEV/$NAME/vhost}' mode='bridge'\/>/" "$XML"
|
||||
if grep -qm1 "<interface type='bridge'>" "$XML"; then
|
||||
# change to macvtap
|
||||
logger -t $(basename $0) "change $DEV to macvtap in $XML"
|
||||
sed -ri "${ROW[$i]} s/<interface type='bridge'>/<interface type='direct' trustGuestRxFilters='yes'>/; $ROW2 s/<source bridge='$DEV'\/>/<source dev='${DEV/$NAME/vhost}' mode='bridge'\/>/" "$XML"
|
||||
fi
|
||||
else
|
||||
# change to bridge
|
||||
logger -t $(basename $0) "change $DEV to bridge in $XML"
|
||||
sed -ri "${ROW[$i]} s/<interface type='direct'( trustGuestRxFilters='yes')?>/<interface type='bridge'>/; $ROW2 s/<source dev='$DEV' mode='bridge'\/>/<source bridge='${DEV/$NAME/br}'\/>/" "$XML"
|
||||
if grep -qm1 "<interface type='direct'" "$XML"; then
|
||||
# change to bridge
|
||||
logger -t $(basename $0) "change $DEV to bridge in $XML"
|
||||
sed -ri "${ROW[$i]} s/<interface type='direct'( trustGuestRxFilters='yes')?>/<interface type='bridge'>/; $ROW2 s/<source dev='$DEV' mode='bridge'\/>/<source bridge='${DEV/$NAME/br}'\/>/" "$XML"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
@@ -10,9 +10,7 @@
|
||||
# LANNAME 'tower'
|
||||
# LANMDNS 'tower.local'
|
||||
# LANFQDN 'lan-ip.hash.myunraid.net' (wildcard cert)
|
||||
# LANFQDN 'hash.unraid.net' (legacy cert)
|
||||
# WANFQDN 'wan-ip.hash.myunraid.net' (wildcard cert)
|
||||
# WANFQDN 'www.hash.unraid.net' (legacy)
|
||||
# WG0FQDN 'wg0-ip.hash.myunraid.net' (wildcard cert)
|
||||
|
||||
CALLER="nginx"
|
||||
@@ -41,6 +39,12 @@ SERVER_NAMES=()
|
||||
[[ $PORTSSL != 443 ]] && PORTSSL_URL=":$PORTSSL"
|
||||
[[ $PORT != 80 ]] && PORT_URL=":$PORT"
|
||||
|
||||
# delete legacy unraid.net certificate
|
||||
if [[ -f $CERTPATH ]]; then
|
||||
TMPCERTNAME=$(openssl x509 -noout -subject -nameopt multiline -in $CERTPATH | sed -n 's/ *commonName *= //p')
|
||||
[[ $TMPCERTNAME == *\.unraid\.net ]] && rm $CERTPATH
|
||||
fi
|
||||
|
||||
# if USE_SSL="auto" and no uploaded cert, treat like USE_SSL="no"
|
||||
[[ $USE_SSL == auto && ! -f $CERTPATH ]] && USE_SSL=no
|
||||
|
||||
@@ -252,7 +256,6 @@ build_servers() {
|
||||
#
|
||||
# Port settings for https using CA-signed cert
|
||||
# ex: https://lan-ip.hash.myunraid.net
|
||||
# ex: https://hash.unraid.net
|
||||
#
|
||||
server {
|
||||
$(listen $PORTSSL ssl http2)
|
||||
@@ -491,15 +494,7 @@ build_ssl() {
|
||||
WANIP=$(curl https://wanip4.unraid.net/ 2>/dev/null)
|
||||
WANIP6=$(curl https://wanip6.unraid.net/ 2>/dev/null)
|
||||
fi
|
||||
if [[ $CERTNAME == *\.unraid\.net ]]; then
|
||||
# legacy LE certificate (only supports IPv4)
|
||||
LANFQDN=$CERTNAME
|
||||
SERVER_NAMES+=($LANFQDN)
|
||||
if [[ -n $WANACCESS && -n $WANIP ]]; then
|
||||
WANFQDN="www.$CERTNAME"
|
||||
SERVER_NAMES+=($WANFQDN)
|
||||
fi
|
||||
elif [[ $CERTNAME == *\.myunraid\.net ]]; then
|
||||
if [[ $CERTNAME == *\.myunraid\.net ]]; then
|
||||
# wildcard LE certificate
|
||||
[[ -n $LANIP ]] && LANFQDN=$(fqdn $LANIP) SERVER_NAMES+=($LANFQDN)
|
||||
[[ -n $LANIP6 ]] && LANFQDN6=$(fqdn $LANIP6) SERVER_NAMES+=($LANFQDN6)
|
||||
@@ -577,6 +572,7 @@ build_ssl() {
|
||||
}
|
||||
|
||||
nginx_status() {
|
||||
sleep 0.1
|
||||
[[ -s $PID && -n "$(cat $PID)" && -d "/proc/$(cat $PID)" ]] && return 0 || return 1;
|
||||
}
|
||||
|
||||
@@ -643,6 +639,11 @@ nginx_stop() {
|
||||
unraid_api_control stop
|
||||
kill -QUIT $(cat $PID)
|
||||
wait_nginx_shutdown
|
||||
if nginx_status; then
|
||||
echo "Killing Nginx..."
|
||||
pkill -f $NGINX
|
||||
wait_nginx_shutdown
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -675,8 +676,6 @@ nginx_reload() {
|
||||
if nginx_check; then
|
||||
echo "Reloading Nginx configuration..."
|
||||
kill -HUP $(cat $PID)
|
||||
# update DNS
|
||||
/usr/bin/php -f /usr/local/emhttp/webGui/include/UpdateDNS.php
|
||||
sleep 3
|
||||
else
|
||||
echo "Invalid configuration, Nginx not reloaded"
|
||||
@@ -692,8 +691,6 @@ nginx_renew() {
|
||||
build_ssl
|
||||
# start unconditionally
|
||||
$NGINX -c $CONF 2>/dev/null
|
||||
# update DNS
|
||||
/usr/bin/php -f /usr/local/emhttp/webGui/include/UpdateDNS.php
|
||||
}
|
||||
|
||||
nginx_update() {
|
||||
|
@@ -221,7 +221,7 @@ done
|
||||
|
||||
logger -t network "hook services: 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
|
||||
@@ -235,8 +235,8 @@ if [[ -z $interface || "eth0 br0 bond0" =~ $interface ]]; then
|
||||
# find management interface
|
||||
[[ -e /sys/class/net/bond0 ]] && dev=bond0 || dev=eth0
|
||||
[[ -e /sys/class/net/br0 ]] && dev=br0
|
||||
IPv4=$(ip -br -4 addr show $dev scope global|awk '{print $3;exit}')
|
||||
IPv6=$(ip -br -6 addr show $dev scope global|awk '{print $NF;exit}')
|
||||
IPv4=$(ip -br -4 addr show $dev scope global|sed -r 's/ metric [0-9]+//g'|awk '{print $3;exit}')
|
||||
IPv6=$(ip -br -6 addr show $dev scope global|sed -r 's/ metric [0-9]+//g'|awk '{print $NF;exit}')
|
||||
[[ -n $IPv4 ]] && echo " IPv4 address: ${IPv4%/*}">>/etc/issue || echo " IPv4 address: not set">>/etc/issue
|
||||
[[ -n $IPv6 ]] && echo " IPv6 address: ${IPv6%/*}">>/etc/issue || echo " IPv6 address: not set">>/etc/issue
|
||||
echo >>/etc/issue
|
||||
|
@@ -15,7 +15,7 @@ while :; do
|
||||
# steady state?
|
||||
subs=$(curl --unix-socket $nginx $status 2>/dev/null|grep -Pom1 'subscribers: \K\d+')
|
||||
if [[ -z $subs || $subs -eq 0 ]]; then
|
||||
logger -t monitor "Stop running nchan processes"
|
||||
# logger -t monitor "Stop running nchan processes"
|
||||
# kill GUI registered nchan processes
|
||||
while IFS=$'\n' read -r running; do
|
||||
pkill -f $docroot/${running/:stop/}
|
||||
|
@@ -38,3 +38,5 @@ mkdir -p "$CFG_NEW"
|
||||
# stating with 6.10 'USE_SSL="auto"' without a LE cert is invalid
|
||||
[[ ! -f /boot/config/ssl/certs/certificate_bundle.pem ]] && sed -i s/USE_SSL=\"auto\"/USE_SSL=\"no\"/ /boot/config/ident.cfg
|
||||
|
||||
# delete any temp dir left over from a version downgrade (see dynamix.plugin.manager/include/Downgrade.php)
|
||||
rm -rf /boot/deletemedowngrade.*
|
||||
|
Reference in New Issue
Block a user