mirror of
https://github.com/unraid/api.git
synced 2026-01-28 19:49:08 -06:00
2125 lines
74 KiB
XML
2125 lines
74 KiB
XML
<?xml version='1.0' standalone='yes'?>
|
||
|
||
<!DOCTYPE PLUGIN [
|
||
<!ENTITY name "dynamix.unraid.net">
|
||
<!ENTITY launch "Unraid.net">
|
||
<!ENTITY author "limetech">
|
||
<!ENTITY version "{{ plg_version }}">
|
||
<!ENTITY node_api_version "{{ node_api_version }}">
|
||
<!ENTITY env "{{ env }}">
|
||
<!ENTITY pluginURL "https://s3.amazonaws.com/dnld.lime-technology.com/unraid-api/&name;.plg">
|
||
<!ENTITY node-api "https://s3.amazonaws.com/dnld.lime-technology.com/unraid-api/unraid-node-api-&node_api_version;.tgz">
|
||
]>
|
||
|
||
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="&pluginURL;" launch="&launch;" support="https://forums.unraid.net" min="6.9.0-beta35" icon="globe">
|
||
|
||
<CHANGES>
|
||
##&name;
|
||
|
||
###&version;
|
||
- initial release
|
||
</CHANGES>
|
||
|
||
<!-- check for plugin update -->
|
||
<FILE Run="/bin/bash" Method="install remove">
|
||
<INLINE>
|
||
if [ -e /etc/rc.d/rc.unraid-api ]; then
|
||
/etc/rc.d/rc.flash_backup stop
|
||
/etc/rc.d/rc.unraid-api uninstall
|
||
rm -f /etc/rc.d/rc.unraid-api
|
||
rm -f /etc/rc.d/rc.flash_backup
|
||
mv -f /usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php- /usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php
|
||
mv -f /usr/local/emhttp/plugins/dynamix/Registration.page- /usr/local/emhttp/plugins/dynamix/Registration.page
|
||
mv -f /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php- /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
|
||
mv -f /usr/local/emhttp/plugins/dynamix/DisplaySettings.page- /usr/local/emhttp/plugins/dynamix/DisplaySettings.page
|
||
rm -rf /boot/config/plugins/Unraid.net/wc
|
||
rm -f /boot/config/plugins/Unraid.net/unraid-node-api.tgz
|
||
rm -f /boot/config/plugins/Unraid.net/.gitignore
|
||
rm -rf /usr/local/emhttp/plugins/dynamix.unraid.net
|
||
rm -f /usr/local/emhttp/webGui/javascript/vue.js
|
||
rm -f /usr/local/emhttp/webGui/javascript/vue.min.js
|
||
rm -rf /usr/local/emhttp/webGui/wc
|
||
fi
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix.unraid.net/include/state.php">
|
||
<INLINE>
|
||
<![CDATA[
|
||
<?PHP
|
||
/* Copyright 2005-2020, Lime Technology
|
||
* Copyright 2012-2020, Bergware International.
|
||
*
|
||
* This program is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU General Public License version 2,
|
||
* as published by the Free Software Foundation.
|
||
*
|
||
* The above copyright notice and this permission notice shall be included in
|
||
* all copies or substantial portions of the Software.
|
||
*/
|
||
?>
|
||
<?
|
||
$docroot = $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";
|
||
|
||
$var = (array)parse_ini_file('state/var.ini');
|
||
$license_state = strtoupper(empty($var['regCheck']) ? $var['regTy'] : $var['regCheck']);
|
||
$key_contents = str_replace(['+','/','='], ['-','_',''], trim(base64_encode(@file_get_contents($var['regFILE']))));
|
||
|
||
if (file_exists('/boot/config/plugins/dynamix/dynamix.cfg')) {
|
||
extract(parse_ini_file('/boot/config/plugins/dynamix/dynamix.cfg',true));
|
||
}
|
||
if (empty($remote)) {
|
||
$remote = [
|
||
"apikey" => "",
|
||
"username" => "",
|
||
"avatar" => "",
|
||
"wanaccess" => "no",
|
||
"wanport" => "443"
|
||
];
|
||
}
|
||
if (empty($remote['username'])) {
|
||
$remote['username'] = '';
|
||
}
|
||
if (empty($remote['avatar'])) {
|
||
$remote['avatar'] = '';
|
||
}
|
||
|
||
$arr = [];
|
||
$arr['event'] = 'STATE';
|
||
$arr['ts'] = time();
|
||
$arr['deviceCount'] = $var['deviceCount'];
|
||
$arr['guid'] = $var['flashGUID'];
|
||
$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['serverip'] = $_SERVER['SERVER_ADDR'];
|
||
$arr['internalip'] = $_SERVER['SERVER_ADDR'];
|
||
$arr['internalport'] = $_SERVER['SERVER_PORT'];
|
||
$arr['protocol'] = $_SERVER['REQUEST_SCHEME'];
|
||
$arr['registered'] = empty($remote['apikey']) || empty($var['regFILE']) ? 0 : 1;
|
||
$arr['username'] = $remote['username'];
|
||
$arr['avatar'] = $remote['avatar'];
|
||
$arr['locale'] = $_SESSION['locale'] ? $_SESSION['locale'] : 'en_US';
|
||
|
||
echo json_encode($arr);
|
||
?>
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<!-- node-api -->
|
||
<FILE Name="/boot/config/plugins/Unraid.net/unraid-node-api.tgz">
|
||
<URL>&node-api;</URL>
|
||
</FILE>
|
||
<!-- env -->
|
||
<FILE Name="/boot/config/plugins/Unraid.net/env">
|
||
<INLINE>env="&env;"</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Run="/bin/bash" Method="install">
|
||
<INLINE>
|
||
if [ "&env;" = "production" ] || [ ! -f /boot/config/plugins/Unraid.net/env ]; then
|
||
echo 'env="&env;"' > /boot/config/plugins/Unraid.net/env
|
||
fi
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Name="/etc/rc.d/rc.unraid-api" Mode="0755">
|
||
<INLINE>
|
||
<![CDATA[
|
||
#!/bin/bash
|
||
# unraid-api-handler
|
||
source /boot/config/plugins/Unraid.net/env
|
||
downloads=(node-api)
|
||
node_base_directory="/usr/local/bin/node"
|
||
|
||
# Only allow specific envs
|
||
if [ "$env" != "staging" ] && [ "$env" != "production" ]; then
|
||
echo "\"$env\" is an unsupported env. Please use \"staging\" or \"production\"."
|
||
exit 1
|
||
fi
|
||
|
||
status() {
|
||
local node_api_pid=$(pidof node-api | awk '{print $1}')
|
||
if [[ $node_api_pid ]]; then
|
||
echo "Unraid-api is running in $env mode."
|
||
else
|
||
echo "No processes are running."
|
||
fi
|
||
}
|
||
switchenv() {
|
||
# Get current environment from file
|
||
local envFile="/boot/config/plugins/Unraid.net/env"
|
||
local currentEnv=$(source $envFile; echo "$env";)
|
||
|
||
if [[ $currentEnv = "production" ]]; then
|
||
echo "Switching from production to staging"
|
||
echo 'env="staging"' > $envFile
|
||
cp $node_base_directory/node-api/.env.staging $node_base_directory/node-api/.env
|
||
elif [[ $currentEnv = "staging" ]]; then
|
||
echo "Switching from staging to production"
|
||
echo 'env="production"' > $envFile
|
||
cp $node_base_directory/node-api/.env.production $node_base_directory/node-api/.env
|
||
fi
|
||
source $envFile;
|
||
reload
|
||
}
|
||
_start() {
|
||
_stop
|
||
local old_working_directory=$(echo $pwd)
|
||
mkdir -p $node_base_directory
|
||
cd $node_base_directory
|
||
|
||
# Local .env
|
||
if [ -f $node_base_directory/node-api/.env ]; then
|
||
# Load Environment Variables
|
||
export $(egrep -v '^#' $node_base_directory/node-api/.env | xargs)
|
||
fi
|
||
|
||
# Start node-api
|
||
ENVIRONMENT=$(echo $env) node $node_base_directory/node-api/index.js &> /dev/null &
|
||
cd $old_working_directory
|
||
|
||
# wait until node_api_pid exists
|
||
for i in {1..10}; do
|
||
local node_api_pid=$(pidof node-api | awk '{print $1}')
|
||
if [ -n "$node_api_pid" ]; then
|
||
break
|
||
fi
|
||
sleep 1
|
||
done
|
||
}
|
||
start() {
|
||
echo "Starting Unraid-api"
|
||
_start
|
||
status
|
||
exit 0
|
||
}
|
||
_node_api_version() {
|
||
# Borrowed from https://gist.github.com/DarrenN/8c6a5b969481725a4413
|
||
local version=$(grep '"version"' $node_base_directory/node-api/package.json | cut -d '"' -f 4)
|
||
echo "v$version"
|
||
}
|
||
report() {
|
||
cat << EOF
|
||
<-----UNRAID-API-REPORT----->
|
||
Env $env
|
||
Node API $(_node_api_version)
|
||
Unraid v$(source /etc/unraid-version; echo "$version";)
|
||
</----UNRAID-API-REPORT----->
|
||
EOF
|
||
}
|
||
startdebug() {
|
||
_stop
|
||
local old_working_directory=$(echo $pwd)
|
||
mkdir -p $node_base_directory
|
||
|
||
# Local .env
|
||
if [ -f $node_base_directory/node-api/.env ]; then
|
||
# Load Environment Variables
|
||
export $(egrep -v '^#' $node_base_directory/node-api/.env | xargs)
|
||
fi
|
||
|
||
# Start node-api
|
||
ENVIRONMENT=$(echo $env) DEBUG=true node $node_base_directory/node-api/index.js
|
||
}
|
||
changeloglevel() {
|
||
kill -USR2 $(pidof node-api)
|
||
}
|
||
_stop() {
|
||
local node_api_pid=$(pidof node-api | awk '{print $1}')
|
||
if [[ $node_api_pid ]]; then
|
||
local parent_pid=$(cat /proc/$node_api_pid/status | grep PPid | cut -f2)
|
||
if [[ $parent_pid != 1 ]]; then
|
||
kill -9 $parent_pid &> /dev/null
|
||
else
|
||
kill -9 $node_api_pid &> /dev/null
|
||
fi
|
||
# wait until node_api_pid no longer exists
|
||
for i in {1..10}; do
|
||
node_api_pid=$(pidof node-api | awk '{print $1}')
|
||
if [ -z "$node_api_pid" ]; then
|
||
break
|
||
fi
|
||
sleep 1
|
||
done
|
||
fi
|
||
}
|
||
stop() {
|
||
echo "Stopping Unraid-api"
|
||
_stop
|
||
status
|
||
exit 0
|
||
}
|
||
reload() {
|
||
echo "Reloading Unraid-api"
|
||
_stop
|
||
rm -f /var/run/unraid-api.sock
|
||
_start
|
||
status
|
||
exit 0
|
||
}
|
||
_install() {
|
||
# Install node-api
|
||
for download in ${downloads[@]}; do
|
||
rm -rf $node_base_directory/${download}
|
||
mkdir -p $node_base_directory/${download}
|
||
tar -C $node_base_directory/${download} -xzf /boot/config/plugins/Unraid.net/unraid-${download}.tgz --strip 1
|
||
done
|
||
|
||
# Copy across wc files
|
||
rm -rf /usr/local/emhttp/webGui/wc
|
||
mkdir -p /usr/local/emhttp/webGui/wc
|
||
cp /boot/config/plugins/Unraid.net/wc/* /usr/local/emhttp/webGui/wc
|
||
}
|
||
install() {
|
||
# Stop old process
|
||
_stop
|
||
|
||
# Install the files
|
||
_install
|
||
|
||
# Start new process
|
||
_start
|
||
|
||
# Wait for inital process to boot
|
||
sleep 2
|
||
|
||
# Print status and exit
|
||
status
|
||
exit 0
|
||
}
|
||
uninstall() {
|
||
stop
|
||
for download in ${downloads[@]}; do
|
||
rm -rf $node_base_directory/${download}
|
||
done
|
||
rm -f /var/run/unraid-api.sock
|
||
}
|
||
case "$1" in
|
||
'status')
|
||
status
|
||
;;
|
||
'start')
|
||
start
|
||
;;
|
||
'_start')
|
||
_start
|
||
;;
|
||
'report')
|
||
report
|
||
;;
|
||
'switch-env')
|
||
switchenv
|
||
;;
|
||
'start-debug')
|
||
startdebug
|
||
;;
|
||
'change-log-level')
|
||
changeloglevel
|
||
;;
|
||
'stop')
|
||
stop
|
||
;;
|
||
'reload')
|
||
reload
|
||
;;
|
||
'install')
|
||
install
|
||
;;
|
||
'_install')
|
||
_install
|
||
;;
|
||
'uninstall')
|
||
uninstall
|
||
;;
|
||
*)
|
||
echo "usage $0 status|start|report|switch-env|start-debug|change-log-level|stop|reload|install|uninstall"
|
||
esac
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<!-- README FILE -->
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix.unraid.net/README.md">
|
||
<INLINE>
|
||
**Unraid.net**
|
||
|
||
Unraid.net provides access to a set web-based services:
|
||
|
||
* Server status such as online/offline, storage used/available, etc.
|
||
* Links for local and remote access to your server webGUI.
|
||
* Backup and Restore of your USB Flash boot device.
|
||
* much more to come
|
||
|
||
A server is registered using your Unraid Community Forum credentials. Registered servers appear under the My Servers forum sub-menu.
|
||
|
||
This is work in progress. Use this for testing purposes only!
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix.unraid.net/Unraid.net.page">
|
||
<INLINE>
|
||
<![CDATA[
|
||
Menu="ManagementAccess:100"
|
||
Title="Unraid.net"
|
||
Icon="icon-u-globe"
|
||
Tag="globe"
|
||
---
|
||
<?PHP
|
||
/* Copyright 2005-2018, Lime Technology
|
||
* Copyright 2012-2018, 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.
|
||
*/
|
||
?>
|
||
<?
|
||
// more:
|
||
// - if someone deletes the dynamic.cfg or directly edits [remote] section therein, it may be possible
|
||
// that server will appear 'unregistered' in webgui but not on My Servers.
|
||
// - appears someone could register, enable remote access, then unregister, replace the ssl cert, and
|
||
// now can remotely access using url that matches their cert. This is probably a bug here, but we might
|
||
// want to rework this somewhat to explicitly enable this 'feature' (remote access using user-provided cert).
|
||
|
||
$keyfile = @file_get_contents($var['regFILE']);
|
||
if ($keyfile !== false)
|
||
$keyfile = @base64_encode($keyfile);
|
||
|
||
if (empty($remote)) {
|
||
$remote = [
|
||
"apikey" => "",
|
||
"wanaccess" => "no",
|
||
"wanport" => "443"
|
||
];
|
||
}
|
||
if (empty($remote['wanport'])) {
|
||
$remote['wanport'] = 443;
|
||
}
|
||
|
||
$hasCert = $var['USE_SSL']!='no' &&
|
||
file_exists('/boot/config/ssl/certs/certificate_bundle.pem') &&
|
||
preg_match('/[0-9a-f]{40}\.unraid\.net$/', exec('openssl x509 -in /boot/config/ssl/certs/certificate_bundle.pem -subject -noout 2>&1'));
|
||
$isRegistered = !empty($remote['apikey']);
|
||
$boolWebUIAuth = $isRegistered && file_exists('/etc/nginx/htpasswd');
|
||
?>
|
||
<script>
|
||
function registerServer(button) {
|
||
var oldlabel = $.trim($(button).text());
|
||
|
||
var failure = function(data) {
|
||
var status = data.status;
|
||
var obj = data.responseJSON;
|
||
var msg = "Sorry, an error ("+status+") occurred registering this server. " +
|
||
"The error is: "+obj.error+".";
|
||
$(button).prop("disabled", false).html(oldlabel);
|
||
swal('Oops',msg,'error');
|
||
};
|
||
|
||
var success = function(data) {
|
||
if (data.apikey) {
|
||
$(button).prop("disabled", false).html(oldlabel);
|
||
$.post('/webGui/include/Dispatcher.php',{
|
||
"#cfg": "/boot/config/plugins/dynamix/dynamix.cfg",
|
||
"remote_apikey": data.apikey,
|
||
"remote_wanaccess": $('#wanaccess').val(),
|
||
"remote_wanport": $('#wanport').val()
|
||
},function(data2) {
|
||
<?if(!$isRegistered):?>
|
||
swal({title:"",text:"Your server has been registered",type:"success",allowEscapeKey:false},function(){button.form.submit();});
|
||
<?else:?>
|
||
button.form.submit();
|
||
<?endif?>
|
||
});
|
||
} else {
|
||
failure({"status": 403, "responseJSON": {"error": "Unable to register this Unraid Server"}});
|
||
}
|
||
};
|
||
|
||
$(button).prop("disabled", true).html("<i class=\"fa fa-spinner fa-spin\" aria-hidden=\"true\"></i> "+oldlabel+"ing");
|
||
$.post("/webGui/include/UpdateDNS.php",{username:$('#ips_username').val(),password:$('#ips_password').val(),externalport:$('#wanport').val(),remoteaccess:$('#wanaccess').val()},success).fail(failure);
|
||
}
|
||
|
||
function unregisterServer(button) {
|
||
var oldlabel = $.trim($(button).text());
|
||
|
||
var failure = function(data) {
|
||
var status = data.status;
|
||
var obj = data.responseJSON;
|
||
var msg = "Sorry, an error ("+status+") occurred unregistering this server. " +
|
||
"The error is: "+obj.error+".";
|
||
$(button).prop("disabled", false).html(oldlabel);
|
||
swal('Oops',msg,'error');
|
||
};
|
||
|
||
var success = function(data) {
|
||
$.post('/webGui/include/Dispatcher.php',{
|
||
"#cfg": "/boot/config/plugins/dynamix/dynamix.cfg",
|
||
"remote_apikey": "",
|
||
"remote_wanaccess": $('#wanaccess').val(),
|
||
"remote_wanport": $('#wanport').val()
|
||
});
|
||
$(button).prop("disabled", false).html(oldlabel);
|
||
swal({title:"",text:"Your server has been unregistered",type:"success",allowEscapeKey:false},function(){button.form.submit();});
|
||
};
|
||
|
||
swal({title:"Remove Registration",text:"Are you sure you want to unregister your server?",type:'warning',confirmButtonText:'Unregister',showCancelButton:true},function(){
|
||
$(button).prop("disabled", true).html("<i class=\"fa fa-spinner fa-spin\" aria-hidden=\"true\"></i> "+oldlabel+"ing");
|
||
$.post("https://keys.lime-technology.com/account/server/unregister",{keyfile:"<?=$keyfile?>"},success).fail(failure);
|
||
});
|
||
}
|
||
|
||
function dnsCheckServer(button) {
|
||
var oldlabel = $.trim($(button).text());
|
||
|
||
var failure = function(data) {
|
||
var status = data.status;
|
||
var obj = data.responseJSON;
|
||
var msg = "Sorry, an error ("+status+") occurred checking this server. " +
|
||
"The error is: "+obj.error+".";
|
||
$(button).prop("disabled", false).html(oldlabel);
|
||
swal('Oops',msg,'error');
|
||
};
|
||
|
||
var success = function(data) {
|
||
$(button).prop("disabled", false).html(oldlabel);
|
||
if (data.status) {
|
||
swal("","Your Unraid Server is reachable from the internet","success");
|
||
} else {
|
||
swal("Oops","This Unraid Server was unreachable from the outside","error");
|
||
}
|
||
};
|
||
|
||
$(button).prop("disabled", true).html("<i class=\"fa fa-spinner fa-spin\" aria-hidden=\"true\"></i> "+oldlabel+"ing");
|
||
$.post("https://keys.lime-technology.com/account/server/checkdns",{externalport:$('#wanport').val(),keyfile:"<?=$keyfile?>"},success).fail(failure);
|
||
}
|
||
|
||
function changeRemoteAccess(dropdown) {
|
||
if ($(dropdown).val() == 'yes') {
|
||
$("#wanpanel").slideDown('fast');
|
||
} else {
|
||
$("#wanpanel").slideUp('fast');
|
||
}
|
||
}
|
||
|
||
function enableFlashBackup(button) {
|
||
var oldlabel = $.trim($(button).text());
|
||
|
||
var failure = function(data) {
|
||
var status = data.status;
|
||
var obj = data.responseJSON;
|
||
var msg = "Sorry, an error ("+status+") occurred enabling Flash backup. " +
|
||
"The error is: "+obj.error+".";
|
||
$(button).prop("disabled", false).html(oldlabel);
|
||
swal({title:"",text:msg,type:"error",allowEscapeKey:false},function(){button.form.submit();});
|
||
};
|
||
|
||
var success = function(data) {
|
||
$(button).prop("disabled", false).html(oldlabel);
|
||
button.form.submit();
|
||
};
|
||
|
||
if (oldlabel == 'Activate') {
|
||
$(button).prop("disabled", true).html("<i class=\"fa fa-spinner fa-spin\" aria-hidden=\"true\"></i> Activating");
|
||
$.post("/plugins/dynamix.unraid.net/include/UpdateFlashBackup.php",{command:"activate"},success).fail(failure);
|
||
}
|
||
if (oldlabel == 'Deactivate') {
|
||
swal({title:"Deactivate",text:"Are you sure you want pause communication with your remote flash backup on unraid.net?",type:'warning',confirmButtonText:'Deactivate',showCancelButton:true},function(){
|
||
$(button).prop("disabled", true).html("<i class=\"fa fa-spinner fa-spin\" aria-hidden=\"true\"></i> Deactivating");
|
||
$.post("/plugins/dynamix.unraid.net/include/UpdateFlashBackup.php",{command:"deactivate"},success).fail(failure);
|
||
});
|
||
}
|
||
if (oldlabel == 'Update') {
|
||
$(button).prop("disabled", true).html("<i class=\"fa fa-spinner fa-spin\" aria-hidden=\"true\"></i> Updating");
|
||
$.post("/plugins/dynamix.unraid.net/include/UpdateFlashBackup.php",{command:"flush"},success).fail(failure);
|
||
}
|
||
if (oldlabel == 'Reinitialize') {
|
||
swal({title:"Reinitialize",text:"Are you sure you want erase all change history in both local and unraid.net remote?",type:'warning',confirmButtonText:'Reinitialize',showCancelButton:true},function(){
|
||
$(button).prop("disabled", true).html("<i class=\"fa fa-spinner fa-spin\" aria-hidden=\"true\"></i> Reinitializing");
|
||
$.post("/plugins/dynamix.unraid.net/include/UpdateFlashBackup.php",{command:"reinit"},success).fail(failure);
|
||
});
|
||
}
|
||
if (oldlabel == 'Changes') {
|
||
openBox("/webGui/include/gitstatus.php", "Changes", 600,600, false);
|
||
}
|
||
}
|
||
|
||
function buttonStateReset(newstate) {
|
||
$('#loadingpanel,#inactivespanel,#activepanel,#changespanel,#uptodatepanel').hide();
|
||
|
||
if (newstate['loading'] && newstate['loading']!='') {
|
||
$('#loadingtext').text(newstate['loading']);
|
||
$('#loadingpanel').show();
|
||
return;
|
||
}
|
||
|
||
if (newstate['activated'] == 'true') {
|
||
$('#activepanel').show();
|
||
|
||
if (newstate['uptodate'] == 'true') {
|
||
$('#uptodatepanel').show();
|
||
} else {
|
||
$('#changespanel').show();
|
||
}
|
||
} else {
|
||
$('#inactivespanel').show();
|
||
}
|
||
}
|
||
$.post('/plugins/dynamix.unraid.net/include/UpdateFlashBackup.php',{command:"status"});
|
||
</script>
|
||
|
||
<form id="UnraidNetSettings" markdown="1" name="UnraidNetSettings" method="POST" action="/update.htm" target="progressFrame">
|
||
Unraid.net Status:
|
||
: <unraid-authed registered="<? echo $isRegistered ?>"></unraid-authed>
|
||
|
||
<?if($isRegistered):?>
|
||
Allow Remote Access:
|
||
<?if(!$hasCert):?>
|
||
: <span><i class="fa fa-warning icon warning"></i> Disabled until you Provision an unraid.net SSL Cert and set SSL/TLS to Auto</span>
|
||
<input type="hidden" id="wanaccess" value="no">
|
||
<input type="hidden" id="wanport" value="0">
|
||
<?elseif(!$boolWebUIAuth):?>
|
||
: <span><i class="fa fa-warning icon warning"></i> Disabled until your root user account is password-protected</span>
|
||
<input type="hidden" id="wanaccess" value="no">
|
||
<input type="hidden" id="wanport" value="0">
|
||
<?else:?>
|
||
: <select id="wanaccess" size="1" class="narrow" onchange="changeRemoteAccess(this)">
|
||
<?=mk_option($remote['wanaccess'], "no", "No")?>
|
||
<?=mk_option($remote['wanaccess'], "yes", "Yes")?>
|
||
</select>
|
||
|
||
<div markdown="1" id="wanpanel" style="display:<?=($remote['wanaccess']=='yes'?'block':'none')?>">
|
||
WAN Port:
|
||
: <input type="number" id="wanport" class="trim" min="0" max="65535" value="<?=htmlspecialchars($remote['wanport'])?>"> <button type="button" onclick="dnsCheckServer(this)" style="margin-top: 0">Check</button>
|
||
|
||
> WAN Port is the external TCP port number setup on your router to NAT/Port Forward traffic from the internet to this
|
||
> Unraid server SSL port for secure web traffic.
|
||
</div>
|
||
|
||
|
||
: <button type="button" onclick="registerServer(this)">Apply</button>
|
||
<?endif?>
|
||
<?endif?>
|
||
</form>
|
||
|
||
<?if($isRegistered):?>
|
||
<form markdown="1" name="FlashBackup" method="POST" action="/update.htm" target="progressFrame">
|
||
<div markdown="1" id="loadingpanel">
|
||
Flash backup:
|
||
: <span class='blue p0'><span markdown="1" id="loadingtext">Loading</span> <i class="fa fa-spinner fa-spin" aria-hidden="true"></i></span>
|
||
|
||
</div>
|
||
<div markdown="1" id="inactivespanel" style="display:none">
|
||
Flash backup:
|
||
: <span class='orange p0'>Not activated</span>
|
||
|
||
|
||
: <button type="button" onclick="enableFlashBackup(this)">Activate</button>
|
||
|
||
> Click Activate to set up a local git repo for your local USB Flash boot device and connect to a dedicated remote on unraid.net tied tothis server.
|
||
|
||
</div>
|
||
<div markdown="1" id="uptodatepanel" style="display:none">
|
||
Flash backup:
|
||
: <span class='green p0'>Activated:</span> <span class='green p0'>Up-to-date</span>
|
||
|
||
</div>
|
||
<div markdown="1" id="changespanel" style="display:none">
|
||
Flash backup:
|
||
: <span class='green p0'>Activated:</span> <span class='orange p0'>Not up-to-date</span>
|
||
|
||
|
||
: <button type="button" onclick="enableFlashBackup(this)">Update</button> <button type="button" onclick="enableFlashBackup(this)">Changes</button>
|
||
|
||
> The Not Up-to-date status indicates there are local files which are changed vs. the remote on unraid.net.
|
||
|
||
> Click Update to push changes to the remote.
|
||
|
||
> Click Changes to see what has changed.
|
||
|
||
</div>
|
||
<div markdown="1" id="uptodatepanel" style="display:none">
|
||
|
||
: <button type="button" disabled>Update</button>
|
||
|
||
> The Up-to-date status indicates your local configuration matches that stored on the unraid.net remote.
|
||
|
||
</div>
|
||
<div markdown="1" id="activepanel" style="display:none">
|
||
|
||
: <button type="button" onclick="enableFlashBackup(this)">Deactivate</button> <button type="button" onclick="enableFlashBackup(this)">Reinitialize</button>
|
||
|
||
> Click Deactivate to pause communication with your remote on unraid.net.
|
||
|
||
> Click Reinitialize to erase all change history in both local and unraid.net remote.
|
||
|
||
</div>
|
||
</form>
|
||
<script>
|
||
var flashbackupsub = new NchanSubscriber('/sub/flashbackup');
|
||
flashbackupsub.on('message', function(data) {
|
||
var ini = parseINI(data);
|
||
|
||
console.info('Flash backup state: ', ini['flashbackup']);
|
||
buttonStateReset(ini['flashbackup']);
|
||
});
|
||
$(function() {
|
||
flashbackupsub.start();
|
||
});
|
||
</script>
|
||
<?endif?>
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<!-- Preserve in case plugin is removed -->
|
||
<FILE Run="/bin/bash" Method="install">
|
||
<INLINE>
|
||
mv -f /usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php /usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php-
|
||
</INLINE>
|
||
</FILE>
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php">
|
||
<INLINE>
|
||
<![CDATA[
|
||
<?PHP
|
||
/* Copyright 2005-2018, Lime Technology
|
||
* Copyright 2012-2018, 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.
|
||
*/
|
||
?>
|
||
<?
|
||
$cli = php_sapi_name()=='cli';
|
||
|
||
function response_complete($httpcode, $result, $cli_success_msg='') {
|
||
global $cli;
|
||
if ($cli) {
|
||
$json = @json_decode($result,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)$result);
|
||
}
|
||
|
||
// remoteaccess, externalport, (if registering) username, password
|
||
extract(parse_ini_file('/boot/config/plugins/dynamix/dynamix.cfg',true));
|
||
if (empty($remote)) {
|
||
$remote = [
|
||
"apikey" => "",
|
||
"wanaccess" => "no",
|
||
"wanport" => "443"
|
||
];
|
||
}
|
||
if (empty($remote['wanport'])) {
|
||
$remote['wanport'] = 443;
|
||
}
|
||
if ($cli) {
|
||
$remoteaccess = $remote['wanaccess'];
|
||
$externalport = $remote['wanport'];
|
||
$username = '';
|
||
$password = '';
|
||
} else {
|
||
$remoteaccess = $_POST['remoteaccess'];
|
||
$externalport = $_POST['externalport'];
|
||
$username = $_POST['username'];
|
||
$password = $_POST['password'];
|
||
}
|
||
$isRegistered = !empty($remote['apikey']);
|
||
|
||
// protocol, hostname, internalport
|
||
list($protocol, $hostname, $internalport) = explode(":", rtrim(file_get_contents("/var/run/nginx.origin")));
|
||
$hostname = substr($hostname, 2);
|
||
|
||
if (!$isRegistered && empty($username) && !preg_match('/.*\.unraid\.net$/', $hostname)) {
|
||
response_complete(406, '{"error":"Nothing to do"}');
|
||
}
|
||
|
||
// keyfile
|
||
$var = parse_ini_file('/var/local/emhttp/var.ini');
|
||
$keyfile = @file_get_contents($var['regFILE']);
|
||
if ($keyfile === false) {
|
||
response_complete(406, '{"error":"Registration key required"}');
|
||
}
|
||
$keyfile = @base64_encode($keyfile);
|
||
|
||
// internalip
|
||
extract(parse_ini_file('/var/local/emhttp/network.ini',true));
|
||
$internalip = $eth0['IPADDR:0'];
|
||
|
||
$ch = curl_init('https://keys.lime-technology.com/account/server/register');
|
||
curl_setopt($ch, CURLOPT_POST, 1);
|
||
|
||
if (!$isRegistered && empty($username)) {
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||
'internalip' => $internalip,
|
||
'keyfile' => $keyfile
|
||
]);
|
||
} else {
|
||
// servername, servercomment
|
||
$servername = $var['NAME'];
|
||
$servercomment = $var['COMMENT'];
|
||
if (empty($username)) {
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||
'servername' => $servername,
|
||
'servercomment' => $servercomment,
|
||
'protocol' => $protocol,
|
||
'hostname' => $hostname,
|
||
'internalport' => $internalport,
|
||
'internalip' => $internalip,
|
||
'remoteaccess' => $remoteaccess,
|
||
'externalport' => $externalport,
|
||
'keyfile' => $keyfile
|
||
]);
|
||
} else {
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||
'servername' => $servername,
|
||
'servercomment' => $servercomment,
|
||
'protocol' => $protocol,
|
||
'hostname' => $hostname,
|
||
'internalport' => $internalport,
|
||
'internalip' => $internalip,
|
||
'remoteaccess' => $remoteaccess,
|
||
'externalport' => $externalport,
|
||
'username' => $username,
|
||
'password' => $password,
|
||
'keyfile' => $keyfile
|
||
]);
|
||
}
|
||
}
|
||
|
||
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) {
|
||
response_complete(500, '{"error":"'.$error.'"}');
|
||
}
|
||
|
||
response_complete($httpcode, $result, 'success');
|
||
?>
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Name="/etc/rc.d/rc.flash_backup" Mode="0755">
|
||
<INLINE>
|
||
<![CDATA[
|
||
#!/bin/bash
|
||
# This file is /etc/rc.d/rc.flash_backup
|
||
# use at queue "f" for flash backup
|
||
QUEUE=" -q f "
|
||
TASKNAME="/etc/rc.d/rc.flash_backup watch"
|
||
TASKACTION="php /usr/local/emhttp/plugins/dynamix.unraid.net/include/UpdateFlashBackup.php update"
|
||
status() {
|
||
local flash_backup_pid=$(pgrep --full "${TASKNAME}")
|
||
if [[ $flash_backup_pid ]]; then
|
||
echo "flash backup monitor is running."
|
||
_hasqueue && echo "changes detected, backup queued"
|
||
exit 0
|
||
else
|
||
if _enabled; then
|
||
echo "flash backup is enabled but the monitor is not running"
|
||
else
|
||
echo "flash backup is disabled so the monitor is disabled"
|
||
fi
|
||
exit 1
|
||
fi
|
||
}
|
||
start() {
|
||
# only run if flash_backup is enabled
|
||
_enabled || exit 1
|
||
# terminate watcher loop/process
|
||
pkill --full "${TASKNAME}" &>/dev/null
|
||
# flush: this will ensure we start with a clean repo
|
||
flush
|
||
# start watcher loop as background process
|
||
exec ${TASKNAME} &>/dev/null &
|
||
exit 0
|
||
}
|
||
stop() {
|
||
# terminate watcher loop/process
|
||
pkill --full "${TASKNAME}" &>/dev/null
|
||
# remove any queued jobs and flush changes
|
||
flush
|
||
exit 0
|
||
}
|
||
reload() {
|
||
stop
|
||
sleep 1
|
||
start
|
||
sleep 1
|
||
status
|
||
exit 0
|
||
}
|
||
flush() {
|
||
# remove any queued jobs
|
||
_removequeue
|
||
# push any changes ad-hoc
|
||
echo ${TASKACTION} | at ${QUEUE} now &>/dev/null
|
||
}
|
||
_watch() {
|
||
# start watcher loop
|
||
while true; do
|
||
if [ "$(git -C /boot status -s)" ]; then
|
||
_hasqueue || ( logger "adding task: ${TASKACTION}" --tag flash_backup; echo ${TASKACTION} | at ${QUEUE} now +1 minute &>/dev/null )
|
||
fi
|
||
sleep 60;
|
||
done
|
||
}
|
||
_hasqueue() {
|
||
# returns false if the queue is empty, true otherwise
|
||
if [ -z "$(atq ${QUEUE})" ]; then
|
||
return 1
|
||
fi
|
||
return 0
|
||
}
|
||
_removequeue() {
|
||
# delete any at jobs in queue f
|
||
atq ${QUEUE} | while read line; do
|
||
id=`echo ${line} | cut -d " " -f 1`
|
||
atrm ${id}
|
||
done
|
||
}
|
||
_enabled() {
|
||
local output=$(git -C /boot config --get remote.origin.url)
|
||
if [[ $output == *"backup.unraid.net"* ]]; then
|
||
return 0
|
||
fi
|
||
return 1
|
||
}
|
||
case "$1" in
|
||
'status')
|
||
status
|
||
;;
|
||
'start')
|
||
start
|
||
;;
|
||
'stop')
|
||
stop
|
||
;;
|
||
'reload')
|
||
reload
|
||
;;
|
||
'flush')
|
||
flush
|
||
;;
|
||
'watch')
|
||
_watch
|
||
;;
|
||
*)
|
||
echo "usage $0 status|start|stop|reload|flush"
|
||
esac
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix.unraid.net/include/UpdateFlashBackup.php">
|
||
<INLINE>
|
||
<![CDATA[
|
||
<?PHP
|
||
/* Copyright 2005-2018, Lime Technology
|
||
* Copyright 2012-2018, 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.
|
||
*/
|
||
?>
|
||
<?
|
||
$cli = php_sapi_name()=='cli';
|
||
|
||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||
|
||
if (file_exists('/boot/config/plugins/dynamix/dynamix.cfg')) {
|
||
extract(parse_ini_file('/boot/config/plugins/dynamix/dynamix.cfg',true));
|
||
}
|
||
if (empty($remote)) {
|
||
$remote = [
|
||
"apikey" => "",
|
||
"username" => "",
|
||
"avatar" => "",
|
||
"wanaccess" => "no",
|
||
"wanport" => "443"
|
||
];
|
||
}
|
||
|
||
function response_complete($httpcode, $result, $cli_success_msg='') {
|
||
global $cli;
|
||
|
||
save_flash_backup_state();
|
||
|
||
if ($cli) {
|
||
$json = @json_decode($result,true);
|
||
if (!empty($json['error'])) {
|
||
echo 'Error: '.$json['error'].PHP_EOL;
|
||
exit(1);
|
||
}
|
||
if (!empty($cli_success_msg)) $cli_success_msg .= PHP_EOL;
|
||
exit($cli_success_msg);
|
||
}
|
||
header('Content-Type: application/json');
|
||
http_response_code($httpcode);
|
||
exit((string)$result);
|
||
}
|
||
|
||
function save_flash_backup_state($loading='') {
|
||
global $arrState;
|
||
|
||
$arrState['loading'] = $loading;
|
||
|
||
$text = "[flashbackup]\n";
|
||
foreach ($arrState as $key => $value) {
|
||
if ($value === false) $value = 'false';
|
||
if ($value === true) $value = 'true';
|
||
$text .= "$key=" . $value . "\n";
|
||
}
|
||
file_put_contents('/var/local/emhttp/flashbackup.new', $text);
|
||
rename('/var/local/emhttp/flashbackup.new', '/var/local/emhttp/flashbackup.ini');
|
||
}
|
||
|
||
function load_flash_backup_state() {
|
||
global $remote;
|
||
global $arrState;
|
||
|
||
$arrState = [
|
||
'activated' => false,
|
||
'uptodate' => false,
|
||
'loading' => ''
|
||
];
|
||
|
||
$arrNewState = false;
|
||
if (file_exists('/var/local/emhttp/flashbackup.ini')) {
|
||
$arrNewState = parse_ini_file('/var/local/emhttp/flashbackup.ini');
|
||
}
|
||
if ($arrNewState !== false) {
|
||
$arrState = array_merge($arrState, $arrNewState);
|
||
}
|
||
|
||
$arrState['activated'] = empty($arrState['activated']) ? true : false;
|
||
$arrState['uptodate'] = empty($arrState['uptodate']) ? true : false;
|
||
$arrState['registered'] = !empty($remote['apikey']);
|
||
}
|
||
// command
|
||
// init (default)
|
||
// activate
|
||
// status
|
||
// update
|
||
// flush
|
||
// reinit
|
||
// deactivate
|
||
if ($cli) {
|
||
if ($argc > 1) $command = $argv[1];
|
||
if ($argc > 2) $commitmsg = $argv[2];
|
||
} else {
|
||
$command = $_POST['command'];
|
||
$commitmsg = $_POST['commitmsg'];
|
||
}
|
||
if (empty($command)) $command='init';
|
||
if (empty($commitmsg)) $commitmsg='Config change';
|
||
|
||
$loadingMessage = '';
|
||
|
||
switch ($command) {
|
||
case 'activate':
|
||
$loadingMessage = 'Activating';
|
||
break;
|
||
case 'deactivate':
|
||
$loadingMessage = 'Deactivating';
|
||
break;
|
||
case 'update':
|
||
$loadingMessage = 'Updating';
|
||
break;
|
||
case 'reinit':
|
||
$loadingMessage = 'Reinitializing';
|
||
break;
|
||
case 'status':
|
||
$loadingMessage = 'Loading';
|
||
break;
|
||
}
|
||
|
||
load_flash_backup_state();
|
||
|
||
// keyfile
|
||
if (!file_exists('/var/local/emhttp/var.ini')) {
|
||
response_complete(406, '{"error":"Machine still booting"}');
|
||
}
|
||
$var = parse_ini_file("/var/local/emhttp/var.ini");
|
||
$keyfile = @file_get_contents($var['regFILE']);
|
||
if ($keyfile === false) {
|
||
response_complete(406, '{"error":"Registration key required"}');
|
||
}
|
||
$keyfile = @base64_encode($keyfile);
|
||
|
||
// check if activated
|
||
if ($command != 'activate') {
|
||
exec('git -C /boot config --get remote.origin.url', $config_output, $return_var);
|
||
if (($return_var != 0) || (strpos($config_output[0],'backup.unraid.net') === false)) {
|
||
$arrState['activated'] = false;
|
||
response_complete(406, '{"error":"Not activated"}');
|
||
}
|
||
}
|
||
|
||
// if flush command, invoke our background rc.flash_backup to flush
|
||
if ($command == 'flush') {
|
||
exec('/etc/rc.d/rc.flash_backup flush &>/dev/null');
|
||
response_complete(200, '{}');
|
||
}
|
||
|
||
if (!empty($loadingMessage)) {
|
||
save_flash_backup_state($loadingMessage);
|
||
}
|
||
|
||
// if deactivate command, just remove our origin
|
||
if ($command == 'deactivate') {
|
||
exec('git --git-dir /boot/.git remote remove origin &>/dev/null');
|
||
exec('/etc/rc.d/rc.flash_backup stop &>/dev/null');
|
||
response_complete(200, '{}');
|
||
}
|
||
|
||
// build a list of sha256 hashes of the bzfiles
|
||
$bzfilehashes = [];
|
||
$allbzfiles = ['bzimage','bzfirmware','bzmodules','bzroot','bzroot-gui'];
|
||
foreach ($allbzfiles as $bzfile) {
|
||
$sha256 = trim(@file_get_contents("/boot/$bzfile.sha256"));
|
||
if (strlen($sha256) != 64) {
|
||
response_complete(406, '{"error":"Invalid or missing '.$bzfile.'.sha256 file"}');
|
||
}
|
||
$bzfilehashes[] = $sha256;
|
||
}
|
||
|
||
$ch = curl_init('https://keys.lime-technology.com/backup/flash/activate');
|
||
curl_setopt($ch, CURLOPT_POST, 1);
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||
'keyfile' => $keyfile,
|
||
'version' => $var['version'],
|
||
'bzfiles' => implode(',', $bzfilehashes)
|
||
]);
|
||
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) {
|
||
response_complete(500, '{"error":"'.$error.'"}');
|
||
}
|
||
|
||
$json = json_decode($result, true);
|
||
if (empty($json) || empty($json['ssh_privkey'])) {
|
||
response_complete(406, $result);
|
||
}
|
||
|
||
// save the public and private keys
|
||
if (!file_exists('/root/.ssh')) {
|
||
mkdir('/root/.ssh', 0700);
|
||
}
|
||
|
||
if ($json['ssh_privkey'] != file_get_contents('/root/.ssh/unraidbackup_id_ed25519')) {
|
||
file_put_contents('/root/.ssh/unraidbackup_id_ed25519', $json['ssh_privkey']);
|
||
chmod('/root/.ssh/unraidbackup_id_ed25519', 0600);
|
||
file_put_contents('/root/.ssh/unraidbackup_id_ed25519.pub', $json['ssh_pubkey']);
|
||
chmod('/root/.ssh/unraidbackup_id_ed25519.pub', 0644);
|
||
}
|
||
|
||
// add configuration to use our keys
|
||
if (!file_exists('/root/.ssh/config') || strpos(file_get_contents('/root/.ssh/config'),'Host backup.unraid.net') === false) {
|
||
file_put_contents('/root/.ssh/config', 'Host backup.unraid.net
|
||
IdentityFile ~/.ssh/unraidbackup_id_ed25519
|
||
IdentitiesOnly yes
|
||
', FILE_APPEND);
|
||
chmod('/root/.ssh/config', 0644);
|
||
}
|
||
|
||
// add our server as a known host
|
||
if (!file_exists('/root/.ssh/known_hosts') || strpos(file_get_contents('/root/.ssh/known_hosts'),'backup.unraid.net,54.70.72.154') === false) {
|
||
file_put_contents('/root/.ssh/known_hosts', 'backup.unraid.net,54.70.72.154 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKrKXKQwPZTY25MoveIw7fZ3IoZvvffnItrx6q7nkNriDMr2WAsoxu0DrU2QrSLH5zFF1ibv4tChS1hOpiYObiI='."\n", FILE_APPEND);
|
||
chmod('/root/.ssh/known_hosts', 0644);
|
||
}
|
||
|
||
// blow away existing repo if reinit command
|
||
if ($command == 'reinit') {
|
||
exec('rm -rf /boot/.git');
|
||
}
|
||
|
||
// ensure git repo is setup on the flash drive
|
||
if (!file_exists('/boot/.git/info/exclude')) {
|
||
exec('git init /boot &>/dev/null');
|
||
}
|
||
|
||
// setup a nice git description
|
||
if (!file_exists('/boot/.git/description') || strpos(file_get_contents('/boot/.git/description'),$var['NAME']) === false) {
|
||
file_put_contents('/boot/.git/description', 'Unraid flash drive for '.$var['NAME']."\n");
|
||
}
|
||
|
||
// setup git ignore for files we dont need in the flash backup
|
||
if (strpos(file_get_contents('/boot/.git/info/exclude'),'forcesync') === false) {
|
||
file_put_contents('/boot/.git/info/exclude', '# Unraid OS Flash Backup
|
||
|
||
# Blacklist everything
|
||
/*
|
||
|
||
# Whitelist selected root files
|
||
!*.sha256
|
||
!changes.txt
|
||
!license.txt
|
||
!startup.nsh
|
||
|
||
!EFI*/
|
||
EFI*/boot/*
|
||
!EFI*/boot/syslinux.cfg
|
||
|
||
!syslinux/
|
||
syslinux/*
|
||
!syslinux/syslinux.cfg
|
||
!syslinux/syslinux.cfg-
|
||
|
||
# Whitelist entire config directory
|
||
!config/
|
||
# except for selected files
|
||
config/drift
|
||
config/forcesync
|
||
config/plugins/unRAIDServer.plg
|
||
config/random-seed
|
||
config/shadow
|
||
config/smbpasswd
|
||
config/plugins/**/*.tgz
|
||
config/plugins/**/*.txz
|
||
config/plugins/**/*.tar.bz2
|
||
');
|
||
}
|
||
|
||
// ensure git user is configured
|
||
exec('git --git-dir /boot/.git config user.email \'gitbot@unraid.net\' &>/dev/null');
|
||
exec('git --git-dir /boot/.git config user.name \'gitbot\' &>/dev/null');
|
||
|
||
// ensure upstream git server is configured and in-sync
|
||
exec('git --git-dir /boot/.git remote add -f -t master -m master origin git@backup.unraid.net:~/flash.git &>/dev/null');
|
||
if ($command != 'reinit') {
|
||
exec('git --git-dir /boot/.git reset origin/master &>/dev/null');
|
||
exec('git --git-dir /boot/.git checkout -B master origin/master &>/dev/null');
|
||
}
|
||
|
||
// establish status
|
||
exec('git -C /boot status --porcelain', $status_output, $return_var);
|
||
$arrState['activated'] = $return_var==0;
|
||
|
||
if ($return_var != 0) {
|
||
$arrState['loading'] = '';
|
||
response_complete(406, '{"error":"'.${status_output[0]}.'"}');
|
||
}
|
||
|
||
$arrState['uptodate'] = empty($status_output);
|
||
|
||
if ($command == 'status') {
|
||
$data = implode("\n", $status_output);
|
||
response_complete($httpcode, '{"data":"'.$data.'"}', $data);
|
||
}
|
||
|
||
if (($command == 'update') || ($command == 'reinit')) {
|
||
// push changes upstream
|
||
if (!empty($status_output)) {
|
||
exec('git -C /boot add -A &>/dev/null');
|
||
if ($command == 'reinit') {
|
||
exec('git -C /boot commit -m \'Initial commit\' &>/dev/null');
|
||
exec('git -C /boot push --force --set-upstream origin master &>/dev/null');
|
||
} else {
|
||
exec('git -C /boot commit -m ' . escapeshellarg($commitmsg) . ' &>/dev/null');
|
||
exec('git -C /boot push --set-upstream origin master &>/dev/null');
|
||
}
|
||
$arrState['uptodate'] = true;
|
||
}
|
||
}
|
||
|
||
if ($command == 'activate') {
|
||
exec('/etc/rc.d/rc.flash_backup start &>/dev/null');
|
||
}
|
||
|
||
response_complete($httpcode, '{}');
|
||
?>
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix.unraid.net/include/RegWizard.php">
|
||
<INLINE>
|
||
<![CDATA[
|
||
<style>
|
||
#sb-title {display:none}
|
||
#sb-info {display:none}
|
||
</style>
|
||
<script markdown="0">
|
||
function handleMessage(e) {
|
||
//if (e.origin != "http://child.com") { return; }
|
||
if (e.data.length == 0) { return; }
|
||
|
||
const SAFE_JSON_PARSE = (str) => {
|
||
try {
|
||
return [null, JSON.parse(str)];
|
||
} catch (err) {
|
||
return [err];
|
||
}
|
||
};
|
||
|
||
const [err, data] = SAFE_JSON_PARSE(e.data);
|
||
if (err) return false; // swallow json parse error
|
||
|
||
const HANDLE_LICENSES = (data, e) => {
|
||
if (data.license) {
|
||
$.get('/webGui/include/InstallKey.php', {url: data.license}, function() {
|
||
console.log('New license key installed: ' + data.license);
|
||
const payload = {
|
||
event: 'LICENSE_PINGBACK',
|
||
message: 'New license key installed',
|
||
license: data.license,
|
||
success: true,
|
||
};
|
||
e.source.postMessage(JSON.stringify(payload), e.origin);
|
||
}).fail(function() {
|
||
console.error('Failed to license new key: ' + data.license);
|
||
const payload = {
|
||
event: 'LICENSE_PINGBACK',
|
||
message: 'Failed to license new key',
|
||
license: data.license,
|
||
success: false,
|
||
};
|
||
e.source.postMessage(JSON.stringify(payload), e.origin);
|
||
});
|
||
} else {
|
||
console.error('KEY_PURCHASE event fired! but missing license data:', data);
|
||
}
|
||
};
|
||
|
||
switch (data.event) {
|
||
case "CLOSE_SHADOWBOX":
|
||
hideRegWizard();
|
||
break;
|
||
case "SHUTDOWN":
|
||
window.location.href = '/webGui/include/Boot.php';
|
||
break;
|
||
case "REG_WIZARD":
|
||
if (data.apikey) {
|
||
var postargs = {
|
||
'#file': 'dynamix/dynamix.cfg',
|
||
'#section': 'remote',
|
||
apikey: data.apikey,
|
||
regWizTime: `${Date.now()}_${data.guid}`, // set when signing in the first time and never unset for the sake of displaying Sign In/Up in the UPC without needing to validate guid every time
|
||
};
|
||
if (data.email) {
|
||
postargs['email'] = data.email;
|
||
}
|
||
if (data.username) {
|
||
postargs['username'] = data.username;
|
||
}
|
||
if (data.avatar) {
|
||
postargs['avatar'] = data.avatar;
|
||
}
|
||
$.post('/update.php', postargs, function() {
|
||
console.log('dynamix/dynamix.cfg: Updated apikey under [remote] section');
|
||
// send a ping back to the regwiz
|
||
const payload = { event: 'ACCOUNT_PINGBACK', success: true, type: 'signIn', webGuiPathname: window.location.pathname };
|
||
e.source.postMessage(JSON.stringify(payload), e.origin);
|
||
}).fail(function() {
|
||
console.error('Failed to update apikey under [remote] section');
|
||
// send a ping back to the regwiz
|
||
const payload = { event: 'ACCOUNT_PINGBACK', success: false, type: 'signIn', webGuiPathname: window.location.pathname };
|
||
e.source.postMessage(JSON.stringify(payload), e.origin);
|
||
});
|
||
}
|
||
// duplicate conditional so we don't get the error from HANDLE_LICENSES()
|
||
if (data.license) HANDLE_LICENSES(data, e);
|
||
break;
|
||
case "KEY_PURCHASE":
|
||
HANDLE_LICENSES(data, e);
|
||
break;
|
||
case "GET_STATE":
|
||
$.get('/plugins/dynamix.unraid.net/include/state.php', function(newstate) {
|
||
e.source.postMessage(newstate, e.origin);
|
||
}).fail(function(err) {
|
||
console.error('Failed to get new state: ' + err);
|
||
});
|
||
break;
|
||
case "SUCCESS_NEW_STATE":
|
||
$.get('/plugins/dynamix.unraid.net/include/state.php', function(newstate) {
|
||
// parse response so we can update the event type string to send back
|
||
const [stateError, stateData] = SAFE_JSON_PARSE(newstate);
|
||
const newPayload = { ...stateData, event: 'DELIVER_NEW_STATE', success: true };
|
||
e.source.postMessage(JSON.stringify(newPayload), e.origin);
|
||
}).fail(function(err) {
|
||
e.source.postMessage(JSON.stringify({ event: 'DELIVER_NEW_STATE', success: false }), e.origin);
|
||
});
|
||
break;
|
||
case "MYSERVERS_UNREGISTER":
|
||
$.post('/update.php', {
|
||
'#file': 'dynamix/dynamix.cfg',
|
||
'#section': 'remote',
|
||
apikey: '',
|
||
avatar: '',
|
||
email: '',
|
||
username: '',
|
||
}, function() {
|
||
console.log('dynamix/dynamix.cfg: Unregistered myservers, cleared apikey under [remote] section');
|
||
// send a ping back to the regwiz
|
||
const payload = { event: 'ACCOUNT_PINGBACK', success: true, type: 'signOut', webGuiPathname: window.location.pathname };
|
||
e.source.postMessage(JSON.stringify(payload), e.origin);
|
||
}).fail(function() {
|
||
console.error('Failed to unregister');
|
||
// send a ping back to the regwiz
|
||
const payload = { event: 'ACCOUNT_PINGBACK', success: false, type: 'signOut', webGuiPathname: window.location.pathname };
|
||
e.source.postMessage(JSON.stringify(payload), e.origin);
|
||
});
|
||
break;
|
||
case "RELOAD":
|
||
return window.location.reload();
|
||
case "REDIRECT_MAIN":
|
||
return window.location.href = '/Main';
|
||
case "STOP_SENDING_SESSION":
|
||
break;
|
||
case "PREFLIGHT_REQUEST":
|
||
break;
|
||
default:
|
||
console.error('Unhandled event \'' + data.event + '\' fired. data:', data);
|
||
break;
|
||
}
|
||
}
|
||
window.addEventListener('message', handleMessage, false);
|
||
</script>
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Name="/usr/local/emhttp/webGui/javascript/vue.js">
|
||
<URL>https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js</URL>
|
||
</FILE>
|
||
|
||
<FILE Name="/usr/local/emhttp/webGui/javascript/vue.min.js">
|
||
<URL>https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js</URL>
|
||
</FILE>
|
||
|
||
<FILE Run="/bin/bash" Method="install Vue.js web component files">
|
||
<INLINE>
|
||
<![CDATA[
|
||
MANIFEST_JSON_PATH=/boot/config/plugins/Unraid.net/wc/manifest.json
|
||
BASE_URL=https://registration.unraid.net/wc/
|
||
BASE_PATH=/boot/config/plugins/Unraid.net/wc/
|
||
MANIFEST_JSON=manifest.json
|
||
MANIFEST_TXT=manifest.txt
|
||
|
||
# Check if we need to download files
|
||
# On first install we cache these
|
||
if [[ ! -f "$MANIFEST_JSON_PATH" ]]; then
|
||
echo "🕹️ Start downloading web components"
|
||
|
||
# Ensure we start off with a clean dir
|
||
rm -rf $BASE_PATH && mkdir -p $BASE_PATH && cd $BASE_PATH
|
||
|
||
# Fetch the manifest
|
||
echo "🎣 Fetching manifest"
|
||
curl --http2 -s ${BASE_URL}$MANIFEST_JSON | jq . > $MANIFEST_JSON
|
||
echo "📋 Received manifest"
|
||
|
||
# Take each key and add it to MANIFEST_TXT
|
||
KEYS=($((<${MANIFEST_JSON} jq -r 'keys | @sh') | tr -d \'\"))
|
||
for ix in ${!KEYS[*]}
|
||
do
|
||
echo "${BASE_URL}${KEYS[$ix]}" >> $MANIFEST_TXT
|
||
echo "✨ ${BASE_URL}${KEYS[$ix]}"
|
||
done
|
||
|
||
# Download files from the manifest file
|
||
echo "🚀 Parsed Manifest – starting downloads"
|
||
xargs -n 1 curl --http2 -s -O < $MANIFEST_TXT
|
||
|
||
# Done
|
||
echo "✅ Registration Wizard files downloaded"
|
||
if [ -f "$MANIFEST_TXT" ]; then
|
||
echo "☄️🚮 Deleted temp files"
|
||
rm $MANIFEST_TXT
|
||
fi
|
||
fi
|
||
|
||
# Copy files to webGui's public dir
|
||
mkdir -p /usr/local/emhttp/webGui/wc/
|
||
rsync -r --exclude="$MANIFEST_JSON" /boot/config/plugins/Unraid.net/wc/ /usr/local/emhttp/webGui/wc/
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
|
||
<FILE Name="/boot/config/plugins/Unraid.net/.gitignore" Method="install">
|
||
<INLINE>
|
||
<![CDATA[
|
||
wc
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice1">
|
||
<INLINE>
|
||
<![CDATA[
|
||
<!-- RegWiz -->
|
||
<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;
|
||
}
|
||
vue-userprofile,
|
||
unraid-user-profile {
|
||
font-size: 16px;
|
||
margin-left: auto;
|
||
height: 100%;
|
||
}
|
||
|
||
unraid-launchpad {
|
||
position: relative;
|
||
z-index: 10001;
|
||
}
|
||
</style>
|
||
<!-- /RegWiz -->
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice2">
|
||
<INLINE>
|
||
<![CDATA[
|
||
<!-- RegWiz -->
|
||
<script type="text/javascript">
|
||
const UPC_ENV = localStorage.getItem('UPC_ENV') ? localStorage.getItem('UPC_ENV') : 'production'; // @TODO - it would be great if this was auto-set when PLG was built
|
||
const VUE_CDN_PREFIX = 'https://cdn.jsdelivr.net/npm/vue@2.6.12';
|
||
const injectJS = (src) => {
|
||
if (UPC_ENV !== 'production') console.debug('[injectJS]', src);
|
||
const script = document.createElement('script');
|
||
script.type = 'text/javascript';
|
||
script.src = src;
|
||
document.body.appendChild(script);
|
||
};
|
||
// by default prod is loaded from hosted sources
|
||
let vueFile = `${VUE_CDN_PREFIX}/dist/vue.min.js`;
|
||
let wcEntryFile = 'https://registration.unraid.net/wc/unraid.min.js';
|
||
// determine what source we should use
|
||
if (UPC_ENV !== 'production') console.debug('[UPC_ENV]', UPC_ENV);
|
||
switch (UPC_ENV) {
|
||
case 'staging':
|
||
// min version of staging
|
||
vueFile = `${VUE_CDN_PREFIX}/dist/vue.min.js`;
|
||
wcEntryFile = 'https://registration-dev.unraid.net/wc/unraid.min.js';
|
||
break;
|
||
case 'staging-debug':
|
||
// non-min version of staging
|
||
vueFile = `${VUE_CDN_PREFIX}/dist/vue.js`;
|
||
wcEntryFile = 'https://registration-dev.unraid.net/wc/unraid.js';
|
||
break;
|
||
case 'local':
|
||
// forces load from webGUI filesystem
|
||
vueFile = '<?autov('/webGui/javascript/vue.js') ?>';
|
||
wcEntryFile = '<?autov('/webGui/wc/unraid.min.js') ?>'; // @TODO / WIP - non-min files aren't downloaded just yet.
|
||
break;
|
||
case 'development':
|
||
// local filesystem Vue.js + external "local" dev server for RegWiz development
|
||
vueFile = '<?autov('/webGui/javascript/vue.js') ?>';
|
||
wcEntryFile = 'https://launchpad.unraid.test:6969/wc/unraid.js';
|
||
break;
|
||
default: // prod
|
||
break;
|
||
}
|
||
// add the intended files to the DOM
|
||
injectJS(vueFile);
|
||
// make sure specified vue file is loaded before attempting to
|
||
// inject and load web component entry since it relies on Vue.js
|
||
let checkForVue = setInterval(() => {
|
||
if (!window.Vue) return;
|
||
clearInterval(checkForVue); // stop checking
|
||
injectJS(wcEntryFile); // and just inject it already!
|
||
}, 10);
|
||
// start a timer to determine if we need to inject webGUI file system
|
||
// fallback if we take too long injecting the above
|
||
setTimeout(() => {
|
||
if (!window.Vue) {
|
||
if (UPC_ENV !== 'production') console.debug('[UPC] fallback to filesystem JS');
|
||
clearInterval(checkForVue); // stop initial check
|
||
injectJS("<?autov('/webGui/javascript/vue.min.js') ?>");
|
||
checkForVue = setInterval(() => { // reset check
|
||
if (!window.Vue) return;
|
||
clearInterval(checkForVue); // stop checking
|
||
injectJS("<?autov('/webGui/wc/unraid.min.js') ?>"); // and just inject it already!
|
||
}, 10);
|
||
}
|
||
}, 2000);
|
||
</script>
|
||
<!-- /RegWiz -->
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice3">
|
||
<INLINE>
|
||
<![CDATA[
|
||
<!-- RegWiz -->
|
||
<?
|
||
$serverstate = [
|
||
"deviceCount" => $var['deviceCount'],
|
||
"email" => ($remote['email']) ? $remote['email'] : '',
|
||
"flashproduct" => $var['flashProduct'],
|
||
"flashvendor" => $var['flashVendor'],
|
||
"guid" => $var['flashGUID'],
|
||
"internalip" => $_SERVER['SERVER_ADDR'],
|
||
"internalport" => $_SERVER['SERVER_PORT'],
|
||
"keyfile" => str_replace(['+','/','='], ['-','_',''], trim(base64_encode(@file_get_contents($var['regFILE'])))),
|
||
"protocol" => $_SERVER['REQUEST_SCHEME'],
|
||
"reggen" => (int)$var['regGen'],
|
||
"registered" => empty($remote['apikey']) || empty($var['regFILE']) ? 0 : 1,
|
||
"servername" => $var['NAME'],
|
||
"serverip" => $_SERVER['SERVER_ADDR'],
|
||
"site" => $_SERVER['REQUEST_SCHEME']."://".$_SERVER['HTTP_HOST'],
|
||
"state" => strtoupper(empty($var['regCheck']) ? $var['regTy'] : $var['regCheck']),
|
||
];
|
||
// upc translations
|
||
$upc_translations = [
|
||
($_SESSION['locale']) ? $_SESSION['locale'] : 'en_US' => [
|
||
'getStarted' => _('Get Started'),
|
||
'signIn' => _('Sign In'),
|
||
'signUp' => _('Sign Up'),
|
||
'signOut' => _('Sign Out'),
|
||
'error' => _('Error'),
|
||
'fixError' => _('Fix Error'),
|
||
'closeLaunchpad' => _('Close Launchpad and continue to webGUI'),
|
||
'learnMore' => _('Learn more'),
|
||
'popUp' => _('Pop-up'),
|
||
'close' => _('Close'),
|
||
'backToPopUp' => sprintf(_('Back to %s'), _('Pop-up')),
|
||
'closePopUp' => sprintf(_('Close %s'), _('Pop-up')),
|
||
'contactSupport' => _('Contact Support'),
|
||
'lanIp' => sprintf(_('LAN IP %s'), '{0}'),
|
||
'continueToUnraid' => _('Continue to Unraid'),
|
||
'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'),
|
||
'message' => [
|
||
'registered' => _('Get started by signing in to Unraidnet'),
|
||
'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'),
|
||
'extend' => _('Extend Trial'),
|
||
],
|
||
'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 popup'),
|
||
'trialHasExpiredSeeOptions' => _('Trial has expired, see options below'),
|
||
'extraLinks' => [
|
||
'newTab' => sprintf(_('Opens %s in new tab'), '{0}'),
|
||
'myServers' => _('My Servers Dashboard'),
|
||
'forums' => _('Unraid Forums'),
|
||
'settings' => [
|
||
'text' => _('Settings'),
|
||
'title' => _('SettingsManagementAccessUnraidnet'),
|
||
],
|
||
],
|
||
'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' => _('My Servers'),
|
||
'beta' => _('beta'),
|
||
'errors' => [
|
||
'unraidApi' => [
|
||
'heading' => _('Unraid API Error'),
|
||
'message' => _('Failed to connect to Unraid API'),
|
||
],
|
||
'myServers' => [
|
||
'heading' => _('My Servers Error'),
|
||
'message' => _('Please wait a moment and reload the page'),
|
||
],
|
||
],
|
||
'closeDetails' => _('Close Details'),
|
||
'loading' => _('Loading My Servers data'),
|
||
'displayingLastKnown' => _('Displaying last known server data'),
|
||
'accessLabels' => [
|
||
'current' => _('Current server'),
|
||
'local' => _('Local access'),
|
||
'offline' => _('Server Offline'),
|
||
'remote' => _('Remote access'),
|
||
'unavailable' => _('Access unavailable'),
|
||
],
|
||
],
|
||
'opensNewHttpsWindow' => [
|
||
'base' => sprintf(_('Opens new HTTPS window to %s'), '{0}'),
|
||
'signIn' => sprintf(_('Opens new HTTPS window to %s'), _('Sign In')),
|
||
'signIn' => 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' => [
|
||
'registered' => _('Thanks for supporting Unraid'),
|
||
'notRegistered' => _('Lets unleash your hardware'),
|
||
],
|
||
'message' => [
|
||
'registered' => _('You are all set'),
|
||
'notRegistered' => _('Sign in or sign up to get started'),
|
||
],
|
||
],
|
||
'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 keyGUID mismatch'),
|
||
'message' => [
|
||
'default' => _('The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /boot/config directory on your USB Flash boot device'),
|
||
'replacementEligible' => _('@:stateData.EGUID.error.message.default or click Replace Key to transfer your registration to this new flash device'),
|
||
],
|
||
],
|
||
],
|
||
'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 /boot/config directory on your USB Flash boot device. If you do not have a backup copy of your license key file you may attempt to recover your key. If this was a 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 /boot/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 SettingsNetwork'),
|
||
],
|
||
],
|
||
'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' => _('Automatically closing in'),
|
||
'byeBye' => _('bye, bye 👋'),
|
||
'browserWillSelfDestructIn' => _('Browser will self destruct in'),
|
||
'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' => _('Dont have an account Sign Up'),
|
||
'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 Unraidnet 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'),
|
||
'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'),
|
||
],
|
||
],
|
||
'forgotPassword' => [
|
||
'heading' => _('Forgot Password'),
|
||
'subheading' => _('After resetting your password come back to the Registration Wizard pop-up window to Sign In and complete your servers registration'),
|
||
'resetPasswordNow' => _('Reset Password Now'),
|
||
'backToSignIn' => _('Back to Sign In'),
|
||
],
|
||
'signIn' => [
|
||
'heading' => [
|
||
'signIn' => _('Unraidnet Sign In'),
|
||
'recover' => _('Unraidnet Sign In to Recover Key'),
|
||
'replace' => _('Unraidnet Sign In to Replace Key'),
|
||
],
|
||
'subheading' => _('Please sign in with same email with which you purchased your license'),
|
||
'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' => _('Unraidnet account password'),
|
||
],
|
||
],
|
||
],
|
||
],
|
||
'signUp' => [
|
||
'heading' => _('Sign Up for Unraid.net'),
|
||
'subheading' => _('This setup will help you get your server up and running'),
|
||
],
|
||
'signOut' => [
|
||
'heading' => _('Unraidnet Sign Out'),
|
||
'subheading' => _('This will remove your server from displaying in My Servers'),
|
||
],
|
||
'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 Unraidnet account'), '{0}'),
|
||
'actionSuccess' => sprintf(_('%s is signed in to your Unraidnet account'), '{0}'),
|
||
'loading' => sprintf(_('Signing in %s to Unraid.net account'), '{0}'),
|
||
],
|
||
],
|
||
'signOut' => [
|
||
'tileTitle' => [
|
||
'actionFail' => sprintf(_('%s was not signed out to your Unraid.net account'), '{0}'),
|
||
'actionSuccess' => sprintf(_('%s was signed out to your Unraidnet account'), '{0}'),
|
||
'loading' => sprintf(_('Signing out %s from Unraidnet 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}'),
|
||
],
|
||
'timeout' => sprintf(_('Communication with %s has timed out'), '{0}'),
|
||
'loading1' => _('Please keep this window open'),
|
||
'loading2' => _('Were working our magic'),
|
||
'countdown' => [
|
||
'success' => [
|
||
'prefix' => _('Auto closing in'),
|
||
'text' => _('You can safely close this window'),
|
||
],
|
||
'error' => [
|
||
'prefix' => _('Auto redirecting in'),
|
||
'text' => _('Back to Registration Home'),
|
||
'complete' => _('Back in a flash'),
|
||
],
|
||
],
|
||
],
|
||
'troubleshoot' => [
|
||
'heading' => [
|
||
'default' => _('Troubleshoot'),
|
||
'success' => _('Thank you for contacting Unraid'),
|
||
],
|
||
'subheading' => [
|
||
'default' => _('Forgot what Unraidnet 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 well 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'),
|
||
'form' => [
|
||
'verificationCode' => _('verification code'),
|
||
'verifyCode' => _('Paste or Enter code'),
|
||
],
|
||
'noCode' => _('Didnt get code'),
|
||
],
|
||
'whatIsUnraidNet' => [
|
||
'heading' => _('What is Unraidnet'),
|
||
'subheading' => _('Expand your servers capabilities'),
|
||
'copy' => _('With an Unraidnet account you can start using My Servers beta which gives you access to the following features'),
|
||
'features' => [
|
||
'secureRemoteAccess' => [
|
||
'heading' => _('Secure remote access'),
|
||
'copy' => _('Whether you need to add a share, container, or virtual machine, do it all from the webGui from anytime and anywhere using HTTPS Best of all, all SSL certificates are verified by Lets Encrypt, so no browser security warnings'),
|
||
],
|
||
'realTimeMonitoring' => [
|
||
'heading' => _('Real-time Monitoring'),
|
||
'copy' => _('Get quick real-time info on the status of your servers such as storage, container, and VM usage And not just for one server, but all the servers in your Unraid fleet'),
|
||
],
|
||
'usbFlashBackup' => [
|
||
'heading' => _('USB Flash Backup'),
|
||
'copy' => _('Click a button and your flash is automatically backed up to Unraidnet enabling easy recovery in the event of a device failure Never self-manage host your flash backups again'),
|
||
],
|
||
'regKeyManagement' => [
|
||
'heading' => _('Registration key management'),
|
||
'copy' => _('Download any registration key linked to your account Upgrade keys to higher editions'),
|
||
],
|
||
],
|
||
],
|
||
'notFound' => [
|
||
'subheading' => _('Page Not Found'),
|
||
],
|
||
'notAllowed' => [
|
||
'subheading' => _('Page Not Allowed'),
|
||
],
|
||
],
|
||
],
|
||
],
|
||
];
|
||
?>
|
||
<unraid-user-profile
|
||
apikey="<?=($remote['apikey']) ? $remote['apikey'] : ''?>"
|
||
banner="<?=($display['banner']) ? $display['banner'] : ''?>"
|
||
bgcolor="<?=($backgnd) ? '#'.$backgnd : ''?>"
|
||
displaydesc="<?=($display['headerdescription']!='no') ? 'true' : ''?>"
|
||
expiretime="<?=1000*($var['regTy']=='Trial'||strstr($var['regTy'],'expired')?$var['regTm2']:0)?>"
|
||
locale="<?=($_SESSION['locale']) ? $_SESSION['locale'] : 'en_US'?>"
|
||
locale-messages="<?=rawurlencode(json_encode($upc_translations, JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE))?>"
|
||
reg-wiz-time="<?=($remote['regWizTime']) ? $remote['regWizTime'] : ''?>"
|
||
serverdesc="<?=$var['COMMENT']?>"
|
||
servermodel="<?=$var['SYS_MODEL']?>"
|
||
serverstate="<?=rawurlencode(json_encode($serverstate, JSON_UNESCAPED_SLASHES))?>"
|
||
textcolor="<?=($header) ? '#'.$header : ''?>"
|
||
theme="<?=$display['theme']?>"
|
||
uptime="<?=1000*(time() - round(strtok(exec("cat /proc/uptime"),' ')))?>"
|
||
></unraid-user-profile>
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
|
||
<FILE Name="/usr/local/emhttp/plugins/dynamix/DisplaySettings.page-splice1">
|
||
<INLINE>
|
||
<![CDATA[
|
||
_(Header show description)_:
|
||
: <select name="headerdescription">
|
||
<?=mk_option($display['headerdescription'], "yes",_('Yes'))?>
|
||
<?=mk_option($display['headerdescription'], "no",_('No'))?>
|
||
</select>
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
|
||
<!-- Preserve in case plugin is removed -->
|
||
<FILE Run="/bin/bash" Method="install">
|
||
<INLINE>
|
||
<![CDATA[
|
||
cp -f /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-
|
||
|
||
cat /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php- | sed -e 's/<\/head>/<? include "\/usr\/local\/emhttp\/plugins\/dynamix.unraid.net\/include\/RegWizard.php" ?>\n<\/head>/g' > /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
|
||
|
||
sed -i $'/<style>/{e cat /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice1\n}' /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
|
||
sed -i $'/<\/body>/{e cat /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice2\n}' /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
|
||
sed -i $'/<div class="block">/{e cat /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice3\n}' /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
|
||
sed -i '/<div class="block">/,/<\/div>/d' /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
|
||
|
||
rm /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice1
|
||
rm /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice2
|
||
rm /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php-splice3
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
<FILE Run="/bin/bash" Method="install">
|
||
<INLINE>
|
||
<![CDATA[
|
||
cp -f /usr/local/emhttp/plugins/dynamix/DisplaySettings.page /usr/local/emhttp/plugins/dynamix/DisplaySettings.page-
|
||
|
||
echo -e "\n\n" >> /usr/local/emhttp/plugins/dynamix/DisplaySettings.page-splice1
|
||
|
||
sed -i $'/_(Header custom text color)_/{e cat /usr/local/emhttp/plugins/dynamix/DisplaySettings.page-splice1\n}' /usr/local/emhttp/plugins/dynamix/DisplaySettings.page
|
||
|
||
rm /usr/local/emhttp/plugins/dynamix/DisplaySettings.page-splice1
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
|
||
<!-- gitty up -->
|
||
<FILE Run="/bin/bash" Method="install">
|
||
<INLINE>
|
||
<![CDATA[
|
||
if [ -f /var/local/emhttp/var.ini ]; then
|
||
echo "/etc/rc.d/rc.unraid-api install; /etc/rc.d/rc.flash_backup start" | at -M now
|
||
elif grep -q 6.9.0-beta35 /etc/unraid-version; then
|
||
echo "/etc/rc.d/rc.unraid-api install; /etc/rc.d/rc.flash_backup start" | at -M now + 1 minute
|
||
fi
|
||
|
||
if [ -f /boot/.git ]; then
|
||
git -C /boot rm --quiet --cached /boot/config/plugins/Unraid.net/wc/* &>/dev/null && echo "Removed old javascript files from repo" || exit 0
|
||
fi
|
||
]]>
|
||
</INLINE>
|
||
</FILE>
|
||
|
||
|
||
</PLUGIN>
|