rewrite from scratch
This commit is contained in:
Родитель
cbb906912b
Коммит
32b952d5af
|
@ -0,0 +1,2 @@
|
|||
\.idea/
|
||||
vendor/
|
|
@ -1,25 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Frank Karlitschek <frank@karlitschek.de>
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
namespace OCA\Backup\AppInfo;
|
||||
|
||||
|
||||
require_once __DIR__ . '/autoload.php';
|
||||
|
||||
$app = new \OCA\Backup\AppInfo\Application();
|
||||
$app->register();
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\AppInfo;
|
||||
|
||||
|
||||
$composerDir = __DIR__ . '/../vendor/';
|
||||
|
||||
if (is_dir($composerDir) && file_exists($composerDir . 'autoload.php')) {
|
||||
require_once $composerDir . 'autoload.php';
|
||||
}
|
||||
|
|
@ -1,19 +1,31 @@
|
|||
<?xml version="1.0"?>
|
||||
<info>
|
||||
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
|
||||
<id>backup</id>
|
||||
<name>Backup</name>
|
||||
<description><![CDATA[Allows admins to generate a backup of an Nextclod instance and restore it. Possible via occ or REST]]></description>
|
||||
<licence>AGPL</licence>
|
||||
<description><![CDATA[Allows admins to generate a backup of a Nextcloud instance and restore it. Possible via occ or REST]]></description>
|
||||
<licence>agpl</licence>
|
||||
<author mail="maxence@artificial-owl.com">Maxence Lange</author>
|
||||
<author>Frank Karlitschek</author>
|
||||
<version>1.0.0</version>
|
||||
<version>0.1.0</version>
|
||||
<namespace>Backup</namespace>
|
||||
|
||||
<category>tools</category>
|
||||
<website>https://github.com/nextcloud/backup</website>
|
||||
<bugs>https://github.com/nextcloud/backup/issues</bugs>
|
||||
<repository type="git">https://github.com/nextcloud/backup.git</repository>
|
||||
<screenshot>https://raw.githubusercontent.com/nextcloud/backup/master/img/screenshot.png</screenshot>
|
||||
<dependencies>
|
||||
<nextcloud min-version="12" max-version="12" />
|
||||
<nextcloud min-version="16" max-version="17"/>
|
||||
</dependencies>
|
||||
|
||||
<background-jobs>
|
||||
<job>OCA\Backup\Cron\Backup</job>
|
||||
</background-jobs>
|
||||
|
||||
<commands>
|
||||
<command>OCA\Backup\Command\CreateCommand</command>
|
||||
<command>OCA\Backup\Command\RestoreCommand</command>
|
||||
<command>OCA\Backup\Command\Create</command>
|
||||
<command>OCA\Backup\Command\Listing</command>
|
||||
<command>OCA\Backup\Command\Details</command>
|
||||
<command>OCA\Backup\Command\Restore</command>
|
||||
</commands>
|
||||
</info>
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup;
|
||||
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use daita\MySmallPhpTools\DI\DIContainer;
|
||||
use daita\MySmallPhpTools\Exceptions\DependencyInjectionException;
|
||||
use Exception;
|
||||
use OC\Config;
|
||||
use OC\Logger;
|
||||
use OCA\Backup\Model\Backup;
|
||||
use OCA\Backup\Service\BackupService;
|
||||
use OCA\Backup\Service\CliService;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use ZipArchive;
|
||||
|
||||
|
||||
/**
|
||||
* extracting app files
|
||||
*/
|
||||
if (!extractAppFiles()) {
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* init few stuff.
|
||||
*/
|
||||
$verbose = false;
|
||||
if (in_array('-v', $argv) || in_array('--verbose', $argv)) {
|
||||
$verbose = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* loading libs.
|
||||
*/
|
||||
if ($verbose) {
|
||||
echo 'Loading libraries.' . "\n";
|
||||
}
|
||||
|
||||
$classes = [
|
||||
'Service\ArchiveService',
|
||||
'Service\BackupService',
|
||||
'Service\CliService',
|
||||
'Service\ConfigService',
|
||||
'Service\EncryptService',
|
||||
'Service\FilesService',
|
||||
'Service\MiscService',
|
||||
|
||||
'Model\ArchiveFile',
|
||||
'Model\Backup',
|
||||
'Model\BackupArchive',
|
||||
'Model\BackupChunk',
|
||||
'Model\BackupOptions',
|
||||
'Model\Error',
|
||||
'Model\RemoteStorage',
|
||||
|
||||
'ISqlDump',
|
||||
'SqlDump\SqlDumpMySQL',
|
||||
|
||||
'Exceptions\ArchiveCreateException',
|
||||
'Exceptions\ArchiveNotFoundException',
|
||||
'Exceptions\BackupFolderException',
|
||||
'Exceptions\BackupScriptNotFoundException',
|
||||
'Exceptions\VersionException',
|
||||
'Exceptions\EncryptionKeyException',
|
||||
'Exceptions\ArchiveDeleteException',
|
||||
'Exceptions\BackupAppCopyException',
|
||||
'Exceptions\BackupNotFoundException',
|
||||
];
|
||||
|
||||
$mockup = [
|
||||
'OCP\IConfig',
|
||||
'OC\Config',
|
||||
'OCP\ILogger',
|
||||
'OC\Logger'
|
||||
];
|
||||
|
||||
loadClasses($classes, $mockup);
|
||||
|
||||
|
||||
/**
|
||||
* generate Container.
|
||||
*/
|
||||
if ($verbose) {
|
||||
echo 'Generating Container.' . "\n";
|
||||
}
|
||||
$container = new DIContainer();
|
||||
|
||||
$container->registerInterface(IConfig::class, Config::class);
|
||||
$container->registerInterface(ILogger::class, Logger::class);
|
||||
|
||||
|
||||
/**
|
||||
* init Services.
|
||||
*/
|
||||
if ($verbose) {
|
||||
echo 'Loading Services.' . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
/**
|
||||
* @var CliService $cliService
|
||||
*/
|
||||
$cliService = $container->query(CliService::class);
|
||||
} catch (DependencyInjectionException $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
if ($verbose) {
|
||||
echo 'App is ready.' . "\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* init input/output
|
||||
*/
|
||||
$inputDefinition = generateInputDefinition();
|
||||
|
||||
$input = new ArgvInput($argv, $inputDefinition);
|
||||
$output = new ConsoleOutput();
|
||||
$output = $output->section();
|
||||
$cliService->init($input, $output);
|
||||
|
||||
if ($verbose) {
|
||||
$output->writeln('Switching to <info>better</info> console output!');
|
||||
$output->writeln('');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* parsing backup.json
|
||||
*/
|
||||
if ($verbose) {
|
||||
echo 'Parsing backup.json.' . "\n";
|
||||
}
|
||||
$json = file_get_contents(BackupService::SUMMARY_FILE);
|
||||
|
||||
$backup = new Backup();
|
||||
$backup->import(json_decode($json, true));
|
||||
$backup->setLocal(true);
|
||||
|
||||
$backup->setEncryptionKey($input->getOption('key'));
|
||||
$options = $backup->getOptions();
|
||||
$options->setNewRoot($input->getOption('root'));
|
||||
$options->setPath($input->getOption('path'));
|
||||
$options->setSearch($input->getOption('search'));
|
||||
$options->setConfigRaw($input->getOption('config'));
|
||||
$options->setChunk($input->getOption('chunk'));
|
||||
$options->setAll($input->getOption('all'));
|
||||
$options->setArchive($input->getOption('archive'));
|
||||
$options->setFixDataDir($input->getOption('fix-datadirectory'));
|
||||
|
||||
$cliService->displayBackupResume($backup);
|
||||
|
||||
|
||||
/**
|
||||
* let's start based on Options
|
||||
*/
|
||||
try {
|
||||
switch ($input->getArgument('action')) {
|
||||
|
||||
case 'details':
|
||||
$cliService->displayBackupDetails($backup);
|
||||
break;
|
||||
|
||||
case 'restore':
|
||||
$cliService->displayBackupRestore($backup);
|
||||
break;
|
||||
|
||||
case 'files':
|
||||
$cliService->displayFilesList($backup);
|
||||
break;
|
||||
|
||||
default:
|
||||
$output->writeln('details/restore/files');
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "\n" . $e->getMessage() . "\n\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The End.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function extractAppFiles(): bool {
|
||||
if (is_dir(__DIR__ . '/app/')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
echo 'Extracting Backup App files (using PHP/ZipArchive) ' . "\n";
|
||||
|
||||
try {
|
||||
$zip = new ZipArchive();
|
||||
if (($err = $zip->open('app.zip')) !== true) {
|
||||
throw new Exception('failed with error ' . $err);
|
||||
}
|
||||
|
||||
$zip->extractTo('./');
|
||||
$zip->close();
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
echo 'Extracting Backup App files (using unzip command) ' . "\n";
|
||||
system('unzip app.zip');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $classes
|
||||
* @param array $mockups
|
||||
*
|
||||
* @return ClassLoader
|
||||
*/
|
||||
function loadClasses(array $classes, array $mockups): ClassLoader {
|
||||
$r = 'OCA\Backup\\';
|
||||
$p = __DIR__ . '/app/lib/';
|
||||
$map = [];
|
||||
foreach ($classes as $class) {
|
||||
$classPath = str_replace('\\', '/', $class);
|
||||
$map[$r . $class] = $p . $classPath . '.php';
|
||||
}
|
||||
|
||||
foreach ($mockups as $class) {
|
||||
$classPath = str_replace('\\', '/', $class);
|
||||
$map[$class] = $p . 'Mockup/' . $classPath . '.php';
|
||||
}
|
||||
|
||||
$loader = require 'app/vendor/autoload.php';
|
||||
$loader->addClassMap($map);
|
||||
$loader->register();
|
||||
|
||||
return $loader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return InputDefinition
|
||||
*/
|
||||
function generateInputDefinition(): InputDefinition {
|
||||
$input = new InputDefinition();
|
||||
|
||||
$input->addOption(new InputOption('verbose', 'v'));
|
||||
$input->addOption(new InputOption('full-install'));
|
||||
$input->addOption(new InputOption('check'));
|
||||
$input->addOption(new InputOption('key', 'k', InputOption::VALUE_REQUIRED, '', ''));
|
||||
$input->addOption(new InputOption('root', '', InputOption::VALUE_REQUIRED, '', ''));
|
||||
$input->addOption(new InputOption('search', '', InputOption::VALUE_REQUIRED, '', ''));
|
||||
$input->addOption(new InputOption('config', '', InputOption::VALUE_REQUIRED, '', '{}'));
|
||||
$input->addOption(new InputOption('path', '', InputOption::VALUE_REQUIRED, '', ''));
|
||||
$input->addOption(new InputOption('chunk', '', InputOption::VALUE_REQUIRED, '', ''));
|
||||
$input->addOption(new InputOption('archive', '', InputOption::VALUE_REQUIRED, '', ''));
|
||||
$input->addOption(new InputOption('dir', '', InputOption::VALUE_REQUIRED, '', ''));
|
||||
$input->addOption(new InputOption('fix-datadirectory'));
|
||||
$input->addOption(new InputOption('all'));
|
||||
$input->addArgument(new InputArgument('action'));
|
||||
$input->addArgument(new InputArgument('search'));
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "nextcloud/backup",
|
||||
"description": "Backup app",
|
||||
"minimum-stability": "stable",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maxence Lange",
|
||||
"email": "maxence@artificial-owl.com"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.2.0"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"daita/my-small-php-tools": "dev-master",
|
||||
"ifsnop/mysqldump-php": "2.0.0",
|
||||
"symfony/console": "^4.2",
|
||||
"pimple/pimple": "~3.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "nextcloud/backup",
|
||||
"description": "Backup app",
|
||||
"minimum-stability": "stable",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maxence Lange",
|
||||
"email": "maxence@artificial-owl.com"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.2.0"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"daita/my-small-php-tools": "dev-master",
|
||||
"ifsnop/mysqldump-php": "2.0.0",
|
||||
"symfony/console": "^4.2",
|
||||
"pimple/pimple": "~3.0",
|
||||
}
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b6c5df6ef9c263971da6fe6265a51a5f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "daita/my-small-php-tools",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/daita/my-small-php-tools.git",
|
||||
"reference": "e2ac095a0148fec7aaafe5dc9edc20d65c2d1f14"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/daita/my-small-php-tools/zipball/e2ac095a0148fec7aaafe5dc9edc20d65c2d1f14",
|
||||
"reference": "e2ac095a0148fec7aaafe5dc9edc20d65c2d1f14",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"daita\\MySmallPhpTools\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"AGPL-3.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maxence Lange",
|
||||
"email": "maxence@artificial-owl.com"
|
||||
}
|
||||
],
|
||||
"description": "My small PHP Tools",
|
||||
"time": "2019-03-29T18:48:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ifsnop/mysqldump-php",
|
||||
"version": "v2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ifsnop/mysqldump-php.git",
|
||||
"reference": "2f850d6c3ea6d55ca2cb7b37bb568264264f728e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ifsnop/mysqldump-php/zipball/2f850d6c3ea6d55ca2cb7b37bb568264264f728e",
|
||||
"reference": "2f850d6c3ea6d55ca2cb7b37bb568264264f728e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.*",
|
||||
"squizlabs/php_codesniffer": "1.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ifsnop\\": "src/Ifsnop/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Diego Torres",
|
||||
"homepage": "https://github.com/ifsnop",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "This is a php version of linux's mysqldump in terminal \"$ mysqldump -u username -p...\"",
|
||||
"homepage": "https://github.com/ifsnop/mysqldump-php",
|
||||
"keywords": [
|
||||
"backup",
|
||||
"database",
|
||||
"dump",
|
||||
"export",
|
||||
"mysql",
|
||||
"mysqldump",
|
||||
"pdo",
|
||||
"sqlite"
|
||||
],
|
||||
"time": "2015-09-10T19:58:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v3.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/silexphp/Pimple.git",
|
||||
"reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32",
|
||||
"reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"psr/container": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^3.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Pimple": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Pimple, a simple Dependency Injection Container",
|
||||
"homepage": "http://pimple.sensiolabs.org",
|
||||
"keywords": [
|
||||
"container",
|
||||
"dependency injection"
|
||||
],
|
||||
"time": "2018-01-21T07:42:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/container.git",
|
||||
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Container\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common Container Interface (PHP FIG PSR-11)",
|
||||
"homepage": "https://github.com/php-fig/container",
|
||||
"keywords": [
|
||||
"PSR-11",
|
||||
"container",
|
||||
"container-interface",
|
||||
"container-interop",
|
||||
"psr"
|
||||
],
|
||||
"time": "2017-02-14T16:28:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "24206aff3efe6962593297e57ef697ebb220e384"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/24206aff3efe6962593297e57ef697ebb220e384",
|
||||
"reference": "24206aff3efe6962593297e57ef697ebb220e384",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/contracts": "^1.0",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/dependency-injection": "<3.4",
|
||||
"symfony/process": "<3.3"
|
||||
},
|
||||
"provide": {
|
||||
"psr/log-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~3.4|~4.0",
|
||||
"symfony/dependency-injection": "~3.4|~4.0",
|
||||
"symfony/event-dispatcher": "~3.4|~4.0",
|
||||
"symfony/lock": "~3.4|~4.0",
|
||||
"symfony/process": "~3.4|~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "For using the console logger",
|
||||
"symfony/event-dispatcher": "",
|
||||
"symfony/lock": "",
|
||||
"symfony/process": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Console\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-04-01T07:32:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/contracts",
|
||||
"version": "v1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/contracts.git",
|
||||
"reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf",
|
||||
"reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/cache": "^1.0",
|
||||
"psr/container": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/cache": "When using the Cache contracts",
|
||||
"psr/container": "When using the Service contracts",
|
||||
"symfony/cache-contracts-implementation": "",
|
||||
"symfony/service-contracts-implementation": "",
|
||||
"symfony/translation-contracts-implementation": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Contracts\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"**/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "A set of abstractions extracted out of the Symfony components",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"abstractions",
|
||||
"contracts",
|
||||
"decoupling",
|
||||
"interfaces",
|
||||
"interoperability",
|
||||
"standards"
|
||||
],
|
||||
"time": "2018-12-05T08:06:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609",
|
||||
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"daita/my-small-php-tools": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "7.2.0"
|
||||
}
|
||||
}
|
|
@ -1,9 +1,16 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Frank Karlitschek <frank@karlitschek.de>
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* @author Frank karlitschek <frank@karlitschek.de>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -21,18 +28,32 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\AppInfo;
|
||||
|
||||
|
||||
use OCP\AppFramework\App;
|
||||
|
||||
|
||||
/**
|
||||
* Class Application
|
||||
*
|
||||
* @package OCA\Backup\AppInfo
|
||||
*/
|
||||
class Application extends App {
|
||||
|
||||
|
||||
const APP_ID = 'backup';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(self::APP_ID);
|
||||
}
|
||||
|
||||
public function register() {
|
||||
/**
|
||||
* Application constructor.
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
public function __construct(array $params = []) {
|
||||
parent::__construct(self::APP_ID, $params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,6 @@
|
|||
|
||||
namespace OCA\Backup\Backup;
|
||||
|
||||
use OCA\Backup\AppInfo\Application;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCSController;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\IRequest;
|
||||
|
||||
class Create {
|
||||
|
||||
/** @var path */
|
||||
|
|
|
@ -23,13 +23,6 @@
|
|||
|
||||
namespace OCA\Backup\Backup;
|
||||
|
||||
use OCA\Backup\AppInfo\Application;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCSController;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\IRequest;
|
||||
|
||||
class Restore {
|
||||
|
||||
/** @var path */
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Command;
|
||||
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Backup\Service\BackupService;
|
||||
use OCA\Backup\Service\MiscService;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\NotPermittedException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Class Backup
|
||||
*
|
||||
* @package OCA\Backup\Command
|
||||
*/
|
||||
class Create extends Base {
|
||||
|
||||
|
||||
/** @var BackupService */
|
||||
private $backupService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* Backup constructor.
|
||||
*
|
||||
* @param BackupService $backupService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(BackupService $backupService, MiscService $miscService) {
|
||||
$this->backupService = $backupService;
|
||||
$this->miscService = $miscService;
|
||||
|
||||
parent::__construct();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function configure() {
|
||||
$this->setName('backup:create')
|
||||
->setDescription('Generate a backup of the instance');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*
|
||||
* @throws NotPermittedException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$backup = $this->backupService->backup();
|
||||
|
||||
// echo '> ' . json_encode($backup, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Frank Karlitschek <frank@karlitschek.de>
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Backup\Command;
|
||||
|
||||
use OCA\Backup\Backup\Create;
|
||||
use OCA\Backup\AppInfo\Application;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class CreateCommand extends Command {
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('backup:create')
|
||||
->setDescription('Generate a backup of the instance')
|
||||
->addArgument(
|
||||
'path',
|
||||
InputArgument::REQUIRED,
|
||||
'The path where the backup should be created'
|
||||
)
|
||||
->addOption(
|
||||
'password',
|
||||
'pass',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Optionally password for an encrypted backup',
|
||||
''
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
|
||||
$path = $input->getArgument('path');
|
||||
|
||||
if ($path == '') {
|
||||
$output->writeln('Backup path not defined');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$password = $input->getOption('password');
|
||||
if ($password == '') {
|
||||
$output->writeln('Password not specified');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$backup = new \OCA\Backup\Backup\Create($path);
|
||||
$backup -> password($password);
|
||||
$backup -> create();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Command;
|
||||
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Backup\Exceptions\ArchiveDeleteException;
|
||||
use OCA\Backup\Exceptions\BackupNotFoundException;
|
||||
use OCA\Backup\Exceptions\EncryptionKeyException;
|
||||
use OCA\Backup\Service\ArchiveService;
|
||||
use OCA\Backup\Service\BackupService;
|
||||
use OCA\Backup\Service\CliService;
|
||||
use OCA\Backup\Service\MiscService;
|
||||
use OCP\Files\IAppData;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\NotPermittedException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Class Backup
|
||||
*
|
||||
* @package OCA\Backup\Command
|
||||
*/
|
||||
class Details extends Base {
|
||||
|
||||
|
||||
/** @var IAppData */
|
||||
private $appData;
|
||||
|
||||
/** @var CliService */
|
||||
private $cliService;
|
||||
|
||||
/** @var BackupService */
|
||||
private $backupService;
|
||||
|
||||
/** @var ArchiveService */
|
||||
private $archiveService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* Backup constructor.
|
||||
*
|
||||
* @param IAppData $appData
|
||||
* @param CliService $cliService
|
||||
* @param BackupService $backupService
|
||||
* @param ArchiveService $archiveService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(
|
||||
IAppData $appData, CliService $cliService, BackupService $backupService,
|
||||
ArchiveService $archiveService, MiscService $miscService
|
||||
) {
|
||||
$this->appData = $appData;
|
||||
$this->cliService = $cliService;
|
||||
$this->backupService = $backupService;
|
||||
$this->archiveService = $archiveService;
|
||||
$this->miscService = $miscService;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function configure() {
|
||||
$this->setName('backup:details')
|
||||
->addArgument('token', InputArgument::REQUIRED, 'token of the backup')
|
||||
->addOption('source', 's', InputOption::VALUE_REQUIRED, 'specify source')
|
||||
->addOption(
|
||||
'check', 'c', InputOption::VALUE_NONE, 'verify the integrity of encrypted files'
|
||||
)
|
||||
->addOption(
|
||||
'key', 'k', InputOption::VALUE_REQUIRED,
|
||||
'verify the integrity of the decrypted archive files'
|
||||
)
|
||||
->addOption('json', 'j', InputOption::VALUE_NONE, 'display json')
|
||||
->setDescription('Details about a backup');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*
|
||||
* @throws BackupNotFoundException
|
||||
* @throws NotFoundException
|
||||
* @throws NotPermittedException
|
||||
* @throws EncryptionKeyException
|
||||
* @throws ArchiveDeleteException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
|
||||
$output = new ConsoleOutput();
|
||||
$output = $output->section();
|
||||
$this->cliService->init($input, $output);
|
||||
|
||||
/** TODO: manage sources:
|
||||
* - default is appdata: we assume the files are in oc_cache and the world is a nice place.
|
||||
* - source could be in the format files://user@path/ if backups files are available in
|
||||
* the files app
|
||||
* - it would also be nice to add a PHP script at the root of the folder that contains
|
||||
* the backup. The script would:
|
||||
* > download the right version of nextcloud (from backup.json),
|
||||
* > auto-extract the archives files at the right place.
|
||||
*/
|
||||
$token = $input->getArgument('token');
|
||||
$backup = $this->backupService->getBackup($token);
|
||||
|
||||
if ($input->getOption('json')) {
|
||||
echo json_encode($backup, JSON_PRETTY_PRINT) . "\n";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cliService->displayBackupResume($backup);
|
||||
$this->cliService->displayBackupDetails($backup);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Command;
|
||||
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Backup\Service\BackupService;
|
||||
use OCA\Backup\Service\MiscService;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\NotPermittedException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Class Backup
|
||||
*
|
||||
* @package OCA\Backup\Command
|
||||
*/
|
||||
class Listing extends Base {
|
||||
|
||||
|
||||
/** @var BackupService */
|
||||
private $backupService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* Backup constructor.
|
||||
*
|
||||
* @param BackupService $backupService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(BackupService $backupService, MiscService $miscService) {
|
||||
$this->backupService = $backupService;
|
||||
$this->miscService = $miscService;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function configure() {
|
||||
$this->setName('backup:list')
|
||||
->setDescription('get list of available backups');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*
|
||||
* @throws NotPermittedException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$backups = $this->backupService->listing();
|
||||
|
||||
foreach ($backups as $backup) {
|
||||
echo ' ' . date("Y-m-d H:i:s", $backup->getCreation()) . ' - ' . $backup->getId()
|
||||
. "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Command;
|
||||
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Backup\Exceptions\BackupNotFoundException;
|
||||
use OCA\Backup\Exceptions\EncryptionKeyException;
|
||||
use OCA\Backup\Service\BackupService;
|
||||
use OCA\Backup\Service\MiscService;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\NotPermittedException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Class Backup
|
||||
*
|
||||
* @package OCA\Backup\Command
|
||||
*/
|
||||
class Restore extends Base {
|
||||
|
||||
|
||||
/** @var BackupService */
|
||||
private $backupService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* Backup constructor.
|
||||
*
|
||||
* @param BackupService $backupService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(BackupService $backupService, MiscService $miscService) {
|
||||
$this->backupService = $backupService;
|
||||
$this->miscService = $miscService;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function configure() {
|
||||
$this->setName('backup:restore')
|
||||
->addArgument('token', InputArgument::REQUIRED, 'token of the backup to restore')
|
||||
->addOption('key', 'k', InputOption::VALUE_REQUIRED, 'specify encryption key')
|
||||
->addOption(
|
||||
'files', 'f', InputOption::VALUE_REQUIRED, 'restore only a specific bunch of files'
|
||||
)
|
||||
->setDescription('Restore a backup of the instance');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*
|
||||
* @throws NotPermittedException
|
||||
* @throws NotFoundException
|
||||
* @throws BackupNotFoundException
|
||||
* @throws EncryptionKeyException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$token = $input->getArgument('token');
|
||||
$key = ($input->getOption('key') === null) ? '' : $input->getOption('key');
|
||||
$files = ($input->getOption('files') === null) ? '' : $input->getOption('files');
|
||||
|
||||
$output->writeln('not available (yet) from the occ.');
|
||||
// $backup = $this->backupService->restore($token, $pass, $files);
|
||||
|
||||
// echo '> ' . json_encode($backup, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Frank Karlitschek <frank@karlitschek.de>
|
||||
*
|
||||
* @author Frank Karlitschek <frank@karlitschek.de>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Backup\Command;
|
||||
|
||||
use OCA\Backup\Backup\Restore;
|
||||
use OCA\Backup\AppInfo\Application;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class RestoreCommand extends Command {
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('backup:restore')
|
||||
->setDescription('Restore a backup of the instance')
|
||||
->addArgument(
|
||||
'path',
|
||||
InputArgument::REQUIRED,
|
||||
'The path where the backup should be restored from'
|
||||
)
|
||||
->addOption(
|
||||
'password',
|
||||
'pass',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Optionally password for an encrypted backup',
|
||||
''
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
|
||||
$path = $input->getArgument('path');
|
||||
|
||||
if ($path == '') {
|
||||
$output->writeln('Backup path not defined');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$password = $input->getOption('password');
|
||||
if ($password == '') {
|
||||
$output->writeln('Password not specified');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$backup = new \OCA\Backup\Backup\Restore($path);
|
||||
$backup -> password($password);
|
||||
$backup -> restore();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -23,8 +23,6 @@
|
|||
|
||||
namespace OCA\Backup\Controller;
|
||||
|
||||
use OCA\Backup\AppInfo\Application;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCSController;
|
||||
use OCP\IRequest;
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Db;
|
||||
|
||||
|
||||
use OCA\Backup\Model\Backup;
|
||||
|
||||
|
||||
/**
|
||||
* Class BackupsRequest
|
||||
*
|
||||
* @package OCA\Backup\Db
|
||||
*/
|
||||
class BackupsRequest extends BackupsRequestBuilder {
|
||||
|
||||
|
||||
/**
|
||||
* create a new Person in the database.
|
||||
*
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function create(Backup $backup): int {
|
||||
|
||||
$qb = $this->getBackupsInsertSql();
|
||||
|
||||
// $qb->setValue('id', $qb->createNamedParameter($id))
|
||||
//// ->setValue('type', $qb->createNamedParameter($actor->getType()))
|
||||
// ->setValue('user_id', $qb->createNamedParameter($actor->getUserId()))
|
||||
// ->setValue('name', $qb->createNamedParameter($actor->getName()))
|
||||
// ->setValue('summary', $qb->createNamedParameter($actor->getSummary()))
|
||||
// ->setValue(
|
||||
// 'creation',
|
||||
// $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE)
|
||||
// );
|
||||
|
||||
return $qb->execute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*/
|
||||
public function update(Backup $backup) {
|
||||
$qb = $this->getBackupsUpdateSql();
|
||||
$this->limitToId($qb, $backup->getId());
|
||||
|
||||
$qb->execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Db;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use OCA\Backup\Model\Backup;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
|
||||
/**
|
||||
* Class BackupRequestBuilder
|
||||
*
|
||||
* @package OCA\Backup\Db
|
||||
*/
|
||||
class BackupsRequestBuilder extends CoreRequestBuilder {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
|
||||
|
||||
/**
|
||||
* Base of the Sql Insert request
|
||||
*
|
||||
* @return IQueryBuilder
|
||||
*/
|
||||
protected function getBackupsInsertSql(): IQueryBuilder {
|
||||
$qb = $this->dbConnection->getQueryBuilder();
|
||||
$qb->insert(self::SQL_TABLES['BACKUPS']);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base of the Sql Update request
|
||||
*
|
||||
* @return IQueryBuilder
|
||||
*/
|
||||
protected function getBackupsUpdateSql(): IQueryBuilder {
|
||||
$qb = $this->dbConnection->getQueryBuilder();
|
||||
$qb->update(self::SQL_TABLES['BACKUPS']);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base of the Sql Select request for Shares
|
||||
*
|
||||
* @return IQueryBuilder
|
||||
*/
|
||||
protected function getBackupsSelectSql(): IQueryBuilder {
|
||||
$qb = $this->dbConnection->getQueryBuilder();
|
||||
|
||||
/** @noinspection PhpMethodParametersCountMismatchInspection */
|
||||
$qb->select(
|
||||
'sa.id', 'sa.user_id', 'sa.preferred_username', 'sa.name', 'sa.summary',
|
||||
'sa.public_key', 'sa.avatar_version', 'sa.private_key', 'sa.creation'
|
||||
)
|
||||
->from(self::SQL_TABLES['BACKUPS'], 'sa');
|
||||
|
||||
$this->defaultSelectAlias = 'sa';
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base of the Sql Delete request
|
||||
*
|
||||
* @return IQueryBuilder
|
||||
*/
|
||||
protected function getBackupsDeleteSql(): IQueryBuilder {
|
||||
$qb = $this->dbConnection->getQueryBuilder();
|
||||
$qb->delete(self::SQL_TABLES['BACKUPS']);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
protected function parseBackupsSelectSql($data): Backup {
|
||||
$backup = new Backup();
|
||||
$backup->importFromDatabase($data);
|
||||
|
||||
return $backup;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Db;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Db\RequestBuilder;
|
||||
use OCA\Backup\Service\MiscService;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
|
||||
/**
|
||||
* Class CoreRequestBuilder
|
||||
*
|
||||
* @package OCA\Backup\Db
|
||||
*/
|
||||
class CoreRequestBuilder extends RequestBuilder {
|
||||
|
||||
|
||||
const SQL_TABLES = [
|
||||
'BACKUPS' => 'backups'
|
||||
];
|
||||
|
||||
|
||||
/** @var IDBConnection */
|
||||
protected $dbConnection;
|
||||
|
||||
/** @var MiscService */
|
||||
protected $miscService;
|
||||
|
||||
|
||||
/** @var string */
|
||||
protected $defaultSelectAlias;
|
||||
|
||||
|
||||
/**
|
||||
* CoreRequestBuilder constructor.
|
||||
*
|
||||
* @param IDBConnection $connection
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(IDBConnection $connection, MiscService $miscService) {
|
||||
$this->dbConnection = $connection;
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Limit the request to the Id
|
||||
*
|
||||
* @param IQueryBuilder $qb
|
||||
* @param int $id
|
||||
*/
|
||||
protected function limitToId(IQueryBuilder &$qb, int $id) {
|
||||
$this->limitToDBFieldInt($qb, 'id', $id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Limit the request to the status
|
||||
*
|
||||
* @param IQueryBuilder $qb
|
||||
* @param int $status
|
||||
*/
|
||||
protected function limitToStatus(IQueryBuilder &$qb, int $status) {
|
||||
$this->limitToDBFieldInt($qb, 'status', $status);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Limit the request to the instance
|
||||
*
|
||||
* @param IQueryBuilder $qb
|
||||
* @param bool $local
|
||||
*/
|
||||
protected function limitToLocal(IQueryBuilder &$qb, bool $local) {
|
||||
$this->limitToDBField($qb, 'local', ($local) ? '1' : '0');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class ArchiveCreateException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class ArchiveDeleteException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class ArchiveNotFoundException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class BackupAppCopyException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class BackupFolderException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class BackupNotFoundException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class BackupScriptNotFoundException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
|
||||
class ChunkNotFoundException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class EncryptionKeyException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Exceptions;
|
||||
|
||||
|
||||
class VersionException extends \Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup;
|
||||
|
||||
|
||||
interface ISqlDump {
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function export(array $data): string;
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param resource $read
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function import(array $data, $read): bool;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OC;
|
||||
|
||||
|
||||
use OCP\IConfig;
|
||||
|
||||
|
||||
class Config implements IConfig {
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OC;
|
||||
|
||||
|
||||
use OCP\ILogger;
|
||||
|
||||
|
||||
class Logger implements ILogger {
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCP;
|
||||
|
||||
|
||||
interface IConfig {
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCP;
|
||||
|
||||
|
||||
interface ILogger {
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Model;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use JsonSerializable;
|
||||
|
||||
|
||||
/**
|
||||
* Class ArchiveFile
|
||||
*
|
||||
* @package OCA\Backup\Model
|
||||
*/
|
||||
class ArchiveFile implements JsonSerializable {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
|
||||
|
||||
/** @var string */
|
||||
private $name = '';
|
||||
|
||||
|
||||
/**
|
||||
* ArchiveFile constructor.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(string $name = '') {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return ArchiveFile
|
||||
*/
|
||||
public function setName(string $name): ArchiveFile {
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return ArchiveFile
|
||||
*/
|
||||
public function import(array $data): ArchiveFile {
|
||||
$this->setName($this->get('name', $data, ''));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize() {
|
||||
return
|
||||
[
|
||||
'name' => $this->getName()
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,460 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Model;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use daita\MySmallPhpTools\Traits\TPathTools;
|
||||
use daita\MySmallPhpTools\Traits\TStringTools;
|
||||
use JsonSerializable;
|
||||
use OCA\Backup\Exceptions\VersionException;
|
||||
use OCP\Files\SimpleFS\ISimpleFolder;
|
||||
|
||||
|
||||
/**
|
||||
* Class Backup
|
||||
*
|
||||
* @package OCA\Backup\Model
|
||||
*/
|
||||
class Backup implements JsonSerializable {
|
||||
|
||||
|
||||
const STATUS_OK = 1;
|
||||
const STATUS_UPLOAD_OK = 2;
|
||||
const STATUS_UPLOAD_EVERYWHERE = 4;
|
||||
|
||||
const STATUS_FAILED = 64;
|
||||
|
||||
const FILE_CONFIG = 1;
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
use TStringTools;
|
||||
use TPathTools;
|
||||
|
||||
|
||||
/** @var string */
|
||||
private $id = '';
|
||||
|
||||
/** @var string */
|
||||
private $name = '';
|
||||
|
||||
/** @var int */
|
||||
private $status = 0;
|
||||
|
||||
/** @var int[] */
|
||||
private $version = [];
|
||||
|
||||
/** @var string[] */
|
||||
private $apps = [];
|
||||
|
||||
/** @var BackupChunk[] */
|
||||
private $chunks = [];
|
||||
|
||||
/** @var ISimpleFolder */
|
||||
private $baseFolder = null;
|
||||
|
||||
/** @var Error[] */
|
||||
private $errors = [];
|
||||
|
||||
/** @var RemoteStorage[] */
|
||||
private $storages = [];
|
||||
|
||||
/** @var int */
|
||||
private $creation = 0;
|
||||
|
||||
/** @var bool */
|
||||
private $local = false;
|
||||
|
||||
/** @var string */
|
||||
private $encryptionKey = '';
|
||||
|
||||
/** @var BackupOptions */
|
||||
private $options = null;
|
||||
|
||||
|
||||
/**
|
||||
* Backup constructor.
|
||||
*
|
||||
* @param bool $init
|
||||
*/
|
||||
public function __construct(bool $init = false) {
|
||||
$this->options = new BackupOptions();
|
||||
|
||||
if ($init) {
|
||||
$this->creation = time();
|
||||
$this->id = $this->uuid();
|
||||
$this->name = date("Y-m-d-His", $this->creation) . '-' . $this->getId();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setId(string $id): Backup {
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setName(string $name): Backup {
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getStatus(): int {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $status
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setStatus(int $status): Backup {
|
||||
$this->status = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Error[]
|
||||
*/
|
||||
public function getErrors(): array {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Error[] $errors
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setErrors(array $errors): Backup {
|
||||
$this->errors = $errors;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return RemoteStorage[]
|
||||
*/
|
||||
public function getStorages(): array {
|
||||
return $this->storages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RemoteStorage[] $storages
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setStorages(array $storages): Backup {
|
||||
$this->storages = $storages;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function getVersion(): array {
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $version
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setVersion(array $version): Backup {
|
||||
$this->version = $version;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $current
|
||||
*
|
||||
* @throws VersionException
|
||||
*/
|
||||
public function compareVersion(array $current): void {
|
||||
// TODO compare version !
|
||||
throw new VersionException(
|
||||
'Your nextcloud must be upgraded to at least v' . implode('.', $this->getVersion())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getApps(): array {
|
||||
return $this->apps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $apps
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setApps(array $apps): Backup {
|
||||
$this->apps = $apps;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $appId
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function addApp(string $appId): Backup {
|
||||
$this->apps[] = $appId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool $filtered
|
||||
*
|
||||
* @return BackupChunk[]
|
||||
*/
|
||||
public function getChunks($filtered = false): array {
|
||||
$options = $this->getOptions();
|
||||
if (!$filtered || $options->getChunk() === '') {
|
||||
return $this->chunks;
|
||||
}
|
||||
|
||||
$options = $this->getOptions();
|
||||
foreach ($this->chunks as $chunk) {
|
||||
if ($chunk->getName() === $options->getChunk()) {
|
||||
return [$chunk];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $chunks
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setChunks(array $chunks): Backup {
|
||||
$this->chunks = $chunks;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BackupChunk $chunk
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function addChunk(BackupChunk $chunk): Backup {
|
||||
$this->chunks[] = $chunk;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasBaseFolder(): bool {
|
||||
return ($this->baseFolder !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ISimpleFolder $folder
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setBaseFolder(ISimpleFolder $folder): Backup {
|
||||
$this->baseFolder = $folder;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ISimpleFolder
|
||||
*/
|
||||
public function getBaseFolder(): ISimpleFolder {
|
||||
return $this->baseFolder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCreation(): int {
|
||||
return $this->creation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $creation
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setCreation(int $creation): Backup {
|
||||
$this->creation = $creation;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isLocal(): bool {
|
||||
return $this->local;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $local
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setLocal(bool $local): Backup {
|
||||
$this->local = $local;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function getOptions(): BackupOptions {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BackupOptions $options
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setOptions(BackupOptions $options): Backup {
|
||||
$this->options = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncryptionKey(): string {
|
||||
return $this->encryptionKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encryptionKey
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function setEncryptionKey(string $encryptionKey): Backup {
|
||||
$this->encryptionKey = $encryptionKey;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Backup
|
||||
*/
|
||||
public function import(array $data): Backup {
|
||||
$this->setId($this->get('id', $data, ''));
|
||||
$this->setStatus($this->getInt('status', $data));
|
||||
$this->setName($this->get('name', $data, ''));
|
||||
$this->setVersion($this->getArray('version', $data, []));
|
||||
$this->setApps($this->getArray('apps', $data, []));
|
||||
$this->setCreation($this->getInt('creation', $data, 0));
|
||||
$this->setChunks($this->getList('chunks', $data, [BackupChunk::class, 'import'], []));
|
||||
$this->setErrors($this->getList('errors', $data, [Error::class, 'import'], []));
|
||||
$this->setStorages($this->getList('remotes', $data, [RemoteStorage::class, 'import'], []));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize() {
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'status' => $this->getStatus(),
|
||||
'name' => $this->getName(),
|
||||
'version' => $this->getVersion(),
|
||||
'apps' => $this->getApps(),
|
||||
'creation' => $this->getCreation(),
|
||||
'chunks' => $this->getChunks(),
|
||||
'errors' => $this->getErrors(),
|
||||
'storages' => $this->getStorages()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Model;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use daita\MySmallPhpTools\Traits\TStringTools;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class BackupArchive
|
||||
*
|
||||
* @package OCA\Backup\Model
|
||||
*/
|
||||
class BackupArchive implements JsonSerializable {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
use TStringTools;
|
||||
|
||||
|
||||
/** @var string */
|
||||
private $name = '';
|
||||
|
||||
/** @var string[] */
|
||||
private $files = [];
|
||||
|
||||
/** @var int */
|
||||
private $count = 0;
|
||||
|
||||
/** @var int */
|
||||
private $size = 0;
|
||||
|
||||
/** @var string */
|
||||
private $checksum = '';
|
||||
|
||||
/** @var string */
|
||||
private $encryptedChecksum = '';
|
||||
|
||||
|
||||
/**
|
||||
* BackupArchive constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->name = $this->uuid();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $ext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(string $ext = ''): string {
|
||||
if ($ext === '') {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
return $this->name . '.' . $ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return BackupArchive
|
||||
*/
|
||||
public function setName(string $name): BackupArchive {
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * @return int
|
||||
// */
|
||||
// public function count(): int {
|
||||
// return sizeof($this->files);
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCount(): int {
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
*
|
||||
* @return BackupArchive
|
||||
*/
|
||||
public function setCount(int $count = -1): BackupArchive {
|
||||
if ($count === -1) {
|
||||
$this->count = sizeof($this->files);
|
||||
} else {
|
||||
$this->count = $count;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return ArchiveFile[]
|
||||
*/
|
||||
public function getFiles(): array {
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArchiveFile[] $files
|
||||
*
|
||||
* @return BackupArchive
|
||||
*/
|
||||
public function setFiles(array $files): BackupArchive {
|
||||
$this->files = $files;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArchiveFile $file
|
||||
*
|
||||
* @return BackupArchive
|
||||
*/
|
||||
public function addFile(ArchiveFile $file): BackupArchive {
|
||||
$this->files[] = $file;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSize(): int {
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $size
|
||||
*
|
||||
* @return BackupArchive
|
||||
*/
|
||||
public function setSize(int $size): BackupArchive {
|
||||
$this->size = $size;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChecksum(): string {
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $checksum
|
||||
*
|
||||
* @return BackupArchive
|
||||
*/
|
||||
public function setChecksum(string $checksum): BackupArchive {
|
||||
$this->checksum = $checksum;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncryptedChecksum(): string {
|
||||
return $this->encryptedChecksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encryptedChecksum
|
||||
*
|
||||
* @return BackupArchive
|
||||
*/
|
||||
public function setEncryptedChecksum(string $encryptedChecksum): BackupArchive {
|
||||
$this->encryptedChecksum = $encryptedChecksum;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return BackupArchive
|
||||
*/
|
||||
public function import(array $data): BackupArchive {
|
||||
$this->setName($this->get('name', $data, ''))
|
||||
// ->setFiles($this->getArray('files', $data, []))
|
||||
->setCount($this->getInt('count', $data, 0))
|
||||
->setSize($this->getInt('size', $data, 0))
|
||||
->setChecksum($this->get('checksum', $data, ''))
|
||||
->setEncryptedChecksum($this->get('encrypted', $data, ''));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getResume(): array {
|
||||
return [
|
||||
'files' => $this->getFileS()
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
return
|
||||
[
|
||||
'name' => $this->getName(),
|
||||
'count' => $this->getCount(),
|
||||
'size' => $this->getSize(),
|
||||
'checksum' => $this->getChecksum(),
|
||||
'encrypted' => $this->getEncryptedChecksum()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Model;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use daita\MySmallPhpTools\Traits\TStringTools;
|
||||
use JsonSerializable;
|
||||
|
||||
|
||||
/**
|
||||
* Class BackupChunk
|
||||
*
|
||||
* @package OCA\Backup\Model
|
||||
*/
|
||||
class BackupChunk implements JsonSerializable {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
use TStringTools;
|
||||
|
||||
|
||||
const ROOT_DISK = 1;
|
||||
const ROOT_NEXTCLOUD = 2;
|
||||
const ROOT_DATA = 3;
|
||||
const ROOT_APPS = 4;
|
||||
|
||||
const FILE_CONFIG = 101;
|
||||
|
||||
// value > 1000 is for content that are not 'file'
|
||||
const SQL_DUMP = 1001;
|
||||
|
||||
/** @var string */
|
||||
private $name = '';
|
||||
|
||||
/** @var int */
|
||||
private $type = 0;
|
||||
|
||||
/** @var string */
|
||||
private $path = '';
|
||||
|
||||
/** @var string */
|
||||
private $root = '';
|
||||
|
||||
/** @var string */
|
||||
private $uniqueFile = '';
|
||||
|
||||
/** @var BackupArchive[] */
|
||||
private $archives = [];
|
||||
|
||||
/** @var string[] */
|
||||
private $files = [];
|
||||
|
||||
|
||||
/**
|
||||
* BackupChunk constructor.
|
||||
*
|
||||
* @param string $name
|
||||
* @param int $type
|
||||
* @param string $path
|
||||
*/
|
||||
public function __construct(int $type = 0, string $path = '', string $name = '') {
|
||||
$this->type = $type;
|
||||
$this->path = $path;
|
||||
|
||||
$this->name = $name;
|
||||
if ($name === '') {
|
||||
$this->name = $this->uuid();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function setName(string $name): BackupChunk {
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getType(): int {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function setType(int $type): BackupChunk {
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath(): string {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function setPath(string $path): BackupChunk {
|
||||
$this->path = $path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRoot(): string {
|
||||
return $this->root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $root
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function setRoot(string $root): BackupChunk {
|
||||
$this->root = $root;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsolutePath(): string {
|
||||
return $this->getRoot() . $this->getPath();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function addFile(string $path): BackupChunk {
|
||||
$this->files[] = $path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFiles(): array {
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $files
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function setFiles(array $files): BackupChunk {
|
||||
$this->files = $files;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUniqueFile(): string {
|
||||
return $this->uniqueFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function setUniqueFile(string $file): BackupChunk {
|
||||
$this->uniqueFile = $file;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return BackupArchive[]
|
||||
*/
|
||||
public function getArchives(): array {
|
||||
return $this->archives;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BackupArchive[] $archives
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function setArchives(array $archives): BackupChunk {
|
||||
$this->archives = $archives;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BackupArchive $archive
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function addArchive(BackupArchive $archive): BackupChunk {
|
||||
$this->archives[] = $archive;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return BackupChunk
|
||||
*/
|
||||
public function import(array $data): BackupChunk {
|
||||
$this->setType($this->getInt('type', $data, 0));
|
||||
$this->setName($this->get('name', $data, ''));
|
||||
$this->setRoot($this->get('root', $data, ''));
|
||||
$this->setPath($this->get('path', $data, ''));
|
||||
$this->setArchives($this->getList('archives', $data, [BackupArchive::class, 'import'], []));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize() {
|
||||
return [
|
||||
'name' => $this->getName(),
|
||||
'type' => $this->getType(),
|
||||
'root' => $this->getRoot(),
|
||||
'path' => $this->getPath(),
|
||||
'archives' => $this->getArchives()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Model;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use daita\MySmallPhpTools\Traits\TPathTools;
|
||||
use JsonSerializable;
|
||||
|
||||
|
||||
/**
|
||||
* Class BackupOptions
|
||||
*
|
||||
* @package OCA\Backup\Model
|
||||
*/
|
||||
class BackupOptions implements JsonSerializable {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
use TPathTools;
|
||||
|
||||
|
||||
/** @var string */
|
||||
private $newRoot = '';
|
||||
|
||||
/** @var string */
|
||||
private $path = '';
|
||||
|
||||
/** @var string */
|
||||
private $search = '';
|
||||
|
||||
/** @var array */
|
||||
private $config = [];
|
||||
|
||||
/** @var string */
|
||||
private $chunk = '';
|
||||
|
||||
/** @var string */
|
||||
private $archive = '';
|
||||
|
||||
/** @var bool */
|
||||
private $all = false;
|
||||
|
||||
/** @var bool */
|
||||
private $fixDataDir = false;
|
||||
|
||||
|
||||
/**
|
||||
* BackupOptions constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNewRoot(): string {
|
||||
return $this->newRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $root
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function setNewRoot(string $root): BackupOptions {
|
||||
if ($root !== '') {
|
||||
$root = $this->withEndSlash($root);
|
||||
}
|
||||
|
||||
$this->newRoot = $root;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath(): string {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function setPath(string $path): BackupOptions {
|
||||
$this->path = $path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSearch(): string {
|
||||
return $this->search;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $search
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function setSearch(string $search): BackupOptions {
|
||||
$this->search = $search;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig(): array {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function setConfig(array $config): BackupOptions {
|
||||
$this->config = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $json
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function setConfigRaw(string $json): BackupOptions {
|
||||
$config = json_decode($json, true);
|
||||
if (is_array($config)) {
|
||||
$this->setConfig($config);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChunk(): string {
|
||||
return $this->chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $chunk
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function setChunk(string $chunk): BackupOptions {
|
||||
$this->chunk = $chunk;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getArchive(): string {
|
||||
return $this->archive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $archive
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function setArchive(string $archive): BackupOptions {
|
||||
$this->archive = $archive;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isAll(): bool {
|
||||
return $this->all;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $all
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function setAll(bool $all): BackupOptions {
|
||||
$this->all = $all;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isFixDataDir(): bool {
|
||||
return $this->fixDataDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $fixDataDir
|
||||
*/
|
||||
public function setFixDataDir(bool $fixDataDir): void {
|
||||
$this->fixDataDir = $fixDataDir;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return BackupOptions
|
||||
*/
|
||||
public function import(array $data): BackupOptions {
|
||||
$this->setNewRoot($this->get('newRoot', $data, ''));
|
||||
$this->setPath($this->get('path', $data, ''));
|
||||
$this->setSearch($this->get('search', $data, ''));
|
||||
$this->setArchive($this->get('archive', $data, ''));
|
||||
$this->setChunk($this->get('chunk', $data, ''));
|
||||
$this->setAll($this->getBool('all', $data, false));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize() {
|
||||
return [
|
||||
'newRoot' => $this->getNewRoot(),
|
||||
'search' => $this->getSearch(),
|
||||
'path' => $this->getPath(),
|
||||
'archive' => $this->getArchive(),
|
||||
'chunk' => $this->getChunk(),
|
||||
'all' => $this->isAll()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Model;
|
||||
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
|
||||
/**
|
||||
* Class BackupError
|
||||
*
|
||||
* @package OCA\Backup\Model
|
||||
*/
|
||||
class Error implements JsonSerializable {
|
||||
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Error
|
||||
*/
|
||||
public function import(array $data): Error {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Model;
|
||||
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
|
||||
/**
|
||||
* Class BackupError
|
||||
*
|
||||
* @package OCA\Backup\Model
|
||||
*/
|
||||
class RemoteStorage implements JsonSerializable {
|
||||
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return RemoteStorage
|
||||
*/
|
||||
public function import(array $data): RemoteStorage {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,590 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Service;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use daita\MySmallPhpTools\Traits\TFileTools;
|
||||
use daita\MySmallPhpTools\Traits\TStringTools;
|
||||
use Exception;
|
||||
use OCA\Backup\Exceptions\ArchiveCreateException;
|
||||
use OCA\Backup\Exceptions\ArchiveDeleteException;
|
||||
use OCA\Backup\Exceptions\ArchiveNotFoundException;
|
||||
use OCA\Backup\Exceptions\BackupAppCopyException;
|
||||
use OCA\Backup\Exceptions\BackupFolderException;
|
||||
use OCA\Backup\Exceptions\BackupScriptNotFoundException;
|
||||
use OCA\Backup\Exceptions\EncryptionKeyException;
|
||||
use OCA\Backup\Model\ArchiveFile;
|
||||
use OCA\Backup\Model\Backup;
|
||||
use OCA\Backup\Model\BackupArchive;
|
||||
use OCA\Backup\Model\BackupChunk;
|
||||
use ZipArchive;
|
||||
use ZipStreamer\COMPR;
|
||||
use ZipStreamer\ZipStreamer;
|
||||
|
||||
|
||||
/**
|
||||
* Class ArchiveService
|
||||
*
|
||||
* @package OCA\Backup\Service
|
||||
*/
|
||||
class ArchiveService {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
use TStringTools;
|
||||
use TFileTools;
|
||||
|
||||
|
||||
const MAX_ZIP_SIZE = 100000000;
|
||||
|
||||
|
||||
/** @var FilesService */
|
||||
private $filesService;
|
||||
|
||||
/** @var EncryptService */
|
||||
private $encryptService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* ArchiveService constructor.
|
||||
*
|
||||
* @param FilesService $filesService
|
||||
* @param EncryptService $encryptService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(
|
||||
FilesService $filesService, EncryptService $encryptService, MiscService $miscService
|
||||
) {
|
||||
$this->filesService = $filesService;
|
||||
$this->encryptService = $encryptService;
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @return bool
|
||||
* @throws ArchiveCreateException
|
||||
* @throws ArchiveDeleteException
|
||||
* @throws ArchiveNotFoundException
|
||||
*/
|
||||
public function getArchives(Backup $backup): bool {
|
||||
foreach ($backup->getChunks(false) as $chunk) {
|
||||
$this->filesService->initBackupChunk($chunk);
|
||||
$this->filesService->fillBackupChunk($chunk, $chunk->getUniqueFile());
|
||||
|
||||
$this->generateArchives($backup, $chunk);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
* @param string $root
|
||||
*
|
||||
* @throws ArchiveDeleteException
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws EncryptionKeyException
|
||||
* @throws BackupFolderException
|
||||
*/
|
||||
public function extractAll(Backup $backup, BAckupArchive $archive, string $root): void {
|
||||
if (!is_dir($root)) {
|
||||
if (!@mkdir($root, 0755, true)) {
|
||||
throw new BackupFolderException('could not create ' . $root);
|
||||
}
|
||||
}
|
||||
|
||||
$this->decryptArchive($backup, $archive);
|
||||
$this->extractAllFromArchive($archive, $root);
|
||||
$this->deleteArchive($backup, $archive, 'zip');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param BackupArchive $archive
|
||||
* @param string $root
|
||||
*
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function extractAllFromArchive(BackupArchive $archive, string $root): void {
|
||||
$zip = $this->openZipArchive($archive);
|
||||
$zip->extractTo($root);
|
||||
$this->closeZipArchive($zip);
|
||||
|
||||
unlink($root . '.backup.' . $archive->getName() . '.json');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param BackupArchive $archive
|
||||
*
|
||||
* @return ZipArchive
|
||||
* @throws ArchiveNotFoundException
|
||||
*/
|
||||
public function openZipArchive(BackupArchive $archive): ZipArchive {
|
||||
$zip = new ZipArchive();
|
||||
if (($err = $zip->open($archive->getName('zip'))) !== true) {
|
||||
throw new ArchiveNotFoundException('Could not open Zip Archive (' . $err . ')');
|
||||
}
|
||||
|
||||
return $zip;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ZipArchive $zip
|
||||
*/
|
||||
public function closeZipArchive(ZipArchive $zip): void {
|
||||
$zip->close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param BackupArchive $archive
|
||||
* @param ZipArchive $zip
|
||||
*/
|
||||
public function listFilesFromZip(BackupArchive $archive, ZipArchive $zip): void {
|
||||
$json = $zip->getFromName('.backup.' . $archive->getName() . '.json');
|
||||
$data = json_decode($json, true);
|
||||
$files = $this->getList('files', $data, [ArchiveFile::class, 'import'], []);
|
||||
|
||||
$archive->setFiles($files);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ZipArchive $zip
|
||||
* @param string $root
|
||||
* @param ArchiveFile[] $archiveFiles
|
||||
*/
|
||||
public function extractFilesFromZip(ZipArchive $zip, string $root, array $archiveFiles): void {
|
||||
$files = array_map(
|
||||
function(ArchiveFile $entry) {
|
||||
return $entry->getName();
|
||||
}, $archiveFiles
|
||||
);
|
||||
|
||||
$zip->extractTo($root, $files);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ZipArchive $zip
|
||||
* @param string $file
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
public function extractContentFromZip(ZipArchive $zip, string $file) {
|
||||
return $zip->getStream($file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
* @param bool $encrypted
|
||||
*
|
||||
* @return bool
|
||||
* @throws ArchiveNotFoundException
|
||||
*/
|
||||
public function verifyChecksum(Backup $backup, BackupArchive $archive, bool $encrypted): bool {
|
||||
$sum = $this->getChecksum($backup, $archive, $encrypted);
|
||||
|
||||
if (!$encrypted && $sum === $archive->getChecksum()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($encrypted && $sum === $archive->getEncryptedChecksum()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $backupChunk
|
||||
*
|
||||
* @throws ArchiveCreateException
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws ArchiveDeleteException
|
||||
*/
|
||||
private function generateArchives(Backup $backup, BackupChunk $backupChunk) {
|
||||
$files = $backupChunk->getFiles();
|
||||
while (!empty($files)) {
|
||||
$archive = $this->createArchiveWithFiles($backup, $backupChunk, $files);
|
||||
$this->updateChecksum($backup, $archive, false);
|
||||
$this->encryptArchive($backup, $archive, true);
|
||||
$this->updateChecksum($backup, $archive, true);
|
||||
|
||||
$backupChunk->addArchive($archive);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $chunk
|
||||
* @param string $filename
|
||||
* @param string $content
|
||||
*
|
||||
* @return void
|
||||
* @throws ArchiveCreateException
|
||||
* @throws ArchiveDeleteException
|
||||
* @throws ArchiveNotFoundException
|
||||
*/
|
||||
public function createContentArchive(
|
||||
Backup $backup, BackupChunk $chunk, string $filename, string $content
|
||||
): void {
|
||||
$archive = new BackupArchive();
|
||||
$archive->setCount(1);
|
||||
$archive->addFile(new ArchiveFile($filename));
|
||||
$archive->setSize(strlen($content));
|
||||
$chunk->addArchive($archive);
|
||||
|
||||
$zip = $this->generateZip($backup, $archive->getName('zip'));
|
||||
$read = fopen('data://text/plain,' . $content, 'r');
|
||||
$zip->addFileFromStream($read, $filename);
|
||||
$zip->finalize();
|
||||
|
||||
$this->updateChecksum($backup, $archive, false);
|
||||
$this->encryptArchive($backup, $archive, true);
|
||||
$this->updateChecksum($backup, $archive, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $backupChunk
|
||||
* @param array $files
|
||||
*
|
||||
* @return BackupArchive
|
||||
* @throws ArchiveCreateException
|
||||
*/
|
||||
private function createArchiveWithFiles(Backup $backup, BackupChunk $backupChunk, array &$files
|
||||
): BackupArchive {
|
||||
|
||||
$archive = new BackupArchive();
|
||||
|
||||
$zip = $this->generateZip($backup, $archive->getName('zip'));
|
||||
|
||||
$zipSize = 0;
|
||||
while (($filename = array_shift($files)) !== null) {
|
||||
$fileSize = filesize($backupChunk->getAbsolutePath() . $filename);
|
||||
if ($zipSize > 0 && ($zipSize + $fileSize) > self::MAX_ZIP_SIZE) {
|
||||
$this->finalizeZip($zip, $archive->setSize($zipSize));
|
||||
|
||||
return $archive;
|
||||
}
|
||||
|
||||
$zipSize += $fileSize;
|
||||
$in = fopen($backupChunk->getAbsolutePath() . $filename, 'r');
|
||||
|
||||
$zip->addFileFromStream($in, $filename);
|
||||
$archiveFile = new ArchiveFile($filename);
|
||||
$archive->addFile($archiveFile);
|
||||
$archive->setCount();
|
||||
}
|
||||
|
||||
$this->finalizeZip($zip, $archive->setSize($zipSize));
|
||||
|
||||
return $archive;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param string $filename
|
||||
*
|
||||
* @return ZipStreamer
|
||||
* @throws ArchiveCreateException
|
||||
*/
|
||||
public function generateZip(Backup $backup, string $filename) {
|
||||
|
||||
if (!$backup->hasBaseFolder()) {
|
||||
throw new ArchiveCreateException('Backup has no Base Folder');
|
||||
}
|
||||
|
||||
$folder = $backup->getBaseFolder();
|
||||
try {
|
||||
$file = $folder->newFile($filename);
|
||||
$zip = new ZipStreamer(
|
||||
[
|
||||
'outstream' => $file->write(),
|
||||
'zip64' => false,
|
||||
'compress' => COMPR::DEFLATE,
|
||||
'level' => $this->assignCompressionLevel()
|
||||
]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveCreateException(
|
||||
'could not create Zip archive (' . $e->getMessage() . ')'
|
||||
);
|
||||
}
|
||||
|
||||
return $zip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZipStreamer $zip
|
||||
* @param BackupArchive $archive
|
||||
*/
|
||||
public function finalizeZip(ZipStreamer $zip, BackupArchive $archive): void {
|
||||
$str = json_encode($archive->getResume(), JSON_PRETTY_PRINT);
|
||||
$read = fopen('data://text/plain,' . $str, 'r');
|
||||
$zip->addFileFromStream($read, '.backup.' . $archive->getName() . '.json');
|
||||
|
||||
$zip->finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
* @param bool $encrypted
|
||||
*
|
||||
* @throws ArchiveNotFoundException
|
||||
*/
|
||||
private function updateChecksum(Backup $backup, BackupArchive $archive, bool $encrypted): void {
|
||||
$sum = $this->getChecksum($backup, $archive, $encrypted);
|
||||
if ($encrypted) {
|
||||
$archive->setEncryptedChecksum($sum);
|
||||
} else {
|
||||
$archive->setChecksum($sum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
* @param bool $encrypted
|
||||
*
|
||||
* @return string
|
||||
* @throws ArchiveNotFoundException
|
||||
*/
|
||||
private function getChecksum(Backup $backup, BackupArchive $archive, bool $encrypted): string {
|
||||
try {
|
||||
if ($backup->isLocal()) {
|
||||
if (!file_exists('./' . $archive->getName(($encrypted) ? '' : 'zip'))) {
|
||||
throw new ArchiveNotFoundException('Archive not found');
|
||||
}
|
||||
$stream = fopen('./' . $archive->getName(($encrypted) ? '' : 'zip'), 'r');
|
||||
} else {
|
||||
$folder = $backup->getBaseFolder();
|
||||
$file = $folder->getFile($archive->getName(($encrypted) ? '' : 'zip'));
|
||||
$stream = $file->read();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveNotFoundException('Archive not found');
|
||||
}
|
||||
|
||||
if (is_bool($stream)) {
|
||||
throw new ArchiveNotFoundException('Archive not found');
|
||||
}
|
||||
|
||||
return $this->getChecksumFromStream($stream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
* @param string $ext
|
||||
*
|
||||
* @throws ArchiveDeleteException
|
||||
*/
|
||||
public function deleteArchive(Backup $backup, BackupArchive $archive, $ext = '') {
|
||||
if ($backup->isLocal()) {
|
||||
unlink('./' . $archive->getName($ext));
|
||||
} else {
|
||||
$folder = $backup->getBaseFolder();
|
||||
try {
|
||||
$file = $folder->getFile($archive->getName($ext));
|
||||
$file->delete();
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveDeleteException('Could not delete Archive');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
* @param bool $delete
|
||||
*
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws ArchiveDeleteException
|
||||
*/
|
||||
public function encryptArchive(Backup $backup, BackupArchive $archive, bool $delete): void {
|
||||
$folder = $backup->getBaseFolder();
|
||||
try {
|
||||
$file = $folder->getFile($archive->getName('zip'));
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveNotFoundException('Could not read Archive to encrypt');
|
||||
}
|
||||
|
||||
try {
|
||||
$encrypted = $folder->newFile($archive->getName());
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveNotFoundException('Could not write to encrypted Archive');
|
||||
}
|
||||
|
||||
$key = substr(sha1($backup->getEncryptionKey(), true), 0, 16);
|
||||
try {
|
||||
$this->encryptService->encryptFile($file->read(), $encrypted->write(), $key);
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveNotFoundException('Could not encrypt Archive');
|
||||
}
|
||||
|
||||
if ($delete) {
|
||||
try {
|
||||
$file->delete();
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveDeleteException('Could not delete non-encrypted Archive !');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
*
|
||||
* @throws EncryptionKeyException
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws ArchiveNotFoundException
|
||||
*/
|
||||
public function decryptArchive(Backup $backup, BackupArchive $archive) {
|
||||
if ($backup->isLocal()) {
|
||||
if (!file_exists('./' . $archive->getName())) {
|
||||
throw new ArchiveNotFoundException('Archive not found');
|
||||
}
|
||||
$stream = fopen('./' . $archive->getName(''), 'r');
|
||||
$write = fopen('./' . $archive->getName('zip'), 'w');
|
||||
} else {
|
||||
$folder = $backup->getBaseFolder();
|
||||
|
||||
try {
|
||||
$encrypted = $folder->getFile($archive->getName());
|
||||
$stream = $encrypted->read();
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveNotFoundException('Archive not found');
|
||||
}
|
||||
|
||||
try {
|
||||
$file = $folder->newFile($archive->getName('zip'));
|
||||
$write = $file->write();
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveNotFoundException('Zip file not created');
|
||||
}
|
||||
}
|
||||
|
||||
$key = substr(sha1($backup->getEncryptionKey(), true), 0, 16);
|
||||
$this->encryptService->decryptFile($stream, $write, $key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @throws BackupScriptNotFoundException
|
||||
* @throws BackupAppCopyException
|
||||
*/
|
||||
public function copyApp(Backup $backup): void {
|
||||
$folder = $backup->getBaseFolder();
|
||||
try {
|
||||
$file = $folder->newFile('app.zip');
|
||||
$zip = new ZipStreamer(
|
||||
[
|
||||
'outstream' => $file->write(),
|
||||
'zip64' => false,
|
||||
'compress' => COMPR::DEFLATE,
|
||||
'level' => $this->assignCompressionLevel()
|
||||
]
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
throw new BackupAppCopyException('Could not generate app.zip');
|
||||
}
|
||||
|
||||
$appFiles = $this->filesService->getFilesFromApp();
|
||||
foreach ($appFiles as $file) {
|
||||
if ($file === 'backup.php') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$in = fopen(FilesService::APP_ROOT . $file, 'rb');
|
||||
$zip->addFileFromStream($in, './app/' . $file);
|
||||
}
|
||||
|
||||
$zip->finalize();
|
||||
|
||||
$script = file_get_contents(FilesService::APP_ROOT . 'backup.php');
|
||||
try {
|
||||
$scriptFile = $folder->newFile('backup.php');
|
||||
$scriptFile->putContent($script);
|
||||
} catch (Exception $e) {
|
||||
throw new BackupScriptNotFoundException('Could not create backup.php');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
private function assignCompressionLevel(): int {
|
||||
try {
|
||||
$extension = new \ReflectionExtension('http');
|
||||
} catch (\ReflectionException $e) {
|
||||
return COMPR::NONE;
|
||||
}
|
||||
|
||||
if (version_compare($extension->getVersion(), '0.10.0', '>=')) {
|
||||
return COMPR::MAXIMUM;
|
||||
}
|
||||
|
||||
return COMPR::NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,479 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Service;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use daita\MySmallPhpTools\Traits\TFileTools;
|
||||
use daita\MySmallPhpTools\Traits\TStringTools;
|
||||
use Exception;
|
||||
use OC;
|
||||
use OCA\Backup\AppInfo\Application;
|
||||
use OCA\Backup\Exceptions\ArchiveCreateException as ArchiveCreateExceptionAlias;
|
||||
use OCA\Backup\Exceptions\ArchiveDeleteException;
|
||||
use OCA\Backup\Exceptions\ArchiveNotFoundException;
|
||||
use OCA\Backup\Exceptions\BackupAppCopyException;
|
||||
use OCA\Backup\Exceptions\BackupFolderException;
|
||||
use OCA\Backup\Exceptions\BackupNotFoundException;
|
||||
use OCA\Backup\Exceptions\BackupScriptNotFoundException as BackupScriptNotFoundExceptionAlias;
|
||||
use OCA\Backup\Exceptions\ChunkNotFoundException;
|
||||
use OCA\Backup\Model\Backup;
|
||||
use OCA\Backup\Model\BackupChunk;
|
||||
use OCA\Backup\SqlDump\SqlDumpMySQL;
|
||||
use OCP\Files\IAppData;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\NotPermittedException;
|
||||
use OCP\Util;
|
||||
|
||||
|
||||
/**
|
||||
* Class BackupService
|
||||
*
|
||||
* @package OCA\Backup\Service
|
||||
*/
|
||||
class BackupService {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
use TStringTools;
|
||||
use TFileTools;
|
||||
|
||||
|
||||
const NOBACKUP_FILE = '.nobackup';
|
||||
const SUMMARY_FILE = 'backup.json';
|
||||
const SQL_DUMP_FILE = 'backup_sql';
|
||||
|
||||
/** @var IAppData */
|
||||
private $appData;
|
||||
|
||||
/** @var ArchiveService */
|
||||
private $archiveService;
|
||||
|
||||
/** @var FilesService */
|
||||
private $filesService;
|
||||
|
||||
/** @var ConfigService */
|
||||
private $configService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* BackupService constructor.
|
||||
*
|
||||
* @param ArchiveService $archiveService
|
||||
* @param FilesService $filesService
|
||||
* @param ConfigService $configService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(
|
||||
ArchiveService $archiveService, FilesService $filesService, ConfigService $configService,
|
||||
MiscService $miscService
|
||||
) {
|
||||
if (class_exists(OC::class)) {
|
||||
$this->appData = OC::$server->getAppDataDir(Application::APP_ID);
|
||||
}
|
||||
|
||||
$this->archiveService = $archiveService;
|
||||
$this->filesService = $filesService;
|
||||
$this->configService = $configService;
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Backup
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws NotPermittedException
|
||||
* @throws ArchiveCreateExceptionAlias
|
||||
* @throws ArchiveDeleteException
|
||||
* @throws BackupAppCopyException
|
||||
* @throws BackupScriptNotFoundExceptionAlias
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function backup(): Backup {
|
||||
$backup = $this->initBackup();
|
||||
$this->archiveService->copyApp($backup);
|
||||
|
||||
$backup->setEncryptionKey('12345');
|
||||
$this->archiveService->getArchives($backup);
|
||||
$this->backupSql($backup);
|
||||
$this->endBackup($backup);
|
||||
|
||||
return $backup;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Backup[]
|
||||
* @throws NotPermittedException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function listing(): array {
|
||||
$this->initBackupFS();
|
||||
|
||||
$backups = [];
|
||||
$ls = $this->appData->getDirectoryListing();
|
||||
foreach ($ls as $entry) {
|
||||
if ($ls === 'remote') {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$backups[] = $this->parseFromFolder($entry->getName());
|
||||
} catch (BackupFolderException $e) {
|
||||
} catch (NotPermittedException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
return $backups;
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * @param string $token
|
||||
// * @param string $pass
|
||||
// * @param string $file
|
||||
// *
|
||||
// * @return Backup
|
||||
// * @throws BackupNotFoundException
|
||||
// * @throws NotFoundException
|
||||
// * @throws NotPermittedException
|
||||
// */
|
||||
// public function restore(string $token, string $pass, string $file = ''): Backup {
|
||||
// $backup = $this->getBackup($token);
|
||||
//
|
||||
// foreach ($backup->getFiles() as $files) {
|
||||
// if ($file === '' || $files->getName() === $file) {
|
||||
// $this->restoreBackupChunk($backup, $files, $pass);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return $backup;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $files
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getExtractRoot(Backup $backup, BackupChunk $files): string {
|
||||
$absoluteRootLength = strlen($this->getAbsoluteRoot($backup));
|
||||
$base = substr($files->getRoot(), $absoluteRootLength);
|
||||
|
||||
$options = $backup->getOptions();
|
||||
$root = ($options->getNewRoot() === '') ? $files->getRoot() : $options->getNewRoot();
|
||||
$root .= $base . $files->getPath();
|
||||
|
||||
return $root;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*/
|
||||
public function restoreBackup(Backup $backup): void {
|
||||
foreach ($backup->getChunks(true) as $backupChunk) {
|
||||
$this->restoreBackupChunk($backup, $backupChunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $files
|
||||
*/
|
||||
public function restoreBackupChunk(Backup $backup, BackupChunk $files): void {
|
||||
if ($files->getType() >= BackupChunk::SQL_DUMP) {
|
||||
$this->restoreNonFileChunk($backup, $files);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$root = $this->getExtractRoot($backup, $files);
|
||||
foreach ($files->getArchives() as $archive) {
|
||||
try {
|
||||
$this->archiveService->extractAll($backup, $archive, $root);
|
||||
} catch (Exception $e) {
|
||||
//echo $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $files
|
||||
*/
|
||||
private function restoreNonFileChunk(Backup $backup, BackupChunk $files): void {
|
||||
switch ($files->getType()) {
|
||||
case BackupChunk::SQL_DUMP:
|
||||
$this->restoreSqlDump($backup, $files);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $files
|
||||
*/
|
||||
private function restoreSqlDump(Backup $backup, BackupChunk $files): void {
|
||||
|
||||
// $sqlDump = new SqlDumpMySQL();
|
||||
// $content = $sqlDump->import();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @return Backup
|
||||
* @throws NotFoundException
|
||||
* @throws NotPermittedException
|
||||
* @throws BackupNotFoundException
|
||||
*/
|
||||
public function getBackup(string $token): Backup {
|
||||
$backups = $this->listing();
|
||||
|
||||
foreach ($backups as $backup) {
|
||||
if ($backup->getId() === $token) {
|
||||
return $backup;
|
||||
}
|
||||
}
|
||||
|
||||
throw new BackupNotFoundException('Backup not found');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsoluteRoot(Backup $backup) {
|
||||
$compared = false;
|
||||
$absoluteRoot = '';
|
||||
foreach ($backup->getChunks() as $backupChunk) {
|
||||
if ($backupChunk->getType() >= BackupChunk::SQL_DUMP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$compared) {
|
||||
$absoluteRoot = $backupChunk->getRoot();
|
||||
$compared = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$absoluteRoot = $this->commonPart($absoluteRoot, $backupChunk->getRoot());
|
||||
}
|
||||
|
||||
return $absoluteRoot;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Backup
|
||||
* @throws NotPermittedException
|
||||
*/
|
||||
private function initBackup(): Backup {
|
||||
$this->initBackupFS();
|
||||
|
||||
$backup = new Backup(true);
|
||||
$backup->setVersion(Util::getVersion());
|
||||
|
||||
$folder = $this->appData->newFolder('/' . $backup->getName());
|
||||
$temp = $folder->newFile(self::SUMMARY_FILE);
|
||||
$temp->putContent('');
|
||||
|
||||
$backup->setBaseFolder($folder);
|
||||
|
||||
$backup->addChunk(new BackupChunk(BackupChunk::ROOT_DATA, '', 'data'));
|
||||
$backup->addChunk(new BackupChunk(BackupChunk::ROOT_NEXTCLOUD, 'apps/', 'apps'));
|
||||
$backup->addChunk(new BackupChunk(BackupChunk::FILE_CONFIG, '', 'config'));
|
||||
|
||||
$this->addCustomAppsChunk($backup);
|
||||
|
||||
return $backup;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws NotPermittedException
|
||||
*/
|
||||
private function initBackupFS() {
|
||||
$path = '/';
|
||||
|
||||
try {
|
||||
$folder = $this->appData->getFolder($path);
|
||||
} catch (NotFoundException $e) {
|
||||
$folder = $this->appData->newFolder($path);
|
||||
}
|
||||
|
||||
$folder->newFile(self::NOBACKUP_FILE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @throws NotPermittedException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
private function endBackup(Backup $backup) {
|
||||
if (!$backup->hasBaseFolder()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$folder = $backup->getBaseFolder();
|
||||
|
||||
$json = $folder->getFile(self::SUMMARY_FILE);
|
||||
$json->putContent(json_encode($backup, JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return Backup
|
||||
* @throws BackupFolderException
|
||||
* @throws NotPermittedException
|
||||
*/
|
||||
private function parseFromFolder(string $path): Backup {
|
||||
try {
|
||||
$folder = $this->appData->getFolder($path);
|
||||
$json = $folder->getFile(self::SUMMARY_FILE)
|
||||
->getContent();
|
||||
|
||||
$summary = json_decode($json, true);
|
||||
if (!is_array($summary)) {
|
||||
throw new BackupFolderException();
|
||||
}
|
||||
|
||||
$backup = new Backup();
|
||||
$backup->setBaseFolder($folder);
|
||||
|
||||
return $backup->import($summary);
|
||||
} catch (NotFoundException $e) {
|
||||
throw new BackupFolderException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*/
|
||||
private function addCustomAppsChunk(Backup $backup) {
|
||||
// TODO: testing with custom apps folder (should work)
|
||||
$customApps = $this->configService->getSystemValue('apps_paths');
|
||||
if (is_array($customApps)) {
|
||||
foreach ($customApps as $app) {
|
||||
if (!is_array($app) || !array_key_exists('path', $app)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$backup->addChunk(
|
||||
new BackupChunk(
|
||||
BackupChunk::ROOT_DISK, $app['path'], 'apps_' . $this->uuid(8)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @throws ArchiveCreateExceptionAlias
|
||||
* @throws Exception
|
||||
*/
|
||||
private function backupSql(Backup $backup) {
|
||||
$content = $this->generateSqlDump();
|
||||
|
||||
$chunk = new BackupChunk(BackupChunk::SQL_DUMP, '', 'sqldump');
|
||||
$this->archiveService->createContentArchive(
|
||||
$backup, $chunk, self::SQL_DUMP_FILE, $content
|
||||
);
|
||||
|
||||
$backup->addChunk($chunk);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function generateSqlDump() {
|
||||
$data = [
|
||||
'dbname' => $this->configService->getSystemValue('dbname'),
|
||||
'dbhost' => $this->configService->getSystemValue('dbhost'),
|
||||
'dbport' => $this->configService->getSystemValue('dbport'),
|
||||
'dbuser' => $this->configService->getSystemValue('dbuser'),
|
||||
'dbpassword' => $this->configService->getSystemValue('dbpassword')
|
||||
];
|
||||
|
||||
// $folder = $this->appData->getFolder('/' . $backup->getName());
|
||||
// $sql = $folder->newFile(self::SQL_DUMP_FILE);
|
||||
// $sql->putContent('');
|
||||
//
|
||||
$sqlDump = new SqlDumpMySQL();
|
||||
$content = $sqlDump->export($data);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param string $name
|
||||
*
|
||||
* @return BackupChunk
|
||||
* @throws ChunkNotFoundException
|
||||
*/
|
||||
public function getChunk(Backup $backup, string $name): BackupChunk {
|
||||
foreach ($backup->getChunks() as $chunk) {
|
||||
if ($chunk->getName() === $name) {
|
||||
return $chunk;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ChunkNotFoundException();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,505 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Service;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Exceptions\MalformedArrayException;
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use Exception;
|
||||
use OCA\Backup\Exceptions\ArchiveDeleteException;
|
||||
use OCA\Backup\Exceptions\ArchiveNotFoundException;
|
||||
use OCA\Backup\Exceptions\BackupFolderException;
|
||||
use OCA\Backup\Exceptions\ChunkNotFoundException;
|
||||
use OCA\Backup\Exceptions\EncryptionKeyException;
|
||||
use OCA\Backup\Model\ArchiveFile;
|
||||
use OCA\Backup\Model\Backup;
|
||||
use OCA\Backup\Model\BackupArchive;
|
||||
use OCA\Backup\Model\BackupChunk;
|
||||
use OCA\Backup\Model\BackupOptions;
|
||||
use OCA\Backup\SqlDump\SqlDumpMySQL;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
|
||||
|
||||
/**
|
||||
* Class CliService
|
||||
*
|
||||
* @package OCA\Backup\Service
|
||||
*/
|
||||
class CliService {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
|
||||
|
||||
/** @var ArchiveService */
|
||||
private $archiveService;
|
||||
|
||||
/** @var BackupService */
|
||||
private $backupService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/** @var InputInterface */
|
||||
private $input;
|
||||
|
||||
/** @var OutputInterface */
|
||||
private $output;
|
||||
|
||||
|
||||
/**
|
||||
* CliService constructor.
|
||||
*
|
||||
* @param ArchiveService $archiveService
|
||||
* @param BackupService $backupService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(
|
||||
ArchiveService $archiveService, BackupService $backupService, MiscService $miscService
|
||||
) {
|
||||
$this->archiveService = $archiveService;
|
||||
$this->backupService = $backupService;
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
public function init(InputInterface $input, OutputInterface $output): void {
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*/
|
||||
public function displayBackupResume(Backup $backup): void {
|
||||
$version = $backup->getVersion();
|
||||
array_pop($version);
|
||||
|
||||
$this->output->writeln('<info>Token:</info> ' . $backup->getId());
|
||||
$this->output->writeln('<info>Name:</info> ' . $backup->getName());
|
||||
$this->output->writeln('<info>Date:</info> ' . date('Y-m-d H:i:s', $backup->getCreation()));
|
||||
$this->output->writeln('<info>Nextcloud</info> ' . implode('.', $version));
|
||||
|
||||
$root = $this->backupService->getAbsoluteRoot($backup);
|
||||
$options = $backup->getOptions();
|
||||
$root .= ($options->getNewRoot() !== '') ? ' -> ' . $options->getNewRoot() : '';
|
||||
|
||||
$this->output->writeln('<info>Root:</info> ' . $root);
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @throws EncryptionKeyException
|
||||
* @throws ArchiveDeleteException
|
||||
*/
|
||||
public function displayBackupDetails(Backup $backup): void {
|
||||
foreach ($backup->getChunks(true) as $backupChunk) {
|
||||
$this->displayBackupChunk($backup, $backupChunk);
|
||||
$this->displayBackupArchives($backup, $backupChunk->getArchives());
|
||||
|
||||
$this->output->writeln('');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $chunk
|
||||
*/
|
||||
public function displayBackupChunk(Backup $backup, BackupChunk $chunk): void {
|
||||
$root = $chunk->getRoot();
|
||||
// $options = $backup->getOptions();
|
||||
if ($backup->getOptions()
|
||||
->getNewRoot()) {
|
||||
$root .= ' -> ' . $this->backupService->getExtractRoot($backup, $chunk);
|
||||
}
|
||||
|
||||
$path = ($chunk->getPath() === '') ? '.' : $chunk->getPath();
|
||||
$this->output->writeln('- <info>Chunk:</info> ' . $chunk->getName());
|
||||
|
||||
if ($chunk->getRoot() === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->output->writeln('- <info>Root:</info> ' . $root);
|
||||
$this->output->writeln('- <info>Path:</info> ' . $path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @throws ArchiveDeleteException
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws EncryptionKeyException
|
||||
* @throws BackupFolderException
|
||||
*/
|
||||
public function displayBackupRestore(Backup $backup): void {
|
||||
|
||||
$options = $backup->getOptions();
|
||||
foreach ($backup->getChunks(true) as $chunk) {
|
||||
|
||||
$this->displayBackupChunk($backup, $chunk);
|
||||
|
||||
// TODO: pre-manage archives (continue on Exception)
|
||||
if ($chunk->getType() >= BackupChunk::SQL_DUMP) {
|
||||
$this->manageNonFileBackup($backup, $chunk);
|
||||
continue;
|
||||
}
|
||||
|
||||
$root = $this->backupService->getExtractRoot($backup, $chunk);
|
||||
|
||||
$helper = new QuestionHelper();
|
||||
$question = '- Extract this chunk in <info>' . $root . '</info> [Y/n]?';
|
||||
if (!$helper->ask($this->input, $this->output, new ConfirmationQuestion($question))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($chunk->getArchives() as $archive) {
|
||||
$this->output->write(' > ' . $archive->getName());
|
||||
|
||||
if ($options->isAll()) {
|
||||
$this->archiveService->extractAll($backup, $archive, $root);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->archiveService->decryptArchive($backup, $archive);
|
||||
$zip = $this->archiveService->openZipArchive($archive);
|
||||
$this->archiveService->listFilesFromZip($archive, $zip);
|
||||
foreach ($archive->getFiles() as $file) {
|
||||
$this->output->write(' * ' . $file->getName(), false);
|
||||
$this->archiveService->extractFilesFromZip($zip, $root, [$file]);
|
||||
}
|
||||
$this->archiveService->deleteArchive($backup, $archive, 'zip');
|
||||
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
if ($options->isAll()) {
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
// TODO: post manage archives
|
||||
if ($chunk->getType() === BackupChunk::FILE_CONFIG) {
|
||||
$this->manageConfigBackup($backup, $chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
*
|
||||
* @throws ArchiveDeleteException
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws EncryptionKeyException
|
||||
*/
|
||||
public function displayFilesList(Backup $backup): void {
|
||||
|
||||
foreach ($backup->getChunks(true) as $backupChunk) {
|
||||
|
||||
$this->displayBackupChunk($backup, $backupChunk);
|
||||
foreach ($backupChunk->getArchives() as $archive) {
|
||||
$this->archiveService->decryptArchive($backup, $archive);
|
||||
$zip = $this->archiveService->openZipArchive($archive);
|
||||
$this->archiveService->listFilesFromZip($archive, $zip);
|
||||
|
||||
foreach ($archive->getFiles() as $file) {
|
||||
if ($this->fitSearch($backup->getOptions(), $file)) {
|
||||
echo '- ' . $archive->getName() . ': ' . $file->getName() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$this->archiveService->deleteArchive($backup, $archive, 'zip');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param BackupOptions $options
|
||||
* @param ArchiveFile $file
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function fitSearch(BackupOptions $options, ArchiveFile $file) {
|
||||
$fitSearch = $fitPath = false;
|
||||
|
||||
$search = $options->getSearch();
|
||||
$path = $options->getPath();
|
||||
if ($search === '' || strpos($file->getName(), $search)) {
|
||||
$fitSearch = true;
|
||||
}
|
||||
|
||||
if ($path === '' || strpos($file->getName(), $path) === 0) {
|
||||
$fitPath = true;
|
||||
}
|
||||
|
||||
return ($fitPath && $fitSearch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param array $backupArchives
|
||||
*
|
||||
* @throws EncryptionKeyException
|
||||
* @throws ArchiveDeleteException
|
||||
*/
|
||||
private function displayBackupArchives(Backup $backup, array $backupArchives): void {
|
||||
|
||||
$table = new Table($this->output);
|
||||
$table->setHeaders(
|
||||
['', 'Name', 'Files', 'Size', 'Encrypted Checksum', 'Archive Checksum'], []
|
||||
);
|
||||
$table->render();
|
||||
$this->output->writeln('');
|
||||
|
||||
$c = 0;
|
||||
foreach ($backupArchives as $archive) {
|
||||
$checksum = $this->generateEncryptedChecksum($backup, $archive);
|
||||
$decryptedChecksum = $this->generateArchiveChecksum($backup, $archive);
|
||||
$table->appendRow(
|
||||
[
|
||||
++$c . '/' . count($backupArchives),
|
||||
$archive->getName(),
|
||||
$archive->getCount(),
|
||||
$archive->getSize(),
|
||||
$checksum,
|
||||
$decryptedChecksum
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateEncryptedChecksum(Backup $backup, BackupArchive $archive): string {
|
||||
if (!$this->input->getOption('check')) {
|
||||
return $archive->getEncryptedChecksum();
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->archiveService->verifyChecksum($backup, $archive, true)) {
|
||||
return '<info>' . $archive->getEncryptedChecksum() . '</info>';
|
||||
}
|
||||
|
||||
return '<error>' . $archive->getEncryptedChecksum() . '</error>';
|
||||
} catch (Exception $e) {
|
||||
return '<error>' . $e->getMessage() . '</error>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupArchive $archive
|
||||
*
|
||||
* @return string
|
||||
* @throws EncryptionKeyException
|
||||
* @throws ArchiveDeleteException
|
||||
*/
|
||||
private function generateArchiveChecksum(Backup $backup, BackupArchive $archive): string {
|
||||
if ($backup->getEncryptionKey() === '') {
|
||||
return $archive->getChecksum();
|
||||
}
|
||||
|
||||
try {
|
||||
$this->archiveService->decryptArchive($backup, $archive);
|
||||
$check = $this->archiveService->verifyChecksum($backup, $archive, false);
|
||||
$this->archiveService->deleteArchive($backup, $archive, 'zip');
|
||||
|
||||
if ($check) {
|
||||
return '<info>' . $archive->getChecksum() . '</info>';
|
||||
}
|
||||
|
||||
return '<error>' . $archive->getChecksum() . '</error>';
|
||||
} catch (ArchiveNotFoundException $e) {
|
||||
return '<error>' . $e->getMessage() . '</error>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $chunk
|
||||
*/
|
||||
private function manageNonFileBackup(Backup $backup, BackupChunk $chunk): void {
|
||||
switch ($chunk->getType()) {
|
||||
case BackupChunk::SQL_DUMP:
|
||||
$this->manageSqlDump($backup, $chunk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $chunk
|
||||
*/
|
||||
private function manageSqlDump(Backup $backup, BackupChunk $chunk) {
|
||||
$helper = new QuestionHelper();
|
||||
|
||||
$data = [];
|
||||
try {
|
||||
$configChunk = $this->backupService->getChunk($backup, 'config');
|
||||
$config = $this->backupService->getExtractRoot($backup, $configChunk) . 'config.php';
|
||||
|
||||
$question = '- Using database configured in <info>' . $config . '</info> [Y/n]?';
|
||||
if (file_exists($config)
|
||||
&& $helper->ask($this->input, $this->output, new ConfirmationQuestion($question))) {
|
||||
$data = $this->extractDatabaseConfig($config);
|
||||
} else {
|
||||
$this->output->writeln(' <!> File <comment>' . $config . '</comment> not found');
|
||||
}
|
||||
} catch (ChunkNotFoundException | MalformedArrayException $e) {
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
// TODO: ask for credentials
|
||||
}
|
||||
|
||||
$question = '- Restore your database in <info>' . $data['dbname'] . '</info> [Y/n]?';
|
||||
if ($helper->ask($this->input, $this->output, new ConfirmationQuestion($question))) {
|
||||
try {
|
||||
$this->importDumpFromChunk($backup, $chunk, $data);
|
||||
} catch (ArchiveDeleteException $e) {
|
||||
} catch (ArchiveNotFoundException $e) {
|
||||
} catch (EncryptionKeyException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $config
|
||||
*
|
||||
* @return array
|
||||
* @throws MalformedArrayException
|
||||
*/
|
||||
private function extractDatabaseConfig(string $config): array {
|
||||
$CONFIG = [];
|
||||
require($config);
|
||||
|
||||
$this->mustContains(['dbtype'], $CONFIG);
|
||||
if ($CONFIG['dbtype'] === 'mysql') {
|
||||
$this->mustContains(['dbname', 'dbport', 'dbhost', 'dbuser', 'dbpassword'], $CONFIG);
|
||||
$data = [
|
||||
'dbname' => $CONFIG['dbname'],
|
||||
'dbhost' => $CONFIG['dbhost'],
|
||||
'dbport' => $CONFIG['dbport'],
|
||||
'dbuser' => $CONFIG['dbuser'],
|
||||
'dbpassword' => $CONFIG['dbpassword']
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $chunk
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @throws ArchiveDeleteException
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws EncryptionKeyException
|
||||
*/
|
||||
private function importDumpFromChunk(Backup $backup, BackupChunk $chunk, array $data) {
|
||||
foreach ($chunk->getArchives() as $archive) {
|
||||
$this->archiveService->decryptArchive($backup, $archive);
|
||||
$zip = $this->archiveService->openZipArchive($archive);
|
||||
$read =
|
||||
$this->archiveService->extractContentFromZip($zip, BackupService::SQL_DUMP_FILE);
|
||||
|
||||
$sqlDump = new SqlDumpMySQL();
|
||||
$sqlDump->import($data, $read);
|
||||
|
||||
$this->archiveService->deleteArchive($backup, $archive, 'zip');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Backup $backup
|
||||
* @param BackupChunk $chunk
|
||||
*/
|
||||
private function manageConfigBackup(Backup $backup, BackupChunk $chunk) {
|
||||
$options = $backup->getOptions();
|
||||
|
||||
if (empty($options->getConfig()) && !$options->isFixDataDir()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$configFile = $this->backupService->getExtractRoot($backup, $chunk) . 'config.php';
|
||||
$CONFIG = [];
|
||||
require($configFile);
|
||||
|
||||
if ($options->isFixDataDir()) {
|
||||
try {
|
||||
$dataChunk = $this->backupService->getChunk($backup, 'data');
|
||||
$CONFIG['datadirectory'] =
|
||||
$this->backupService->getExtractRoot($backup, $dataChunk);
|
||||
} catch (ChunkNotFoundException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
$CONFIG = array_merge($CONFIG, $options->getConfig());
|
||||
|
||||
file_put_contents($configFile, "<?php\n" . '$CONFIG = ' . var_export($CONFIG, true) . ';');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/** @noinspection PhpUndefinedClassInspection */
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Service;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use daita\MySmallPhpTools\Traits\TPathTools;
|
||||
use OCA\Backup\AppInfo\Application;
|
||||
use OCP\IConfig;
|
||||
|
||||
|
||||
class ConfigService {
|
||||
|
||||
|
||||
use TPathTools;
|
||||
use TArrayTools;
|
||||
|
||||
|
||||
/** @var array */
|
||||
public $defaults = [];
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* ConfigService constructor.
|
||||
*
|
||||
* @param IConfig $config
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(IConfig $config, MiscService $miscService) {
|
||||
$this->config = $config;
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a value by key
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAppValue($key) {
|
||||
$defaultValue = null;
|
||||
if (array_key_exists($key, $this->defaults)) {
|
||||
$defaultValue = $this->defaults[$key];
|
||||
}
|
||||
|
||||
return $this->config->getAppValue(Application::APP_ID, $key, $defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value by key
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getAppValueInt(string $key): int {
|
||||
$defaultValue = null;
|
||||
if (array_key_exists($key, $this->defaults)) {
|
||||
$defaultValue = $this->defaults[$key];
|
||||
}
|
||||
|
||||
return (int)$this->config->getAppValue(Application::APP_ID, $key, $defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value by key
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setAppValue($key, $value) {
|
||||
$this->config->setAppValue(Application::APP_ID, $key, $value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSystemValue($key) {
|
||||
return $this->config->getSystemValue($key, '');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Service;
|
||||
|
||||
|
||||
use OCA\Backup\Exceptions\ArchiveNotFoundException;
|
||||
use OCA\Backup\Exceptions\EncryptionKeyException;
|
||||
|
||||
/**
|
||||
* Class EncryptService
|
||||
*
|
||||
* @package OCA\Backup\Service
|
||||
*/
|
||||
class EncryptService {
|
||||
|
||||
|
||||
const BLOCK_SIZE = 500;
|
||||
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* EncryptService constructor.
|
||||
*
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(MiscService $miscService) {
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param resource $in
|
||||
* @param resource $out
|
||||
* @param string $key
|
||||
*/
|
||||
public function encryptFile($in, $out, $key) {
|
||||
$iv = openssl_random_pseudo_bytes(16);
|
||||
|
||||
fwrite($out, $iv);
|
||||
while (!feof($in)) {
|
||||
$clear = fread($in, 16 * self::BLOCK_SIZE);
|
||||
$encrypted = openssl_encrypt($clear, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
|
||||
fwrite($out, $encrypted);
|
||||
|
||||
$iv = substr($encrypted, 0, 16);
|
||||
}
|
||||
|
||||
fclose($in);
|
||||
fclose($out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param resource $in
|
||||
* @param resource $out
|
||||
* @param string $key
|
||||
*
|
||||
* @throws ArchiveNotFoundException
|
||||
* @throws EncryptionKeyException
|
||||
*/
|
||||
public function decryptFile($in, $out, $key) {
|
||||
if (is_bool($in)) {
|
||||
throw new ArchiveNotFoundException('archive not found');
|
||||
}
|
||||
|
||||
$iv = fread($in, 16);
|
||||
while (!feof($in)) {
|
||||
$encrypted = fread($in, 16 * (self::BLOCK_SIZE + 1));
|
||||
$clear = openssl_decrypt($encrypted, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
|
||||
if (is_bool($clear)) {
|
||||
throw new EncryptionKeyException('Wrong encryption key');
|
||||
}
|
||||
fwrite($out, $clear);
|
||||
|
||||
$iv = substr($encrypted, 0, 16);
|
||||
}
|
||||
|
||||
fclose($in);
|
||||
fclose($out);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Service;
|
||||
|
||||
|
||||
use OCA\Backup\Model\Backup;
|
||||
|
||||
/**
|
||||
* Class ExtractService
|
||||
*
|
||||
* @package OCA\Backup\Service
|
||||
*/
|
||||
class ExtractService {
|
||||
|
||||
|
||||
const BLOCK_SIZE = 500;
|
||||
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* ExtractService constructor.
|
||||
*
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(MiscService $miscService) {
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $backup
|
||||
*/
|
||||
public function extract(Backup $backup) {
|
||||
|
||||
echo 'EXTRACT !';
|
||||
echo 'EXTRACT !';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Service;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use daita\MySmallPhpTools\Traits\TPathTools;
|
||||
use daita\MySmallPhpTools\Traits\TStringTools;
|
||||
use OCA\Backup\Model\Backup;
|
||||
use OCA\Backup\Model\BackupArchive;
|
||||
use OCA\Backup\Model\BackupChunk;
|
||||
|
||||
|
||||
/**
|
||||
* Class FilesService
|
||||
*
|
||||
* @package OCA\Backup\Service
|
||||
*/
|
||||
class FilesService {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
use TStringTools;
|
||||
|
||||
|
||||
const APP_ROOT = __DIR__ . '/../../';
|
||||
|
||||
|
||||
/** @var ConfigService */
|
||||
private $configService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* FilesService constructor.
|
||||
*
|
||||
* @param ConfigService $configService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(ConfigService $configService, MiscService $miscService) {
|
||||
$this->configService = $configService;
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param BackupChunk $backupChunk
|
||||
* @param string $path
|
||||
*/
|
||||
public function fillBackupChunk(BackupChunk $backupChunk, string $path = ''): void {
|
||||
|
||||
// TODO: check no trailing slashes
|
||||
if (!is_dir($backupChunk->getAbsolutePath() . $path)) {
|
||||
$backupChunk->addFile($path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($path !== '') {
|
||||
$path .= '/';
|
||||
}
|
||||
|
||||
if (file_exists($backupChunk->getAbsolutePath() . $path . BackupService::NOBACKUP_FILE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (scandir($backupChunk->getAbsolutePath() . $path) as $entry) {
|
||||
if ($entry === '.' || $entry === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->fillBackupChunk($backupChunk, $path . $entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
use TPathTools;
|
||||
|
||||
/**
|
||||
* @param BackupChunk $backupChunk
|
||||
*/
|
||||
public function initBackupChunk(BackupChunk $backupChunk): void {
|
||||
$root = '';
|
||||
switch ($backupChunk->getType()) {
|
||||
case BackupChunk::ROOT_DISK:
|
||||
$root = '/';
|
||||
break;
|
||||
|
||||
case BackupChunk::ROOT_NEXTCLOUD:
|
||||
$root = \OC::$SERVERROOT;
|
||||
break;
|
||||
|
||||
case BackupChunk::ROOT_DATA:
|
||||
$root = $this->configService->getSystemValue('datadirectory');
|
||||
break;
|
||||
|
||||
case BackupChunk::FILE_CONFIG:
|
||||
$root = \OC::$SERVERROOT;
|
||||
$backupChunk->setPath('config/');
|
||||
$backupChunk->setUniqueFile('config.php');
|
||||
break;
|
||||
}
|
||||
|
||||
if ($root !== '') {
|
||||
$backupChunk->setRoot($this->withEndSlash($root));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getFilesFromApp($path = ''): array {
|
||||
$files = [];
|
||||
foreach (scandir(self::APP_ROOT . $path) as $entry) {
|
||||
if ($entry === '.' || $entry === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir(self::APP_ROOT . $path . $entry)) {
|
||||
$files = array_merge($files, $this->getFilesFromApp($path . $entry . '/'));
|
||||
}
|
||||
|
||||
if (is_file(self::APP_ROOT . $path . $entry)) {
|
||||
$files[] = $path . $entry;
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
/** @noinspection PhpUndefinedClassInspection */
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\Service;
|
||||
|
||||
|
||||
use OCA\Backup\AppInfo\Application;
|
||||
use OCP\ILogger;
|
||||
|
||||
|
||||
/**
|
||||
* Class MiscService
|
||||
*
|
||||
* @package OCA\Backup\Service
|
||||
*/
|
||||
class MiscService {
|
||||
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
|
||||
/**
|
||||
* MiscService constructor.
|
||||
*
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
public function __construct(ILogger $logger) {
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param int $level
|
||||
*/
|
||||
public function log($message, $level = 2) {
|
||||
$data = array(
|
||||
'app' => Application::APP_ID,
|
||||
'level' => $level
|
||||
);
|
||||
|
||||
$this->logger->log($level, $message, $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Backup
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Backup\SqlDump;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Ifsnop\Mysqldump\Mysqldump;
|
||||
use OCA\Backup\ISqlDump;
|
||||
|
||||
|
||||
/**
|
||||
* Class SqlDumpMySQL
|
||||
*
|
||||
* @package OCA\Backup\SqlDump
|
||||
*/
|
||||
class SqlDumpMySQL implements ISqlDump {
|
||||
|
||||
|
||||
/**
|
||||
* SqlDumpMySQL constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function export(array $data): string {
|
||||
$connect = 'mysql:host=' . $data['dbhost'] . ';dbname=' . $data['dbname'];
|
||||
$settings = [
|
||||
'compress' => Mysqldump::NONE,
|
||||
'no-data' => false,
|
||||
'add-drop-table' => true,
|
||||
'single-transaction' => true,
|
||||
'lock-tables' => true,
|
||||
'add-locks' => true,
|
||||
'extended-insert' => true,
|
||||
'disable-foreign-keys-check' => true,
|
||||
'skip-triggers' => false,
|
||||
'add-drop-trigger' => true,
|
||||
'databases' => false,
|
||||
'add-drop-database' => true,
|
||||
'hex-blob' => true
|
||||
];
|
||||
|
||||
$dump = new Mysqldump($connect, $data['dbuser'], $data['dbpassword'], $settings);
|
||||
|
||||
ob_start();
|
||||
$dump->start();
|
||||
$content = ob_get_clean();
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param resource $read
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function import(array $data, $read): bool {
|
||||
$sql =
|
||||
mysqli_connect($data['dbhost'], $data['dbuser'], $data['dbpassword'], $data['dbname']);
|
||||
|
||||
$request = '';
|
||||
while (($line = fgets($read)) !== false) {
|
||||
$line = trim($line);
|
||||
if (substr($line, 0, 2) === '--' || $line === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$request .= $line;
|
||||
if (substr($line, -1) === ';') {
|
||||
mysqli_query($sql, $request);
|
||||
$request = '';
|
||||
}
|
||||
}
|
||||
|
||||
mysqli_close($sql);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче