mirror of
https://github.com/nextcloud/nextcloudpi.git
synced 2026-01-10 15:12:01 -03:30
ncp-web: add backups panel
This commit is contained in:
parent
01cd4215a5
commit
f34354c336
@ -100,7 +100,8 @@ tar $compress_arg -cf "$destfile" \
|
||||
exit 1
|
||||
}
|
||||
rm "$dbbackup"
|
||||
chmod 600 "$destfile"
|
||||
chmod 640 "$destfile"
|
||||
chown :www-data "$destfile"
|
||||
|
||||
echo "backup $destfile generated"
|
||||
EOF
|
||||
|
||||
10
changelog.md
10
changelog.md
@ -1,9 +1,13 @@
|
||||
|
||||
[v1.11.4](https://github.com/nextcloud/nextcloudpi/commit/62a7f45) (2019-04-28) letsencrypt: switch to apt version
|
||||
[v1.12.0](https://github.com/nextcloud/nextcloudpi/commit/703ff6f) (2019-04-29) ncp-web: add backups panel
|
||||
|
||||
[v1.11.3 ](https://github.com/nextcloud/nextcloudpi/commit/71d8f52) (2019-04-09) nc-restore: check btrfs command
|
||||
[v1.11.5](https://github.com/nextcloud/nextcloudpi/commit/01cd421) (2019-04-29) letsencrypt: force renewal by default
|
||||
|
||||
[v1.11.2, master](https://github.com/nextcloud/nextcloudpi/commit/3754609) (2019-04-06) armbian: fix uu
|
||||
[v1.11.4 ](https://github.com/nextcloud/nextcloudpi/commit/b3c7d13) (2019-04-28) letsencrypt: switch to apt version
|
||||
|
||||
[v1.11.3 ](https://github.com/nextcloud/nextcloudpi/commit/02efd61) (2019-04-09) nc-restore: check btrfs command
|
||||
|
||||
[v1.11.2 ](https://github.com/nextcloud/nextcloudpi/commit/3754609) (2019-04-06) armbian: fix uu
|
||||
|
||||
[v1.11.1 ](https://github.com/nextcloud/nextcloudpi/commit/a712935) (2019-04-05) nc-backup: fix space calculation
|
||||
|
||||
|
||||
159
ncp-web/backups.php
Normal file
159
ncp-web/backups.php
Normal file
@ -0,0 +1,159 @@
|
||||
<!--
|
||||
NextCloudPi Web Backups Panel
|
||||
|
||||
Copyleft 2019 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com>
|
||||
GPL licensed (see end of file) * Use at your own risk!
|
||||
|
||||
More at https://nextcloudpi.com
|
||||
-->
|
||||
<?php
|
||||
|
||||
$bkp_cfg = file_get_contents('/usr/local/etc/ncp-config.d/nc-backup.cfg') or exit('backup config not found');
|
||||
$bkp_auto_cfg = file_get_contents('/usr/local/etc/ncp-config.d/nc-backup-auto.cfg') or exit('backup config not found');
|
||||
|
||||
$bkp_json = json_decode($bkp_cfg , true) or exit('invalid format');
|
||||
$bkp_auto_json = json_decode($bkp_auto_cfg, true) or exit('invalid format');
|
||||
|
||||
$bkp_dir = $bkp_json['params'][0]['value'];
|
||||
$bkp_auto_dir = $bkp_auto_json['params'][1]['value'];
|
||||
|
||||
$bkps = array();
|
||||
$bkps_auto = array();
|
||||
|
||||
if (file_exists($bkp_dir))
|
||||
{
|
||||
$bkps = array_diff(scandir($bkp_dir), array('.', '..'));
|
||||
$bkps = preg_filter('/^/', $bkp_dir. '/', $bkps);
|
||||
}
|
||||
|
||||
if (file_exists($bkp_auto_dir))
|
||||
{
|
||||
$bkps_auto = array_diff(scandir($bkp_auto_dir), array('.', '..'));
|
||||
$bkps_auto = preg_filter('/^/', $bkp_auto_dir . '/', $bkps_auto);
|
||||
}
|
||||
|
||||
$bkps = array_unique(array_merge($bkps, $bkps_auto));
|
||||
|
||||
if (!empty($bkps))
|
||||
{
|
||||
echo <<<HTML
|
||||
<div id="backups-table">
|
||||
<table class="dashtable backuptable">
|
||||
<th>Date</th><th>Size</th><th>Compressed</th><th>Data</th><th></th>
|
||||
HTML;
|
||||
foreach ($bkps as $bkp)
|
||||
{
|
||||
$extension = pathinfo($bkp, PATHINFO_EXTENSION);
|
||||
if ($extension === "tar" || $extension === "gz")
|
||||
{
|
||||
$compressed = "";
|
||||
if ($extension === "gz")
|
||||
$compressed = '✓';
|
||||
|
||||
$date = date("Y M d @ H:i", filemtime($bkp));
|
||||
$size = round(filesize($bkp)/1024/1024) . " MiB";
|
||||
|
||||
$has_data = '';
|
||||
exec("sudo /home/www/ncp-backup-launcher.sh bkp " . escapeshellarg($bkp) . " \"$compressed\"", $output, $ret);
|
||||
if ($ret == 0)
|
||||
$has_data = '✓';
|
||||
|
||||
echo <<<HTML
|
||||
<tr id="$bkp">
|
||||
<td class="long-field" title="$bkp">$date </td>
|
||||
<td class="val-field">$size</td>
|
||||
<td class="ok-field align-center">$compressed</td>
|
||||
<td class="ok-field align-center">$has_data</td>
|
||||
<td>
|
||||
<img class="hidden-btn default-btn download-bkp" title="download" src="../img/download.svg">
|
||||
<img class="hidden-btn default-btn delete-bkp" title="delete" src="../img/delete.svg">
|
||||
<img class="hidden-btn default-btn restore-bkp" title="restore" src="../img/defaults.svg">
|
||||
</td>
|
||||
</tr>
|
||||
HTML;
|
||||
echo '<input type="hidden" name="csrf-token" value="' . getCSRFToken() . '"/>';
|
||||
}
|
||||
}
|
||||
echo <<<HTML
|
||||
</table>
|
||||
</div>
|
||||
HTML;
|
||||
} else {
|
||||
echo "<div>No backups found.</div>";
|
||||
}
|
||||
?>
|
||||
|
||||
</br></br>
|
||||
<h2 class="text-title">Restore from file</h2>
|
||||
<form action="upload.php" method="POST" enctype="multipart/form-data">
|
||||
<div class="restore-upload-btn-wrapper">
|
||||
<input type="file" name="backup" id="restore-upload" accept=".tar,.tar.gz"/>
|
||||
<input id="restore-upload-btn" type="submit" value="Restore"/>
|
||||
</div>
|
||||
</form>
|
||||
</br></br>
|
||||
|
||||
<h2 class="text-title"><?php echo $l->__("Snapshots"); ?></h2>
|
||||
|
||||
<?php
|
||||
|
||||
include( '/var/www/nextcloud/config/config.php' );
|
||||
|
||||
$snap_dir = realpath($CONFIG['datadirectory'] . '/../ncp-snapshots');
|
||||
$snaps = array();
|
||||
if (file_exists($snap_dir))
|
||||
{
|
||||
$snaps = array_diff(scandir($snap_dir), array('.', '..'));
|
||||
$snaps = preg_filter('/^/', $snap_dir . '/', $snaps);
|
||||
}
|
||||
|
||||
if (!empty($snaps))
|
||||
{
|
||||
echo <<<HTML
|
||||
<div id="snapshots-table">
|
||||
<table class="dashtable backuptable">
|
||||
HTML;
|
||||
foreach ($snaps as $snap)
|
||||
{
|
||||
exec("sudo /home/www/ncp-backup-launcher.sh chksnp " . escapeshellarg($snap), $out, $ret);
|
||||
if ($ret == 0)
|
||||
{
|
||||
$snap_name = basename($snap);
|
||||
echo <<<HTML
|
||||
<tr id="$snap">
|
||||
<td class="text-align-left" title="$snap">$snap_name</td>
|
||||
<td>
|
||||
<img class="hidden-btn default-btn delete-snap" title="delete" src="../img/delete.svg">
|
||||
<img class="hidden-btn default-btn restore-snap" title="restore" src="../img/defaults.svg">
|
||||
</td>
|
||||
</tr>
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
echo <<<HTML
|
||||
</table>
|
||||
</div>
|
||||
HTML;
|
||||
} else {
|
||||
echo "<div>No snapshots found.</div>";
|
||||
}
|
||||
?>
|
||||
|
||||
<!--
|
||||
License
|
||||
|
||||
This script is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This script is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this script; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
-->
|
||||
@ -1076,7 +1076,7 @@ select {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#loading-info-gif {
|
||||
.loading-section-gif {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@ -1150,6 +1150,9 @@ select {
|
||||
.icon-search {
|
||||
background-image: url('../img/search.svg');
|
||||
}
|
||||
.icon-backups {
|
||||
background-image: url('../img/defaults-white.svg');
|
||||
}
|
||||
.icon-config {
|
||||
background-image: url('../img/settings-white.svg');
|
||||
}
|
||||
@ -1223,6 +1226,18 @@ a#versionlink:hover {
|
||||
max-width: 210px;
|
||||
}
|
||||
|
||||
#confirmation-dialog {
|
||||
position:fixed;
|
||||
top:0;
|
||||
bottom:0;
|
||||
height:100%;
|
||||
width:100%;
|
||||
background-color:rgba(0, 0, 0, 0.5);
|
||||
z-index:9000;
|
||||
text-align:center;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
display:block;
|
||||
background: white;
|
||||
@ -1249,7 +1264,7 @@ a#versionlink:hover {
|
||||
opacity:0.75
|
||||
}
|
||||
|
||||
#close-wizard {
|
||||
.close-dialog-x {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
@ -1319,6 +1334,23 @@ a#versionlink:hover {
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
}
|
||||
|
||||
.backuptable td {
|
||||
text-align: right;
|
||||
}
|
||||
.text-align-left {
|
||||
text-align: left !important;
|
||||
padding-left: 1em;
|
||||
}
|
||||
.backuptable th {
|
||||
text-align: center;
|
||||
}
|
||||
#backups-content div {
|
||||
text-align: center;
|
||||
}
|
||||
.align-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
#dashboard-suggestions {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
@ -1353,7 +1385,23 @@ a#versionlink:hover {
|
||||
-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)';
|
||||
opacity: 0.5;
|
||||
}
|
||||
.pwd-btn:hover, .default-btn:hover {
|
||||
-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)';
|
||||
opacity: 1;
|
||||
|
||||
.hidden-btn {
|
||||
cursor: pointer;
|
||||
-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=0)';
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.backuptable tr:hover img {
|
||||
-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)';
|
||||
opacity: 0.5;
|
||||
}
|
||||
.pwd-btn:hover, .default-btn:hover {
|
||||
-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)' !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
.restore-upload-btn-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
75
ncp-web/download.php
Normal file
75
ncp-web/download.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
///
|
||||
// NextCloudPi Web Panel backend
|
||||
//
|
||||
// Copyleft 2019 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com>
|
||||
// GPL licensed (see end of file) * Use at your own risk!
|
||||
//
|
||||
// More at https://nextcloudpi.com
|
||||
///
|
||||
|
||||
include ('csrf.php');
|
||||
session_start();
|
||||
|
||||
// CSRF check
|
||||
$token = isset($_REQUEST['token']) ? $_REQUEST['token'] : '';
|
||||
if ( empty($token) || !validateCSRFToken($token) )
|
||||
exit('Unauthorized download');
|
||||
|
||||
if (!isset($_REQUEST["bkp"]))
|
||||
die();
|
||||
|
||||
$file = $_REQUEST["bkp"];
|
||||
|
||||
if (!file_exists($file))
|
||||
die('File not found');
|
||||
|
||||
if (!is_readable($file))
|
||||
die('NCP does not have read permissions on this file');
|
||||
|
||||
$size = filesize($file);
|
||||
|
||||
$extension = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ($extension === "tar" )
|
||||
$mime_type = 'application/x-tar';
|
||||
else if( $extension === "gz")
|
||||
$mime_type = 'application/x-gzip';
|
||||
else
|
||||
die();
|
||||
|
||||
ob_start();
|
||||
ob_clean();
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: ' . $mime_type);
|
||||
header("Content-Transfer-Encoding: Binary");
|
||||
header("Content-disposition: attachment; filename=\"" . basename($file) . "\"");
|
||||
header('Content-Length: ' . $size);
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
|
||||
$chunksize = 8 * (1024 * 1024);
|
||||
if($size > $chunksize)
|
||||
{
|
||||
$handle = fopen($file, 'rb') or die("Error opening file");
|
||||
|
||||
while (!feof($handle))
|
||||
{
|
||||
$buffer = fread($handle, $chunksize);
|
||||
echo $buffer;
|
||||
|
||||
ob_flush();
|
||||
flush();
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
}
|
||||
else
|
||||
readfile($file);
|
||||
|
||||
ob_flush();
|
||||
flush();
|
||||
|
||||
exit();
|
||||
|
||||
?>
|
||||
@ -123,7 +123,6 @@ function print_config_forms( $l /* translations l10n object */ )
|
||||
$cfg_dir = '/usr/local/etc/ncp-config.d/';
|
||||
$d_iterator = new RecursiveDirectoryIterator($bin_dir);
|
||||
$iterator = new RecursiveIteratorIterator($d_iterator);
|
||||
$objects = new RegexIterator($iterator, '/^.+\.sh$/i', RecursiveRegexIterator::GET_MATCH);
|
||||
|
||||
$ret = "";
|
||||
$sections = array_diff(scandir($bin_dir), array('.', '..', 'l10n'));
|
||||
@ -167,7 +166,6 @@ function print_sidebar( $l /* translations l10n object */, $ticks /* wether to c
|
||||
$cfg_dir = '/usr/local/etc/ncp-config.d/';
|
||||
$d_iterator = new RecursiveDirectoryIterator($bin_dir);
|
||||
$iterator = new RecursiveIteratorIterator($d_iterator);
|
||||
$objects = new RegexIterator($iterator, '/^.+\.sh$/i', RecursiveRegexIterator::GET_MATCH);
|
||||
|
||||
$ret = "";
|
||||
$sections = array_diff(scandir($bin_dir), array('.', '..', 'l10n'));
|
||||
|
||||
54
ncp-web/img/defaults-white.svg
Normal file
54
ncp-web/img/defaults-white.svg
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewbox="0 0 16 16"
|
||||
id="svg4"
|
||||
sodipodi:docname="defaults-white.svg"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="640"
|
||||
inkscape:window-height="480"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.75"
|
||||
inkscape:cx="8"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg4" />
|
||||
<path
|
||||
d="m7.9319 2.4252c-3.4324 0-5.6787 2.9953-5.5301 5.8394h-1.8778l3.3924 3.4063 3.5454-3.3664h-1.8657c-0.20594-1.4772 1.0106-2.706 2.3366-2.6868 1.386 0.020855 2.4331 1.0688 2.4331 2.3758 0.07821 1.3851-1.4164 2.9788-3.4463 2.1985 0 1.0688 0.00261 2.2115 0 3.2717 3.641 0.72124 6.6389-2.1811 6.6389-5.431 0-3.0961-2.5374-5.6074-5.6266-5.6074z"
|
||||
id="path2"
|
||||
style="fill:#ffffff" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
1
ncp-web/img/delete.svg
Normal file
1
ncp-web/img/delete.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 16 16" width="16" height="16"><path d="M6.5 1L6 2H3c-.554 0-1 .446-1 1v1h12V3c0-.554-.446-1-1-1h-3l-.5-1zM3 5l.875 9c.06.55.573 1 1.125 1h6c.552 0 1.064-.45 1.125-1L13 5z"/></svg>
|
||||
|
After Width: | Height: | Size: 247 B |
1
ncp-web/img/download.svg
Normal file
1
ncp-web/img/download.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 16 16" width="16" height="16"><path d="M6 1h4v7h5l-7 7-7-7h5z"/></svg>
|
||||
|
After Width: | Height: | Size: 138 B |
@ -104,7 +104,7 @@ if ($ret == 0) {
|
||||
<br>
|
||||
<a href="wizard"> <button type="button" class="wizard-btn" id="go-wizard">{$l->__("run")} </button></a>
|
||||
<button type="button" class="first-run-close" id="skip-wizard" >{$l->__("skip")} </button>
|
||||
<button type="button" class="first-run-close" id="close-wizard">{$l->__("close")}</button>
|
||||
<button type="button" class="first-run-close close-dialog-x">{$l->__("close")}</button>
|
||||
<br><br>
|
||||
</div>
|
||||
</div>
|
||||
@ -113,6 +113,20 @@ HTML;
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="confirmation-dialog" class="hidden">
|
||||
<div class='dialog'>
|
||||
<br><br>
|
||||
<h2 id="config-box-title">Are you sure?</h2>
|
||||
<br>
|
||||
<p>Click OK to confirm this operation</p>
|
||||
<br>
|
||||
<button type="button" id="confirmation-dialog-ok"> OK </button>
|
||||
<button type="button" class="confirmation-dialog-close"> Cancel </button>
|
||||
<button type="button" class="confirmation-dialog-close close-dialog-x">Close</button>
|
||||
<br><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header role="banner"><div id="header">
|
||||
<div id="header-left">
|
||||
<a href="https://ownyourbits.com" id="nextcloudpi" target="_blank" tabindex="1">
|
||||
@ -166,6 +180,11 @@ HTML;
|
||||
<div class="icon-dashboard"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="backups-btn" title="<?php echo $l->__("Backups and snapshots"); ?>">
|
||||
<div class="expand">
|
||||
<div class="icon-backups"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="config-btn" title="<?php echo $l->__("Nextcloud Configuration"); ?>">
|
||||
<div class="expand">
|
||||
<div class="icon-config"></div>
|
||||
@ -213,7 +232,13 @@ HTML;
|
||||
<h2 class="text-title"><?php echo $l->__("System Info"); ?></h2>
|
||||
<div id="dashboard-suggestions" class="table-wrapper"></div>
|
||||
<div id="dashboard-table" class="outputbox table-wrapper"></div>
|
||||
<div id="loading-info-gif"> <img src="img/loading-small.gif"> </div>
|
||||
<div id="loading-info-gif" class="loading-section-gif"> <img src="img/loading-small.gif"> </div>
|
||||
</div>
|
||||
|
||||
<div id="backups-wrapper" class="content-box <?php if($_GET['app'] != 'backups') echo 'hidden';?>">
|
||||
<h2 class="text-title"><?php echo $l->__("Backups"); ?></h2>
|
||||
<div id="backups-content" class="table-wrapper"></div>
|
||||
<div id="loading-backups-gif" class="loading-section-gif"> <img src="img/loading-small.gif"> </div>
|
||||
</div>
|
||||
|
||||
<div id="nc-config-wrapper" class="content-box <?php if($_GET['app'] != 'config') echo 'hidden';?>">
|
||||
|
||||
@ -4,20 +4,23 @@
|
||||
// Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com>
|
||||
// GPL licensed (see end of file) * Use at your own risk!
|
||||
//
|
||||
// More at https://ownyourbits.com/2017/02/13/nextcloud-ready-raspberry-pi-image/
|
||||
// More at https://nextcloudpi.com
|
||||
///
|
||||
|
||||
var MINI = require('minified');
|
||||
var $ = MINI.$, $$ = MINI.$$, EE = MINI.EE;
|
||||
var selectedID = null;
|
||||
var selectedID = null;
|
||||
var ncp_app_list = null;
|
||||
var search_box = null;
|
||||
var lock = false;
|
||||
var search_box = null;
|
||||
var lock = false;
|
||||
|
||||
// URL based navigation
|
||||
// TODO unify repeating code
|
||||
window.onpopstate = function(event) {
|
||||
selectedID = location.search.split('=')[1];
|
||||
if (selectedID == 'config')
|
||||
if (selectedID == 'backups')
|
||||
switch_to_section('backups');
|
||||
else if (selectedID == 'config')
|
||||
switch_to_section('nc-config');
|
||||
else if (selectedID == 'dashboard')
|
||||
switch_to_section('dashboard');
|
||||
@ -27,14 +30,16 @@ window.onpopstate = function(event) {
|
||||
|
||||
function errorMsg()
|
||||
{
|
||||
$('#config-box').fill( "Something went wrong. Try refreshing the page" );
|
||||
$('#app-content').fill( "Something went wrong. Try refreshing the page" );
|
||||
}
|
||||
|
||||
function switch_to_section(section)
|
||||
{
|
||||
// TODO unify repeating code
|
||||
$( '#config-wrapper > div' ).hide();
|
||||
$( '#dashboard-wrapper' ).hide();
|
||||
$( '#nc-config-wrapper' ).hide();
|
||||
$( '#backups-wrapper' ).hide();
|
||||
$( '#' + section + '-wrapper' ).show();
|
||||
$( '#app-navigation ul' ).set('-active');
|
||||
selectedID = null;
|
||||
@ -123,10 +128,169 @@ function print_dashboard()
|
||||
$('#loading-info-gif').hide();
|
||||
$('#dashboard-table').ht( ret.table );
|
||||
$('#dashboard-suggestions').ht( ret.suggestions );
|
||||
reload_sidebar();
|
||||
print_backups();
|
||||
} ).error( errorMsg );
|
||||
}
|
||||
|
||||
function del_bkp(button)
|
||||
{
|
||||
var tr = button.up().up();
|
||||
var path = tr.get('.id');
|
||||
$.request('post', 'ncp-launcher.php', { action:'del-bkp',
|
||||
value: path,
|
||||
csrf_token: $( '#csrf-token' ).get( '.value' ) }).then(
|
||||
function success( result )
|
||||
{
|
||||
var ret = $.parseJSON( result );
|
||||
if ( ret.token )
|
||||
$('#csrf-token').set( { value: ret.token } );
|
||||
if ( ret.ret && ret.ret == '0' ) // means that the process was launched
|
||||
tr.remove();
|
||||
else
|
||||
console.log('failed removing ' + path);
|
||||
}
|
||||
).error( errorMsg )
|
||||
}
|
||||
|
||||
function restore_bkp(button)
|
||||
{
|
||||
var tr = button.up().up();
|
||||
var path = tr.get('.id');
|
||||
click_app($('#nc-restore'));
|
||||
history.pushState(null, selectedID, "?app=" + selectedID);
|
||||
$('#nc-restore-BACKUPFILE').set({ value: path });
|
||||
$('#nc-restore-config-button').trigger('click');
|
||||
}
|
||||
|
||||
function restore_snap(button)
|
||||
{
|
||||
var tr = button.up().up();
|
||||
var path = tr.get('.id');
|
||||
click_app($('#nc-restore-snapshot'));
|
||||
history.pushState(null, selectedID, "?app=" + selectedID);
|
||||
$('#nc-restore-snapshot-SNAPSHOT').set({ value: path });
|
||||
$('#nc-restore-snapshot-config-button').trigger('click');
|
||||
}
|
||||
|
||||
function del_snap(button)
|
||||
{
|
||||
var tr = button.up().up();
|
||||
var path = tr.get('.id');
|
||||
$.request('post', 'ncp-launcher.php', { action:'del-snap',
|
||||
value: path,
|
||||
csrf_token: $('#csrf-token').get('.value') }).then(
|
||||
function success( result )
|
||||
{
|
||||
var ret = $.parseJSON( result );
|
||||
if ( ret.token )
|
||||
$('#csrf-token').set( { value: ret.token } );
|
||||
if ( ret.ret && ret.ret == '0' ) // means that the process was launched
|
||||
tr.remove();
|
||||
else
|
||||
console.log('failed removing ' + path);
|
||||
}
|
||||
).error( errorMsg )
|
||||
}
|
||||
|
||||
function restore_upload(button)
|
||||
{
|
||||
var file = $$('#restore-upload').files[0];
|
||||
if (!file) return;
|
||||
var upload_token = $('#csrf-token').get('.value');
|
||||
var form_data = new FormData();
|
||||
form_data.append('backup', file);
|
||||
form_data.append('csrf_token', upload_token);
|
||||
$.request('post', 'upload.php', form_data).then(
|
||||
function success( result )
|
||||
{
|
||||
var ret = $.parseJSON( result );
|
||||
if ( ret.token )
|
||||
$('#csrf-token').set( { value: ret.token } );
|
||||
if ( ret.ret && ret.ret == '0' ) // means that the process was launched
|
||||
{
|
||||
click_app($('#nc-restore'));
|
||||
history.pushState(null, selectedID, "?app=" + selectedID);
|
||||
$('#nc-restore-BACKUPFILE').set({ value: '/tmp/' + upload_token.replace('/', '') + file.name });
|
||||
$('#nc-restore-config-button').trigger('click');
|
||||
}
|
||||
else
|
||||
console.log('error uploading ' + file);
|
||||
}
|
||||
).error( errorMsg )
|
||||
}
|
||||
|
||||
clicked_dialog_button = null;
|
||||
clicked_dialog_action = null;
|
||||
|
||||
function dialog_action(button)
|
||||
{
|
||||
if ( clicked_dialog_action && clicked_dialog_button)
|
||||
clicked_dialog_action(clicked_dialog_button);
|
||||
}
|
||||
|
||||
// backups
|
||||
function set_backup_handlers()
|
||||
{
|
||||
$( '.download-bkp' ).on('click', function(e)
|
||||
{
|
||||
var tr = this.up().up();
|
||||
var path = tr.get('.id');
|
||||
window.location.replace('download.php?bkp=' + encodeURIComponent(path) + '&token=' + encodeURIComponent(tr.next().get('.value')));
|
||||
});
|
||||
$( '.delete-bkp' ).on('click', function(e)
|
||||
{
|
||||
$('#confirmation-dialog').show();
|
||||
clicked_dialog_action = del_bkp;
|
||||
clicked_dialog_button = this;
|
||||
});
|
||||
$( '.restore-bkp' ).on('click', function(e)
|
||||
{
|
||||
$('#confirmation-dialog').show();
|
||||
clicked_dialog_action = restore_bkp;
|
||||
clicked_dialog_button = this;
|
||||
});
|
||||
$( '#restore-upload-btn' ).on('click', function(e)
|
||||
{
|
||||
var file = $$('#restore-upload').files[0];
|
||||
if (!file) return;
|
||||
$('#confirmation-dialog').show();
|
||||
clicked_dialog_action = restore_upload;
|
||||
clicked_dialog_button = this;
|
||||
});
|
||||
$( '.restore-snap' ).on('click', function(e)
|
||||
{
|
||||
$('#confirmation-dialog').show();
|
||||
clicked_dialog_action = restore_snap;
|
||||
clicked_dialog_button = this;
|
||||
});
|
||||
$( '.delete-snap' ).on('click', function(e)
|
||||
{
|
||||
$('#confirmation-dialog').show();
|
||||
clicked_dialog_action = del_snap;
|
||||
clicked_dialog_button = this;
|
||||
});
|
||||
}
|
||||
|
||||
function print_backups()
|
||||
{
|
||||
// request
|
||||
$.request('post', 'ncp-launcher.php', { action:'backups',
|
||||
csrf_token: $('#csrf-token-ui').get('.value') }
|
||||
).then(
|
||||
function success( result )
|
||||
{
|
||||
var ret = $.parseJSON( result );
|
||||
if (ret.token)
|
||||
$('#csrf-token-ui').set({ value: ret.token });
|
||||
if (ret.ret && ret.ret == '0') {
|
||||
$('#loading-backups-gif').hide();
|
||||
$('#backups-content').ht(ret.output);
|
||||
set_backup_handlers();
|
||||
reload_sidebar();
|
||||
}
|
||||
}).error( errorMsg );
|
||||
}
|
||||
|
||||
function reload_sidebar()
|
||||
{
|
||||
// request
|
||||
@ -272,9 +436,16 @@ $(function()
|
||||
{
|
||||
if ( ret.ret == '0' )
|
||||
{
|
||||
if( ret.ref && ret.ref == 'nc-update' )
|
||||
window.location.reload( true );
|
||||
reload_sidebar();
|
||||
if (ret.ref)
|
||||
{
|
||||
if (ret.ref == 'nc-update')
|
||||
window.location.reload( true );
|
||||
else if(ret.ref == 'nc-backup')
|
||||
print_backups();
|
||||
if(ret.ref != 'nc-restore' && ret.ref != 'nc-backup') // FIXME PHP is reloaded asynchronously after nc-restore
|
||||
reload_sidebar();
|
||||
}
|
||||
|
||||
$('.circle-retstatus').set('+icon-green-circle');
|
||||
}
|
||||
else
|
||||
@ -354,7 +525,6 @@ $(function()
|
||||
function dirname(path) { return path.replace(/\\/g,'/').replace(/\/[^\/]*$/, ''); }
|
||||
|
||||
var span = this.up().select('span', true);
|
||||
console.log(span);
|
||||
var path = dirname(this.get('.value'));
|
||||
|
||||
// request
|
||||
@ -470,6 +640,22 @@ $(function()
|
||||
$( '#first-run-wizard' ).hide();
|
||||
} );
|
||||
|
||||
// dialog confirmation
|
||||
$( '#confirmation-dialog-ok' ).on('click', function(e)
|
||||
{
|
||||
$( '#confirmation-dialog' ).hide();
|
||||
dialog_action();
|
||||
} );
|
||||
$( '.confirmation-dialog-close' ).on('click', function(e)
|
||||
{
|
||||
$( '#confirmation-dialog' ).hide();
|
||||
} );
|
||||
$( '#confirmation-dialog' ).on('|click', function(e)
|
||||
{
|
||||
if( e.target.id == 'confirmation-dialog' )
|
||||
$( '#confirmation-dialog' ).hide();
|
||||
} );
|
||||
|
||||
// click to nextcloud button
|
||||
$('#nextcloud-btn').set( '@href', window.location.protocol + '//' + window.location.hostname );
|
||||
|
||||
@ -482,6 +668,7 @@ $(function()
|
||||
history.pushState(null, selectedID, "?app=dashboard");
|
||||
} );
|
||||
|
||||
// TODO unify repeating code
|
||||
// config button
|
||||
$( '#config-btn' ).on('click', function(e)
|
||||
{
|
||||
@ -491,6 +678,15 @@ $(function()
|
||||
history.pushState(null, selectedID, "?app=config");
|
||||
} );
|
||||
|
||||
// backups button
|
||||
$( '#backups-btn' ).on('click', function(e)
|
||||
{
|
||||
if ( lock ) return;
|
||||
close_menu();
|
||||
switch_to_section( 'backups' );
|
||||
history.pushState(null, selectedID, "?app=backups");
|
||||
} );
|
||||
|
||||
// language selection
|
||||
var langold = $( '#language-selection' ).get( '.value' );
|
||||
$( '#language-selection' ).on( 'change', function(e)
|
||||
|
||||
@ -136,6 +136,21 @@ else if ( $_POST['action'] == "info" )
|
||||
echo ' "ret": "' . $ret . '" }';
|
||||
}
|
||||
|
||||
//
|
||||
// backups
|
||||
//
|
||||
else if ( $_POST['action'] == "backups" )
|
||||
{
|
||||
ob_start();
|
||||
include('backups.php');
|
||||
$backups_page = ob_get_clean();
|
||||
|
||||
// return JSON
|
||||
echo '{ "token": "' . getCSRFToken() . '",'; // Get new token
|
||||
echo ' "output": ' . json_encode($backups_page) . ' , ';
|
||||
echo ' "ret": "0" }';
|
||||
}
|
||||
|
||||
//
|
||||
// sidebar
|
||||
//
|
||||
@ -175,6 +190,34 @@ else if ( $_POST['action'] == "path-exists" )
|
||||
echo ' "ret": "' . $ret . '" }';
|
||||
}
|
||||
|
||||
//
|
||||
// del backup
|
||||
//
|
||||
else if ( $_POST['action'] == "del-bkp" )
|
||||
{
|
||||
$file = escapeshellarg($_POST['value']);
|
||||
$ret = 1;
|
||||
exec("sudo /home/www/ncp-backup-launcher.sh del $file", $out, $ret);
|
||||
|
||||
// return JSON
|
||||
echo '{ "token": "' . getCSRFToken() . '",'; // Get new token
|
||||
echo ' "ret": "' . $ret . '" }';
|
||||
}
|
||||
|
||||
//
|
||||
// del snapshot
|
||||
//
|
||||
else if ( $_POST['action'] == "del-snap" )
|
||||
{
|
||||
$file = escapeshellarg($_POST['value']);
|
||||
$ret = 1;
|
||||
exec("sudo /home/www/ncp-backup-launcher.sh delsnp $file", $out, $ret);
|
||||
|
||||
// return JSON
|
||||
echo '{ "token": "' . getCSRFToken() . '",'; // Get new token
|
||||
echo ' "ret": "' . $ret . '" }';
|
||||
}
|
||||
|
||||
//
|
||||
// poweroff
|
||||
//
|
||||
|
||||
47
ncp-web/upload.php
Normal file
47
ncp-web/upload.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
///
|
||||
// NextCloudPi Web Panel backend
|
||||
//
|
||||
// Copyleft 2019 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com>
|
||||
// GPL licensed (see end of file) * Use at your own risk!
|
||||
//
|
||||
// More at https://nextcloudpi.com
|
||||
///
|
||||
|
||||
include ('csrf.php');
|
||||
session_start();
|
||||
|
||||
// CSRF check
|
||||
$token = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : '';
|
||||
if ( empty($token) || !validateCSRFToken($token) )
|
||||
exit( '{ "output": "Unauthorized request. Try reloading the page" }' );
|
||||
|
||||
isset($_FILES['backup']) or exit( '{ "output": "no upload" }' );
|
||||
|
||||
$error=$_FILES['backup']['error'];
|
||||
if ($error !== 0)
|
||||
exit( '{ "output": "upload error ' . $error . '" }' );
|
||||
|
||||
$file_name = $_POST['csrf_token'] . basename($_FILES['backup']['name']);
|
||||
$file_name = str_replace('/', '', $file_name);
|
||||
$file_size = $_FILES['backup']['size'];
|
||||
$file_tmp = $_FILES['backup']['tmp_name'];
|
||||
$file_type = $_FILES['backup']['type'];
|
||||
|
||||
preg_match( '/\.\./' , $file_name, $matches )
|
||||
and exit( '{ "output": "Invalid input" , "token": "' . getCSRFToken() . '" }' );
|
||||
|
||||
if($file_size === 0)
|
||||
$errors[]='No file';
|
||||
|
||||
$extension = pathinfo($file_name, PATHINFO_EXTENSION);
|
||||
if ($extension !== "tar" and $extension !== "gz")
|
||||
exit( '{ "output": "invalid file" }' );
|
||||
|
||||
if (!move_uploaded_file($file_tmp, sys_get_temp_dir() . '/' . $file_name))
|
||||
exit('{ "output": "upload denied" }');
|
||||
|
||||
// return JSON
|
||||
echo '{ "token": "' . getCSRFToken() . '",'; // Get new token
|
||||
echo ' "ret": "0" }';
|
||||
?>
|
||||
32
ncp.sh
32
ncp.sh
@ -22,7 +22,7 @@ install()
|
||||
{
|
||||
# NCP-CONFIG
|
||||
apt-get update
|
||||
$APTINSTALL git dialog whiptail jq
|
||||
$APTINSTALL git dialog whiptail jq file
|
||||
mkdir -p "$CONFDIR" "$BINDIR"
|
||||
|
||||
# include option in raspi-config (only Raspbian)
|
||||
@ -131,11 +131,39 @@ EOF
|
||||
|
||||
cat > /home/www/ncp-launcher.sh <<'EOF'
|
||||
#!/bin/bash
|
||||
grep -q '[\\&#;`|*?~<>^()[{}$&[:space:]]' <<< "$*" && exit 1
|
||||
source /usr/local/etc/library.sh
|
||||
run_app $1
|
||||
EOF
|
||||
chmod 700 /home/www/ncp-launcher.sh
|
||||
echo "www-data ALL = NOPASSWD: /home/www/ncp-launcher.sh , /sbin/halt, /sbin/reboot" >> /etc/sudoers
|
||||
|
||||
cat > /home/www/ncp-backup-launcher.sh <<'EOF'
|
||||
#!/bin/bash
|
||||
action="${1}"
|
||||
file="${2}"
|
||||
compressed="${3}"
|
||||
grep -q '[\\&#;`|*?~<>^()[{}$&]' <<< "$*" && exit 1
|
||||
[[ "$file" =~ ".." ]] && exit 1
|
||||
[[ "${action}" == "chksnp" ]] && {
|
||||
btrfs subvolume show "$file" &>/dev/null || exit 1
|
||||
exit
|
||||
}
|
||||
[[ "${action}" == "delsnp" ]] && {
|
||||
btrfs subvolume delete "$file" || exit 1
|
||||
exit
|
||||
}
|
||||
[[ -f "$file" ]] || exit 1
|
||||
[[ "$file" =~ ".tar" ]] || exit 1
|
||||
[[ "${action}" == "del" ]] && {
|
||||
[[ "$(file "$file")" =~ "tar archive" ]] || [[ "$(file "$file")" =~ "gzip compressed data" ]] || exit 1
|
||||
rm "$file" || exit 1
|
||||
exit
|
||||
}
|
||||
[[ "$compressed" != "" ]] && pigz="-I pigz"
|
||||
tar $pigz -tf "$file" data &>/dev/null
|
||||
EOF
|
||||
chmod 700 /home/www/ncp-backup-launcher.sh
|
||||
echo "www-data ALL = NOPASSWD: /home/www/ncp-launcher.sh , /home/www/ncp-backup-launcher.sh, /sbin/halt, /sbin/reboot" >> /etc/sudoers
|
||||
|
||||
# NCP AUTO TRUSTED DOMAIN
|
||||
mkdir -p /usr/lib/systemd/system
|
||||
|
||||
41
update.sh
41
update.sh
@ -27,6 +27,8 @@ nc-init
|
||||
UFW
|
||||
nc-snapshot
|
||||
nc-snapshot-auto
|
||||
nc-snapshot-sync
|
||||
nc-restore-snapshot
|
||||
nc-audit
|
||||
nc-hdd-monitor
|
||||
nc-zram
|
||||
@ -187,6 +189,45 @@ EOF
|
||||
# switch back to the apt LE version
|
||||
which letsencrypt &>/dev/null || install_app letsencrypt
|
||||
|
||||
# update launchers
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends file
|
||||
cat > /home/www/ncp-launcher.sh <<'EOF'
|
||||
#!/bin/bash
|
||||
grep -q '[\\&#;`|*?~<>^()[{}$&[:space:]]' <<< "$*" && exit 1
|
||||
source /usr/local/etc/library.sh
|
||||
run_app $1
|
||||
EOF
|
||||
chmod 700 /home/www/ncp-launcher.sh
|
||||
|
||||
cat > /home/www/ncp-backup-launcher.sh <<'EOF'
|
||||
#!/bin/bash
|
||||
action="${1}"
|
||||
file="${2}"
|
||||
compressed="${3}"
|
||||
grep -q '[\\&#;`|*?~<>^()[{}$&]' <<< "$*" && exit 1
|
||||
[[ "$file" =~ ".." ]] && exit 1
|
||||
[[ "${action}" == "chksnp" ]] && {
|
||||
btrfs subvolume show "$file" &>/dev/null || exit 1
|
||||
exit
|
||||
}
|
||||
[[ "${action}" == "delsnp" ]] && {
|
||||
btrfs subvolume delete "$file" || exit 1
|
||||
exit
|
||||
}
|
||||
[[ -f "$file" ]] || exit 1
|
||||
[[ "$file" =~ ".tar" ]] || exit 1
|
||||
[[ "${action}" == "del" ]] && {
|
||||
[[ "$(file "$file")" =~ "tar archive" ]] || [[ "$(file "$file")" =~ "gzip compressed data" ]] || exit 1
|
||||
rm "$file" || exit 1
|
||||
exit
|
||||
}
|
||||
[[ "$compressed" != "" ]] && pigz="-I pigz"
|
||||
tar $pigz -tf "$file" data &>/dev/null
|
||||
EOF
|
||||
chmod 700 /home/www/ncp-backup-launcher.sh
|
||||
sed -i 's|www-data ALL = NOPASSWD: .*|www-data ALL = NOPASSWD: /home/www/ncp-launcher.sh , /home/www/ncp-backup-launcher.sh, /sbin/halt, /sbin/reboot|' /etc/sudoers
|
||||
|
||||
# remove redundant opcache configuration. Leave until update bug is fixed -> https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=815968
|
||||
# Bug #416 reappeared after we moved to php7.2 and debian buster packages. (keep last)
|
||||
[[ "$( ls -l /etc/php/7.2/fpm/conf.d/*-opcache.ini | wc -l )" -gt 1 ]] && rm "$( ls /etc/php/7.2/fpm/conf.d/*-opcache.ini | tail -1 )"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user