This commit is contained in:
Maxence Lange 2021-09-08 12:30:29 -01:00
Родитель 5ab334bc95
Коммит b8165fdc87
35 изменённых файлов: 2383 добавлений и 724 удалений

Просмотреть файл

@ -1,37 +0,0 @@
<?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\AppInfo;
require_once __DIR__ . '/autoload.php';

Просмотреть файл

@ -3,11 +3,10 @@
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 a Nextcloud instance and restore it. Possible via occ or REST]]></description>
<description><![CDATA[Backup. Restore.]]></description>
<licence>agpl</licence>
<author mail="maxence@artificial-owl.com">Maxence Lange</author>
<author>Frank Karlitschek</author>
<version>0.1.0</version>
<version>0.1.2</version>
<namespace>Backup</namespace>
<category>tools</category>
<website>https://github.com/nextcloud/backup</website>
@ -15,17 +14,20 @@
<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="16" max-version="17"/>
<nextcloud min-version="22" max-version="23"/>
</dependencies>
<background-jobs>
<job>OCA\Backup\Cron\Backup</job>
</background-jobs>
<!-- <background-jobs>-->
<!-- <job>OCA\Backup\Cron\Backup</job>-->
<!-- </background-jobs>-->
<commands>
<command>OCA\Backup\Command\Create</command>
<command>OCA\Backup\Command\Listing</command>
<command>OCA\Backup\Command\Details</command>
<command>OCA\Backup\Command\Restore</command>
<command>OCA\Backup\Command\RemoteAdd</command>
<command>OCA\Backup\Command\RemoteList</command>
<!-- <command>OCA\Backup\Command\Remote</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>

Просмотреть файл

@ -1,29 +1,8 @@
<?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/>.
*
*/
return [
'ocs' => [
['name' => 'API#createBackup', 'url' => '/api/v1/create', 'verb' => 'POST'],
['name' => 'API#restoreBackup', 'url' => '/api/v1/restore', 'verb' => 'POST'],
],
'routes' => [
['name' => 'Remote#appService', 'url' => '/', 'verb' => 'GET'],
['name' => 'Remote#test', 'url' => '/test', 'verb' => 'GET']
]
];

Просмотреть файл

@ -15,9 +15,8 @@
}
},
"require": {
"daita/my-small-php-tools": "dev-master",
"artificial-owl/my-small-php-tools": "~23",
"ifsnop/mysqldump-php": "2.0.0",
"symfony/console": "^4.2",
"pimple/pimple": "~3.0"
}
}

Просмотреть файл

@ -1,23 +0,0 @@
{
"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",
}
}

261
composer.lock сгенерированный
Просмотреть файл

@ -1,32 +1,32 @@
{
"_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",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b6c5df6ef9c263971da6fe6265a51a5f",
"content-hash": "f5e410c5db65574e29844da89236fc3e",
"packages": [
{
"name": "daita/my-small-php-tools",
"version": "dev-master",
"name": "artificial-owl/my-small-php-tools",
"version": "v23.0.5",
"source": {
"type": "git",
"url": "https://github.com/daita/my-small-php-tools.git",
"reference": "e2ac095a0148fec7aaafe5dc9edc20d65c2d1f14"
"url": "https://github.com/ArtificialOwl/my-small-php-tools.git",
"reference": "0574c5936e45299541453f47344ce90866abc0f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/daita/my-small-php-tools/zipball/e2ac095a0148fec7aaafe5dc9edc20d65c2d1f14",
"reference": "e2ac095a0148fec7aaafe5dc9edc20d65c2d1f14",
"url": "https://api.github.com/repos/ArtificialOwl/my-small-php-tools/zipball/0574c5936e45299541453f47344ce90866abc0f2",
"reference": "0574c5936e45299541453f47344ce90866abc0f2",
"shasum": ""
},
"require": {
"php": "^7.0"
"php": ">=7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"daita\\MySmallPhpTools\\": "lib/"
"ArtificialOwl\\MySmallPhpTools\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
@ -40,7 +40,11 @@
}
],
"description": "My small PHP Tools",
"time": "2019-03-29T18:48:14+00:00"
"support": {
"issues": "https://github.com/ArtificialOwl/my-small-php-tools/issues",
"source": "https://github.com/ArtificialOwl/my-small-php-tools/tree/v23.0.5"
},
"time": "2021-09-08T12:00:47+00:00"
},
{
"name": "ifsnop/mysqldump-php",
@ -92,6 +96,10 @@
"pdo",
"sqlite"
],
"support": {
"issues": "https://github.com/ifsnop/mysqldump-php/issues",
"source": "https://github.com/ifsnop/mysqldump-php/tree/devel"
},
"time": "2015-09-10T19:58:38+00:00"
},
{
@ -142,31 +150,30 @@
"container",
"dependency injection"
],
"support": {
"issues": "https://github.com/silexphp/Pimple/issues",
"source": "https://github.com/silexphp/Pimple/tree/master"
},
"time": "2018-01-21T07:42:36+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf",
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": ">=7.2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
@ -179,7 +186,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
@ -191,219 +198,23 @@
"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"
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/1.1.1"
},
"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"
"time": "2021-03-05T17:36:06+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"daita/my-small-php-tools": 20
},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"platform-overrides": {
"php": "7.2.0"
}
},
"plugin-api-version": "2.0.0"
}

Просмотреть файл

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
@ -8,7 +9,6 @@ declare(strict_types=1);
* 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
@ -32,7 +32,22 @@ declare(strict_types=1);
namespace OCA\Backup\AppInfo;
use OCA\Backup\Handlers\WebfingerHandler;
use OCA\Backup\Listeners\FileChanged;
use OCA\Backup\Listeners\FileCreated;
use OCA\Backup\Listeners\FileDeleted;
use OCA\Backup\Listeners\FileRenamed;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\Files\Events\Node\NodeCreatedEvent;
use OCP\Files\Events\Node\NodeDeletedEvent;
use OCP\Files\Events\Node\NodeRenamedEvent;
use OCP\Files\Events\Node\NodeWrittenEvent;
require_once __DIR__ . '/../../vendor/autoload.php';
/**
@ -40,10 +55,13 @@ use OCP\AppFramework\App;
*
* @package OCA\Backup\AppInfo
*/
class Application extends App {
class Application extends App implements IBootstrap {
const APP_ID = 'backup';
const APP_NAME = 'Backup';
const APP_SUBJECT = 'http://nextcloud.com/';
const APP_REL = 'https://apps.nextcloud.com/apps/backup';
/**
@ -55,5 +73,25 @@ class Application extends App {
parent::__construct(self::APP_ID, $params);
}
/**
* @param IRegistrationContext $context
*/
public function register(IRegistrationContext $context): void {
$context->registerEventListener(NodeCreatedEvent::class, FileCreated::class);
$context->registerEventListener(NodeWrittenEvent::class, FileChanged::class);
$context->registerEventListener(NodeRenamedEvent::class, FileRenamed::class);
$context->registerEventListener(NodeDeletedEvent::class, FileDeleted::class);
$context->registerWellKnownHandler(WebfingerHandler::class);
}
/**
* @param IBootContext $context
*/
public function boot(IBootContext $context): void {
}
}

Просмотреть файл

@ -1,146 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2017 Frank Karlitschek <frank@karlitschek.de>
*
* @author Frank Karlitschek <frank@karlitchek.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\Backup;
class Create {
/** @var path */
protected $path;
/** @var password */
protected $password;
/**
* @param string $path
*/
public function __construct($path) {
$this->path = $path;
}
/**
* @param string $password
*/
public function password($password) {
$this->password = $password;
}
/**
* @param string $dbtype
* @param string $dbname
* @param string $dbuser
* @param string $dbpassword
* @param string $dbhost
* @param string $path
*/
private function createDump($dbtype,$dbname,$dbuser,$dbpassword,$dbhost,$path) {
switch ($dbtype) {
case 'sqlite3':
// nothing to do because DB file is already in the data folder
break;
case 'mysql':
$check = shell_exec('which mysqldump');
if(!empty($check)) {
$cmd = 'mysqldump --password='.$dbpassword.' --user='.$dbuser.' --host='.$dbhost.' '.$dbname.' >'.$path.'/mysql.dmp';
shell_exec($cmd);
} else {
\OC::$server->getLogger()->error('rsync is not installed',['app' => 'backup',]);
}
break;
case 'pqsql':
// todo
break;
case 'oci':
// todo
break;
}
}
/**
* @param string $path
*/
private function copydata($path) {
$check = shell_exec('which rsync');
if(!empty($check)) {
$output = shell_exec('rsync -r '.\OCP\Config::getSystemValue('datadirectory').' '.$path);
} else {
\OC::$server->getLogger()->error('rsync is not installed',['app' => 'backup',]);
}
}
/**
* @param string $path
*/
private function copyconfig($path) {
$check = shell_exec('which rsync');
if(!empty($check)) {
$output = shell_exec('rsync -r '.\OC::$configDir.' '.$path.'/config');
} else {
\OC::$server->getLogger()->error('rsync is not installed',['app' => 'backup',]);
}
}
/**
* @param string $path
*/
private function writemeta($path) {
$meta = array('date' => date('c'), 'instanceid' => \OCP\Config::getSystemValue('instanceid'), 'dbtype' => \OCP\Config::getSystemValue('dbtype'));
file_put_contents($path.'/backup.json', json_encode($meta));
}
/**
*/
public function create() {
\OC::$server->getLogger()->warning('Create backup! Path:'.$this->path.' Password:'.$this->password,['app' => 'backup',]);
if(!is_dir($this->path) || !is_writable($this->path)) {
\OC::$server->getLogger()->error('Can\'t access directory '.$this->path,['app' => 'backup',]);
exit;
}
$maintainance = \OCP\Config::getSystemValue('maintenance');
\OCP\Config::setSystemValue('maintenance',true);
// create DB dump
$this->createDump(
\OCP\Config::getSystemValue('dbtype'),
\OCP\Config::getSystemValue('dbname'),
\OCP\Config::getSystemValue('dbuser'),
\OCP\Config::getSystemValue('dbpassword'),
\OCP\Config::getSystemValue('dbhost'),
$this->path
);
// copy config folder
$this->copyconfig($this->path);
// syncing data directory
$this->copydata($this->path);
// write meta file
$this->writemeta($this->path);
\OCP\Config::setSystemValue('maintenance',$maintainance);
}
}

Просмотреть файл

@ -1,82 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2017 Frank Karlitschek <frank@karlitschek.de>
*
* @author Frank Karlitschek <frank@karlitchek.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\Backup;
class Restore {
/** @var path */
protected $path;
/** @var password */
protected $password;
/**
* @param string $path
*/
public function __construct($path) {
$this->path = $path;
}
/**
* @param string $password
*/
public function password($password) {
$this->password = $password;
}
/**
* @param string $dbtype
* @param string $dbname
* @param string $dbuser
* @param string $dbpassword
* @param string $dbhost
* @param string $path
*/
private function restoreDump($dbtype,$dbname,$dbuser,$dbpassword,$dbhost,$path) {
}
/**
* @param string $path
*/
private function copydata($path) {
}
/**
* @param string $path
*/
private function copyconfig($path) {
}
/**
* @param string $path
*/
private function readmeta($path) {
}
/**
*/
public function restore() {
\OC::$server->getLogger()->warning('Restore backup! Path:'.$this->path.' Password:'.$this->password,['app' => 'backup',]);
}
}

Просмотреть файл

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
@ -8,7 +9,6 @@ declare(strict_types=1);
* 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

286
lib/Command/RemoteAdd.php Executable file
Просмотреть файл

@ -0,0 +1,286 @@
<?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 2021, 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 ArtificialOwl\MySmallPhpTools\Exceptions\RequestNetworkException;
use ArtificialOwl\MySmallPhpTools\Exceptions\SignatoryException;
use ArtificialOwl\MySmallPhpTools\Exceptions\SignatureException;
use ArtificialOwl\MySmallPhpTools\Exceptions\WellKnownLinkNotFoundException;
use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore;
use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc23\TNC23WellKnown;
use OC\Core\Command\Base;
use OCA\Backup\AppInfo\Application;
use OCA\Backup\Db\RemoteRequest;
use OCA\Backup\Exceptions\RemoteInstanceDuplicateException;
use OCA\Backup\Exceptions\RemoteInstanceNotFoundException;
use OCA\Backup\Exceptions\RemoteInstanceUidException;
use OCA\Backup\Model\RemoteInstance;
use OCA\Backup\Service\RemoteStreamService;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
/**
* Class RemoteAdd
*
* @package OCA\Backup\Command
*/
class RemoteAdd extends Base {
use TNC23WellKnown;
/** @var RemoteRequest */
private $remoteRequest;
/** @var RemoteStreamService */
private $remoteStreamService;
/**
* RemoteAdd constructor.
*
* @param RemoteRequest $remoteRequest
* @param RemoteStreamService $remoteStreamService
*/
public function __construct(
RemoteRequest $remoteRequest,
RemoteStreamService $remoteStreamService
) {
parent::__construct();
$this->remoteRequest = $remoteRequest;
$this->remoteStreamService = $remoteStreamService;
}
/**
*
*/
protected function configure() {
$this->setName('backup:remote:add')
->setDescription('Add remote instances to store your backups')
->addArgument('address', InputArgument::REQUIRED, 'address of the remote instance of Nextcloud');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
* @throws RequestNetworkException
* @throws SignatureException
* @throws WellKnownLinkNotFoundException
* @throws SignatoryException
* @throws RemoteInstanceUidException
* @throws RemoteInstanceDuplicateException
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
$address = $input->getArgument('address');
$resource = $this->getCurrentResourceFromAddress($output, $address);
$knownInstance = null;
try {
$knownInstance = $this->remoteRequest->getFromHref($resource->g('id'));
} catch (RemoteInstanceNotFoundException $e) {
}
try {
/** @var RemoteInstance $remoteSignatory */
$remoteSignatory = $this->remoteStreamService->retrieveSignatory($resource->g('id'), true);
} catch (SignatureException $e) {
throw new SignatureException($address . ' cannot auth its identity: ' . $e->getMessage());
}
try {
$duplicateInstance = $this->remoteRequest->getFromInstance($address);
if ($duplicateInstance->getId() !== $remoteSignatory->getId()) {
throw new RemoteInstanceDuplicateException(
'There is already a known instance with same ADDRESS but different HREF. Please remove it first!'
);
}
} catch (RemoteInstanceNotFoundException $e) {
}
$remoteSignatory->setInstance($address);
echo json_encode($knownInstance) . "\n";
if (!is_null($knownInstance)) {
if ($remoteSignatory->getInstance() !== $knownInstance->getInstance()) {
throw new RemoteInstanceDuplicateException(
'There is already a known instance with same HREF but different ADDRESS ('
. $knownInstance->getInstance() . '). Please remove it first!'
);
}
if ($remoteSignatory->getUid(true) !== $knownInstance->getUid()) {
$output->writeln('');
$output->writeln('<error>This instance is already known under an other identity!</error>');
$output->writeln(
'<error>Please CONFIRM with the admin of the remote instance before updating this known instance.</error>'
);
$helper = $this->getHelper('question');
$question = new ConfirmationQuestion(
'Are you sure you want to continue with the process ? (y/N)',
false,
'/^(y|Y)/i'
);
if (!$helper->ask($input, $output, $question)) {
return 0;
}
}
}
$this->configureRemoteInstance($input, $output, $remoteSignatory, $knownInstance);
$this->saveRemoteInstance($input, $output, $remoteSignatory);
return 0;
}
/**
* @param OutputInterface $output
* @param string $address
*
* @return SimpleDataStore
* @throws RequestNetworkException
* @throws WellKnownLinkNotFoundException
*/
private function getCurrentResourceFromAddress(
OutputInterface $output,
string $address
): SimpleDataStore {
try {
$webfinger = $this->getWebfinger($address, Application::APP_SUBJECT);
} catch (RequestNetworkException $e) {
throw new RequestNetworkException(
$address
. ' is not reachable or is not a instance of Nextcloud or do not have the Backup App installed'
);
}
try {
$backupLink = $this->extractLink(Application::APP_REL, $webfinger);
} catch (WellKnownLinkNotFoundException $e) {
throw new WellKnownLinkNotFoundException(
$address
. ' is not a instance of Nextcloud or do not have the Backup App installed and configured'
);
}
$output->writeln(
'Remote instance <info>' . $address . '</info> is using <info>' . $backupLink->getProperty('name')
. ' v' . $backupLink->getProperty('version') . '</info>'
);
$resource = $this->getResourceFromLink($backupLink);
$output->writeln('Authentication key: <info>' . $resource->g('uid') . '</info>');
return $resource;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @param RemoteInstance $remoteInstance
*/
private function configureRemoteInstance(
InputInterface $input,
OutputInterface $output,
RemoteInstance $remoteInstance,
?RemoteInstance $knownInstance
): void {
$outgoing = !(is_null($knownInstance)) && $knownInstance->isOutgoing();
$incoming = !(is_null($knownInstance)) && $knownInstance->isIncoming();
$output->writeln('');
$helper = $this->getHelper('question');
$question = new ConfirmationQuestion(
'Do you want to use <info>' . $remoteInstance->getInstance()
. '</info> as a remote instance to store your backup files ? '
. ($outgoing ? '(Y/n)' : '(y/N)'),
$outgoing,
'/^(y|Y)/i'
);
$remoteInstance->setOutgoing($helper->ask($input, $output, $question));
$question = new ConfirmationQuestion(
'Do you want to allow <info>' . $remoteInstance->getInstance()
. '</info> to store its backup files on your own instance ? '
. ($incoming ? '(Y/n)' : '(y/N)'),
$incoming,
'/^(y|Y)/i'
);
$remoteInstance->setIncoming($helper->ask($input, $output, $question));
}
/**
* @throws RemoteInstanceUidException
*/
private function saveRemoteInstance(
InputInterface $input,
OutputInterface $output,
RemoteInstance $remoteInstance
): void {
$output->writeln('');
$output->writeln(
'Using remote instance to store local backups: ' . ($remoteInstance->isOutgoing(
) ? '<info>yes</info>' : '<comment>no</comment>')
);
$output->writeln(
'Locally storing backups from remote instance: ' . ($remoteInstance->isIncoming(
) ? '<info>yes</info>' : '<comment>no</comment>')
);
$helper = $this->getHelper('question');
$question = new ConfirmationQuestion(
'Please confirm those settings <info>(y/N)</info> ',
false,
'/^(y|Y)/i'
);
if (!$helper->ask($input, $output, $question)) {
return;
}
$this->remoteRequest->insertOrUpdate($remoteInstance);
}
}

76
lib/Command/RemoteList.php Executable file
Просмотреть файл

@ -0,0 +1,76 @@
<?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 2021, 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 Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class RemoteList
*
* @package OCA\Backup\Command
*/
class RemoteList extends Base {
public function __construct() {
parent::__construct();
}
/**
*
*/
protected function configure() {
$this->setName('backup:remote:list')
->setDescription('Listing configured remote instances');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
return 0;
}
}

Просмотреть файл

@ -1,67 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2017 Frank Karlitschek <frank@karlitschek.de>
*
* @author Frank Karlitschek <frank@karlitchek.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\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IRequest;
class APIController extends OCSController {
/**
* @param string $appName
* @param IRequest $request
*/
public function __construct($appName, IRequest $request) {
parent::__construct($appName, $request);
}
/**
* @param string $path
* @param string $password
* @return DataResponse
*/
public function createBackup($path, $password) {
$backup = new \OCA\Backup\Backup\Create($path);
$backup -> password($password);
$backup -> create();
return new DataResponse();
}
/**
* @param string $path
* @param string $password
* @return DataResponse
*/
public function restoreBackup($path, $password) {
$backup = new \OCA\Backup\Backup\Restore($path);
$backup -> password($password);
$backup -> restore();
return new DataResponse();
}
}

Просмотреть файл

@ -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 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\Controller;
use ArtificialOwl\MySmallPhpTools\Exceptions\JsonNotRequestedException;
use ArtificialOwl\MySmallPhpTools\Exceptions\SignatoryException;
use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Controller;
use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException;
use OCA\Backup\Service\RemoteStreamService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
/**
* Class RemoteController
*
* @package OCA\Backup\Controller
*/
class RemoteController extends Controller {
use TNC22Controller;
/** @var RemoteStreamService */
private $remoteStreamService;
/**
* RemoteController constructor.
*
* @param string $appName
* @param IRequest $request
* @param RemoteStreamService $remoteStreamService
*/
public function __construct(
string $appName,
IRequest $request,
RemoteStreamService $remoteStreamService
) {
parent::__construct($appName, $request);
$this->remoteStreamService = $remoteStreamService;
}
/**
* @PublicPage
* @NoCSRFRequired
*
* @return DataResponse
* @throws NotLoggedInException
* @throws SignatoryException
*/
public function appService(): DataResponse {
try {
$this->publicPageJsonLimited();
} catch (JsonNotRequestedException $e) {
return new DataResponse();
}
$signatory = $this->remoteStreamService->getAppSignatory(false, $this->request->getParam('auth', ''));
return new DataResponse($signatory);
}
}

Просмотреть файл

@ -72,7 +72,7 @@ class BackupsRequest extends BackupsRequestBuilder {
*/
public function update(Backup $backup) {
$qb = $this->getBackupsUpdateSql();
$this->limitToId($qb, $backup->getId());
$qb->limitToId($backup->getId());
$qb->execute();
}

Просмотреть файл

@ -31,8 +31,10 @@ declare(strict_types=1);
namespace OCA\Backup\Db;
use daita\MySmallPhpTools\Traits\TArrayTools;
use OCA\Backup\Model\Backup;
use ArtificialOwl\MySmallPhpTools\Exceptions\RowNotFoundException;
use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
use OCA\Backup\Exceptions\RestoringPointNotFoundException;
use OCA\Backup\Model\RestoringPoint;
use OCP\DB\QueryBuilder\IQueryBuilder;
/**
@ -49,11 +51,11 @@ class BackupsRequestBuilder extends CoreRequestBuilder {
/**
* Base of the Sql Insert request
*
* @return IQueryBuilder
* @return CoreQueryBuilder
*/
protected function getBackupsInsertSql(): IQueryBuilder {
$qb = $this->dbConnection->getQueryBuilder();
$qb->insert(self::SQL_TABLES['BACKUPS']);
protected function getBackupsInsertSql(): CoreQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->select(self::TABLE_RESTORING_POINT);
return $qb;
}
@ -64,9 +66,9 @@ class BackupsRequestBuilder extends CoreRequestBuilder {
*
* @return IQueryBuilder
*/
protected function getBackupsUpdateSql(): IQueryBuilder {
$qb = $this->dbConnection->getQueryBuilder();
$qb->update(self::SQL_TABLES['BACKUPS']);
protected function getBackupsUpdateSql(): CoreQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->update(self::TABLE_RESTORING_POINT);
return $qb;
}
@ -75,19 +77,15 @@ class BackupsRequestBuilder extends CoreRequestBuilder {
/**
* Base of the Sql Select request for Shares
*
* @return IQueryBuilder
* @return CoreQueryBuilder
*/
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';
protected function getBackupsSelectSql(): CoreQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(
self::TABLE_RESTORING_POINT,
self::$tables[self::TABLE_RESTORING_POINT],
'b'
);
return $qb;
}
@ -99,23 +97,38 @@ class BackupsRequestBuilder extends CoreRequestBuilder {
* @return IQueryBuilder
*/
protected function getBackupsDeleteSql(): IQueryBuilder {
$qb = $this->dbConnection->getQueryBuilder();
$qb->delete(self::SQL_TABLES['BACKUPS']);
$qb = $this->getQueryBuilder();
$qb->delete(self::TABLE_RESTORING_POINT);
return $qb;
}
/**
* @param array $data
* @param CoreQueryBuilder $qb
*
* @return Backup
* @return RestoringPoint
* @throws RestoringPointNotFoundException
*/
protected function parseBackupsSelectSql($data): Backup {
$backup = new Backup();
$backup->importFromDatabase($data);
public function getItemFromRequest(CoreQueryBuilder $qb): RestoringPoint {
/** @var RestoringPoint $restoringPoint */
try {
$restoringPoint = $qb->asItem(RestoringPoint::class);
} catch (RowNotFoundException $e) {
throw new RestoringPointNotFoundException();
}
return $backup;
return $restoringPoint;
}
/**
* @param CoreQueryBuilder $qb
*
* @return RestoringPoint[]
*/
public function getItemsFromRequest(CoreQueryBuilder $qb): array {
/** @var RestoringPoint[] $result */
return $qb->asItems(RestoringPoint::class);
}
}

Просмотреть файл

@ -0,0 +1,70 @@
<?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 2021
* @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 ArtificialOwl\MySmallPhpTools\Db\Nextcloud\nc22\NC22ExtendedQueryBuilder;
/**
* Class CoreQueryBuilder
*
* @package OCA\Backup\Db
*/
class CoreQueryBuilder extends NC22ExtendedQueryBuilder {
/**
* CoreQueryBuilder constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Limit the request to the Id
*
* @param int $id
*/
public function limitToId(int $id): void {
$this->limitInt('id', $id);
}
/**
* @param string $host
*/
public function limitToInstance(string $host): void {
$this->limit('instance', $host, '', false);
}
}

Просмотреть файл

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
@ -9,7 +10,7 @@ declare(strict_types=1);
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2019, Maxence Lange <maxence@artificial-owl.com>
* @copyright 2021
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
@ -30,11 +31,10 @@ declare(strict_types=1);
namespace OCA\Backup\Db;
use daita\MySmallPhpTools\Db\RequestBuilder;
use OCA\Backup\Service\MiscService;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use Exception;
use OC\DB\Connection;
use OC\DB\SchemaWrapper;
use OCA\Backup\Service\ConfigService;
/**
@ -42,68 +42,117 @@ use OCP\IDBConnection;
*
* @package OCA\Backup\Db
*/
class CoreRequestBuilder extends RequestBuilder {
class CoreRequestBuilder {
const SQL_TABLES = [
'BACKUPS' => 'backups'
public const TABLE_RESTORING_POINT = 'backup_point';
public const TABLE_REMOTE = 'backup_remote';
/** @var array */
public static $tables = [
self::TABLE_REMOTE => [
'id',
'uid',
'instance',
'href',
'exchange',
'item'
],
self::TABLE_RESTORING_POINT => [
'id',
'user_id',
'preferred_username',
'name',
'summary',
'sa.public_key',
'avatar_version',
'private_key',
'creation'
]
];
/** @var IDBConnection */
protected $dbConnection;
/** @var MiscService */
protected $miscService;
/** @var string */
protected $defaultSelectAlias;
/** @var ConfigService */
protected $configService;
/**
* CoreRequestBuilder constructor.
* CoreQueryBuilder constructor.
*
* @param IDBConnection $connection
* @param MiscService $miscService
* @param ConfigService $configService
*/
public function __construct(IDBConnection $connection, MiscService $miscService) {
$this->dbConnection = $connection;
$this->miscService = $miscService;
public function __construct(ConfigService $configService) {
$this->configService = $configService;
}
/**
* Limit the request to the Id
*
* @param IQueryBuilder $qb
* @param int $id
* @return CoreQueryBuilder
*/
protected function limitToId(IQueryBuilder &$qb, int $id) {
$this->limitToDBFieldInt($qb, 'id', $id);
public function getQueryBuilder(): CoreQueryBuilder {
return new CoreQueryBuilder();
}
/**
* Limit the request to the status
*
* @param IQueryBuilder $qb
* @param int $status
* @param bool $shares
*/
protected function limitToStatus(IQueryBuilder &$qb, int $status) {
$this->limitToDBFieldInt($qb, 'status', $status);
public function cleanDatabase(bool $shares = false): void {
foreach (array_keys(self::$tables) as $table) {
$qb = $this->getQueryBuilder();
try {
$qb->delete($table);
$qb->execute();
} catch (Exception $e) {
}
}
}
public function uninstall(): void {
$this->uninstallAppTables();
$this->uninstallFromMigrations();
$this->uninstallFromJobs();
$this->configService->unsetAppConfig();
}
/**
* this just empty all tables from the app.
*/
public function uninstallAppTables() {
$dbConn = \OC::$server->get(Connection::class);
$schema = new SchemaWrapper($dbConn);
foreach (array_keys(self::$tables) as $table) {
if ($schema->hasTable($table)) {
$schema->dropTable($table);
}
}
$schema->performDropTableCalls();
}
/**
* 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');
public function uninstallFromMigrations() {
$qb = $this->getQueryBuilder();
$qb->delete('migrations');
$qb->limit('app', 'backup');
$qb->unlike('version', '001%');
$qb->execute();
}
/**
*
*/
public function uninstallFromJobs() {
$qb = $this->getQueryBuilder();
// $qb->delete('jobs');
// $qb->where($this->exprLimitToDBField($qb, 'class', 'OCA\Backup\', true, true));
// $qb->execute();
}
}

142
lib/Db/RemoteRequest.php Normal file
Просмотреть файл

@ -0,0 +1,142 @@
<?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\Exceptions\RemoteInstanceNotFoundException;
use OCA\Backup\Exceptions\RemoteInstanceUidException;
use OCA\Backup\Model\RemoteInstance;
/**
* Class RemoteRequest
*
* @package OCA\Backup\Db
*/
class RemoteRequest extends RemoteRequestBuilder {
/**
* create a new Person in the database.
*
* @param RemoteInstance $remote
*
* @return int
* @throws RemoteInstanceUidException
*/
public function save(RemoteInstance $remote): int {
$remote->mustBeIdentityAuthed();
$qb = $this->getRemoteInsertSql();
$qb->setValue('uid', $qb->createNamedParameter($remote->getUid(true)))
->setValue('instance', $qb->createNamedParameter($remote->getInstance()))
->setValue('href', $qb->createNamedParameter($remote->getId()))
->setValue('exchange', $qb->createNamedParameter($remote->getExchange()))
->setValue('item', $qb->createNamedParameter(json_encode($remote->getOrigData())));
return $qb->execute();
}
/**
* @param RemoteInstance $remote
*
* @throws RemoteInstanceUidException
*/
public function update(RemoteInstance $remote) {
$remote->mustBeIdentityAuthed();
$qb = $this->getRemoteUpdateSql();
$qb->set('uid', $qb->createNamedParameter($remote->getUid(true)))
->set('href', $qb->createNamedParameter($remote->getId()))
->set('exchange', $qb->createNamedParameter($remote->getExchange()))
->set('item', $qb->createNamedParameter(json_encode($remote->getOrigData())));
$qb->limitToInstance($remote->getInstance());
$qb->execute();
}
/**
* @param int $dbId
*
* @return RemoteInstance
* @throws RemoteInstanceNotFoundException
*/
public function getFromDbId(int $dbId): RemoteInstance {
$qb = $this->getRemoteSelectSql();
$qb->limitToId($dbId);
return $this->getItemFromRequest($qb);
}
/**
* @throws RemoteInstanceNotFoundException
*/
public function getFromInstance(string $instance): RemoteInstance {
$qb = $this->getRemoteSelectSql();
$qb->limit('instance', $instance, '', false);
return $this->getItemFromRequest($qb);
}
/**
* @param string $href
*
* @return RemoteInstance
* @throws RemoteInstanceNotFoundException
*/
public function getFromHref(string $href): RemoteInstance {
$qb = $this->getRemoteSelectSql();
$qb->limit('href', $href, '', false);
return $this->getItemFromRequest($qb);
}
/**
* @param RemoteInstance $remoteInstance
*
* @throws RemoteInstanceUidException
*/
public function insertOrUpdate(RemoteInstance $remoteInstance): void {
try {
$this->getFromHref($remoteInstance->getId());
$this->update($remoteInstance);
} catch (RemoteInstanceNotFoundException $e) {
$this->save($remoteInstance);
}
}
}

Просмотреть файл

@ -0,0 +1,129 @@
<?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 ArtificialOwl\MySmallPhpTools\Exceptions\RowNotFoundException;
use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
use OCA\Backup\Exceptions\RemoteInstanceNotFoundException;
use OCA\Backup\Model\RemoteInstance;
use OCP\DB\QueryBuilder\IQueryBuilder;
/**
* Class RemoteRequestBuilder
*
* @package OCA\Backup\Db
*/
class RemoteRequestBuilder extends CoreRequestBuilder {
use TArrayTools;
/**
* @return CoreQueryBuilder
*/
protected function getRemoteInsertSql(): CoreQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->insert(self::TABLE_REMOTE);
return $qb;
}
/**
* @return CoreQueryBuilder
*/
protected function getRemoteUpdateSql(): CoreQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->update(self::TABLE_REMOTE);
return $qb;
}
/**
* @return CoreQueryBuilder
*/
protected function getRemoteSelectSql(): CoreQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(
self::TABLE_REMOTE,
self::$tables[self::TABLE_REMOTE],
'remote'
);
return $qb;
}
/**
* @return IQueryBuilder
*/
protected function getRemoteDeleteSql(): IQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->delete(self::TABLE_REMOTE);
return $qb;
}
/**
* @param CoreQueryBuilder $qb
*
* @return RemoteInstance
* @throws RemoteInstanceNotFoundException
*/
public function getItemFromRequest(CoreQueryBuilder $qb): RemoteInstance {
/** @var RemoteInstance $remote */
try {
$remote = $qb->asItem(RemoteInstance::class);
} catch (RowNotFoundException $e) {
throw new RemoteInstanceNotFoundException();
}
return $remote;
}
/**
* @param CoreQueryBuilder $qb
*
* @return RemoteInstance[]
*/
public function getItemsFromRequest(CoreQueryBuilder $qb): array {
/** @var RemoteInstance[] $result */
return $qb->asItems(RemoteInstance::class);
}
}

Просмотреть файл

@ -0,0 +1,46 @@
<?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 2021, 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;
use Exception;
/**
* Class RemoteInstanceDuplicateException
*
* @package OCA\Backup\Exceptions
*/
class RemoteInstanceDuplicateException extends Exception {
}

Просмотреть файл

@ -0,0 +1,46 @@
<?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 2021, 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;
use Exception;
/**
* Class RemoteInstanceNotFoundException
*
* @package OCA\Backup\Exceptions
*/
class RemoteInstanceNotFoundException extends Exception {
}

Просмотреть файл

@ -0,0 +1,46 @@
<?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 2021, 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;
use Exception;
/**
* Class RemoteInstanceUidException
*
* @package OCA\Backup\Exceptions
*/
class RemoteInstanceUidException extends Exception {
}

Просмотреть файл

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
@ -28,12 +29,18 @@ declare(strict_types=1);
*/
namespace OCA\Backup\AppInfo;
namespace OCA\Backup\Exceptions;
$composerDir = __DIR__ . '/../vendor/';
use Exception;
/**
* Class RestoringPointNotFoundException
*
* @package OCA\Backup\Exceptions
*/
class RestoringPointNotFoundException extends Exception {
if (is_dir($composerDir) && file_exists($composerDir . 'autoload.php')) {
require_once $composerDir . 'autoload.php';
}

Просмотреть файл

@ -0,0 +1,127 @@
<?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\Handlers;
use ArtificialOwl\MySmallPhpTools\Exceptions\SignatoryException;
use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
use OC\URLGenerator;
use OCA\Backup\AppInfo\Application;
use OCA\Backup\Service\ConfigService;
use OCA\Backup\Service\RemoteStreamService;
use OCP\Http\WellKnown\IHandler;
use OCP\Http\WellKnown\IRequestContext;
use OCP\Http\WellKnown\IResponse;
use OCP\Http\WellKnown\JrdResponse;
use OCP\IURLGenerator;
/**
* Class WebfingerHandler
*
* @package OCA\Circles\Handlers
*/
class WebfingerHandler implements IHandler {
use TArrayTools;
/** @var URLGenerator */
private $urlGenerator;
/** @var RemoteStreamService */
private $remoteStreamService;
/** @var ConfigService */
private $configService;
/**
* WebfingerHandler constructor.
*
* @param IURLGenerator $urlGenerator
* @param RemoteStreamService $remoteStreamService
* @param ConfigService $configService
*/
public function __construct(
IURLGenerator $urlGenerator,
RemoteStreamService $remoteStreamService,
ConfigService $configService
) {
$this->urlGenerator = $urlGenerator;
$this->remoteStreamService = $remoteStreamService;
$this->configService = $configService;
}
/**
* @param string $service
* @param IRequestContext $context
* @param IResponse|null $response
*
* @return IResponse|null
*/
public function handle(string $service, IRequestContext $context, ?IResponse $response): ?IResponse {
if ($service !== 'webfinger') {
return $response;
}
$request = $context->getHttpRequest();
$subject = $request->getParam('resource', '');
if ($subject !== Application::APP_SUBJECT) {
return $response;
}
$token = $request->getParam('check', '');
if (!($response instanceof JrdResponse)) {
$response = new JrdResponse($subject);
}
try {
$this->remoteStreamService->getAppSignatory();
$href = $this->urlGenerator->linkToRouteAbsolute('backup.Remote.appService');
$info = [
'app' => Application::APP_ID,
'name' => Application::APP_NAME,
'version' => $this->configService->getAppValue('installed_version')
];
} catch (SignatoryException $e) {
return $response;
}
return $response->addLink(Application::APP_REL, 'application/json', $href, [], $info);
}
}

Просмотреть файл

@ -0,0 +1,64 @@
<?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 2021, 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\Listeners;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeWrittenEvent;
use OCP\Files\InvalidPathException;
use OCP\Files\NotFoundException;
/**
* Class FileChanged
*
* @package OCA\Backup\Listeners
*/
class FileChanged implements IEventListener {
/**
* @param Event $event
*/
public function handle(Event $event): void {
if (!($event instanceof NodeWrittenEvent)) {
return;
}
try {
$node = $event->getNode();
} catch (InvalidPathException | NotFoundException $e) {
}
}
}

Просмотреть файл

@ -0,0 +1,69 @@
<?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 2021, 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\Listeners;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeCreatedEvent;
/**
* Class FileCreated
*
* @package OCA\Backup\Listeners
*/
class FileCreated implements IEventListener {
/**
* @param Event $event
*/
public function handle(Event $event): void {
if (!($event instanceof NodeCreatedEvent)) {
return;
}
// $node = $event->getNode();
// $user = $this->userSession->getUser();
// if ($user === null) {
// return;
// }
//
// try {
// } catch (InvalidPathException | NotFoundException $e) {
// $this->exception($e);
// }
}
}

Просмотреть файл

@ -0,0 +1,64 @@
<?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 2021, 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\Listeners;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeDeletedEvent;
use OCP\Files\InvalidPathException;
use OCP\Files\NotFoundException;
/**
* Class FileDeleted
*
* @package OCA\Backup\Listeners
*/
class FileDeleted implements IEventListener {
/**
* @param Event $event
*/
public function handle(Event $event): void {
if (!($event instanceof NodeDeletedEvent)) {
return;
}
try {
$node = $event->getNode();
} catch (InvalidPathException | NotFoundException $e) {
}
}
}

Просмотреть файл

@ -0,0 +1,64 @@
<?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 2021, 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\Listeners;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeRenamedEvent;
use OCP\Files\InvalidPathException;
use OCP\Files\NotFoundException;
/**
* Class FileRenamed
*
* @package OCA\Backup\Listeners
*/
class FileRenamed implements IEventListener {
/**
* @param Event $event
*/
public function handle(Event $event): void {
if (!($event instanceof NodeRenamedEvent)) {
return;
}
try {
$node = $event->getTarget();
} catch (InvalidPathException | NotFoundException $e) {
}
}
}

Просмотреть файл

@ -0,0 +1,125 @@
<?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 2021
* @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\Migration;
use Closure;
use Doctrine\DBAL\Schema\SchemaException;
use OCP\DB\ISchemaWrapper;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
/**
* Class Version0023Date20210907122531
*
* @package OCA\Backup\Migration
*/
class Version0023Date20210907122531 extends SimpleMigrationStep {
/**
* @param IDBConnection $connection
*/
public function __construct(IDBConnection $connection) {
}
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*
* @return null|ISchemaWrapper
* @throws SchemaException
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
/**
* BACKUP_REMOTE
*/
if (!$schema->hasTable('backup_remote')) {
$table = $schema->createTable('backup_remote');
$table->addColumn(
'id', 'integer', [
'autoincrement' => true,
'notnull' => true,
'length' => 4,
'unsigned' => true,
]
);
$table->addColumn(
'uid', 'string', [
'notnull' => false,
'length' => 20,
]
);
$table->addColumn(
'instance', 'string', [
'notnull' => false,
'length' => 127,
]
);
$table->addColumn(
'exchange', 'integer', [
'notnull' => true,
'length' => 1,
'unsigned' => true,
]
);
$table->addColumn(
'href', 'string', [
'notnull' => false,
'length' => 254,
]
);
$table->addColumn(
'item', 'text', [
'notnull' => false,
]
);
$table->addColumn(
'creation', 'datetime', [
'notnull' => false,
]
);
$table->setPrimaryKey(['id']);
$table->addUniqueIndex(['instance']);
$table->addIndex(['uid']);
$table->addIndex(['href']);
}
return $schema;
}
}

Просмотреть файл

@ -0,0 +1,349 @@
<?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 2021, 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 ArtificialOwl\MySmallPhpTools\Db\Nextcloud\nc22\INC22QueryRow;
use ArtificialOwl\MySmallPhpTools\Model\Nextcloud\nc23\NC23Signatory;
use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
use JsonSerializable;
use OCA\Backup\Exceptions\RemoteInstanceNotFoundException;
use OCA\Backup\Exceptions\RemoteInstanceUidException;
/**
* Class AppService
*
* @package OCA\Circles\Model
*/
class RemoteInstance extends NC23Signatory implements INC22QueryRow, JsonSerializable {
use TArrayTools;
const EXCHANGE_IN = 1;
const EXCHANGE_OUT = 2;
const TEST = 'test';
/** @var int */
private $dbId = 0;
/** @var string */
private $root = '';
/** @var int */
private $exchange = 0;
/** @var string */
private $test = '';
/** @var string */
private $uid = '';
/** @var string */
private $authSigned = '';
/** @var bool */
private $identityAuthed = false;
/**
* @param int $dbId
*
* @return self
*/
public function setDbId(int $dbId): self {
$this->dbId = $dbId;
return $this;
}
/**
* @return int
*/
public function getDbId(): int {
return $this->dbId;
}
/**
* @return string
*/
public function getRoot(): string {
return $this->root;
}
/**
* @param string $root
*
* @return $this
*/
public function setRoot(string $root): self {
$this->root = $root;
return $this;
}
/**
* @param int $exchange
*
* @return $this
*/
public function setExchange(int $exchange): self {
$this->exchange = $exchange;
return $this;
}
/**
* @return int
*/
public function getExchange(): int {
return $this->exchange;
}
/**
* @param bool $incoming
*
* @return $this
*/
public function setIncoming(bool $incoming = false): self {
$this->exchange |= self::EXCHANGE_IN;
if (!$incoming) {
$this->exchange -= self::EXCHANGE_IN;
}
return $this;
}
/**
* @return bool
*/
public function isIncoming(): bool {
return (($this->getExchange() & self::EXCHANGE_IN) !== 0);
}
/**
* @param bool $outgoing
*
* @return $this
*/
public function setOutgoing(bool $outgoing = false): self {
$this->exchange |= self::EXCHANGE_OUT;
if (!$outgoing) {
$this->exchange -= self::EXCHANGE_OUT;
}
return $this;
}
/**
* @return bool
*/
public function isOutgoing(): bool {
return (($this->getExchange() & self::EXCHANGE_OUT) !== 0);
}
/**
* @param string $test
*
* @return RemoteInstance
*/
public function setTest(string $test): self {
$this->test = $test;
return $this;
}
/**
* @return string
*/
public function getTest(): string {
return $this->test;
}
/**
* @return $this
*/
public function setUidFromKey(): self {
$this->setUid(hash('sha512', $this->getPublicKey()));
return $this;
}
/**
* @param string $uid
*
* @return RemoteInstance
*/
public function setUid(string $uid): self {
$this->uid = $uid;
return $this;
}
/**
* @param bool $shorten
*
* @return string
*/
public function getUid(bool $shorten = false): string {
if ($shorten) {
return substr($this->uid, 0, 18);
}
return $this->uid;
}
/**
* @param string $authSigned
*
* @return RemoteInstance
*/
public function setAuthSigned(string $authSigned): self {
$this->authSigned = $authSigned;
return $this;
}
/**
* @return string
*/
public function getAuthSigned(): string {
return $this->authSigned;
}
/**
* @param bool $identityAuthed
*
* @return RemoteInstance
*/
public function setIdentityAuthed(bool $identityAuthed): self {
$this->identityAuthed = $identityAuthed;
return $this;
}
/**
* @return bool
*/
public function isIdentityAuthed(): bool {
return $this->identityAuthed;
}
/**
* @throws RemoteInstanceUidException
*/
public function mustBeIdentityAuthed(): void {
if (!$this->isIdentityAuthed()) {
throw new RemoteInstanceUidException('identity not authed');
}
}
/**
* @param array $data
*
* @return NC23Signatory
*/
public function import(array $data): NC23Signatory {
parent::import($data);
$this->setTest($this->get('test', $data))
->setRoot($this->get('root', $data))
->setUid($this->get('uid', $data));
$algo = '';
$authSigned = trim($this->get('auth-signed', $data), ':');
if (strpos($authSigned, ':') > 0) {
list($algo, $authSigned) = explode(':', $authSigned);
}
$this->setAuthSigned($authSigned)
->setAlgorithm($algo);
return $this;
}
/**
* @return array
*/
public function jsonSerialize(): array {
$data = [
'uid' => $this->getUid(true),
'root' => $this->getRoot(),
'test' => $this->getTest()
];
if ($this->getAuthSigned() !== '') {
$data['auth-signed'] = $this->getAlgorithm() . ':' . $this->getAuthSigned();
}
return array_filter(array_merge($data, parent::jsonSerialize()));
}
/**
* @param array $data
*
* @return self
* @throws RemoteInstanceNotFoundException
*/
public function importFromDatabase(array $data): INC22QueryRow {
if ($this->getInt('id', $data) === 0) {
throw new RemoteInstanceNotFoundException();
}
$this->setDbId($this->getInt('id', $data));
$this->import($this->getArray('item', $data));
$this->setExchange($this->getInt('exchange', $data));
$this->setOrigData($this->getArray('item', $data));
$this->setInstance($this->get('instance', $data));
$this->setId($this->get('href', $data));
return $this;
}
}

Просмотреть файл

@ -0,0 +1,68 @@
<?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 ArtificialOwl\MySmallPhpTools\Db\Nextcloud\nc23\INC23QueryRow;
use ArtificialOwl\MySmallPhpTools\IDeserializable;
use JsonSerializable;
/**
* Class RestoringPoint
*
* @package OCA\Backup\Model
*/
class RestoringPoint implements IDeserializable, INC23QueryRow, JsonSerializable {
/**
* @return array
*/
public function jsonSerialize(): array {
return
[
];
}
public function importFromDatabase(array $data): INC23QueryRow {
return $this;
}
public function import(array $data): IDeserializable {
return $this;
}
}

Просмотреть файл

@ -1,5 +1,5 @@
<?php
/** @noinspection PhpUndefinedClassInspection */
declare(strict_types=1);
@ -32,8 +32,8 @@ declare(strict_types=1);
namespace OCA\Backup\Service;
use daita\MySmallPhpTools\Traits\TArrayTools;
use daita\MySmallPhpTools\Traits\TPathTools;
use ArtificialOwl\MySmallPhpTools\Model\Nextcloud\nc23\NC23Request;
use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
use OCA\Backup\AppInfo\Application;
use OCP\IConfig;
@ -41,29 +41,28 @@ use OCP\IConfig;
class ConfigService {
use TPathTools;
use TArrayTools;
const SELF_SIGNED_CERT = 'self_signed_cert';
/** @var array */
public $defaults = [];
public $defaults = [
self::SELF_SIGNED_CERT => '0'
];
/** @var IConfig */
private $config;
/** @var MiscService */
private $miscService;
/**
* ConfigService constructor.
*
* @param IConfig $config
* @param MiscService $miscService
*/
public function __construct(IConfig $config, MiscService $miscService) {
public function __construct(IConfig $config) {
$this->config = $config;
$this->miscService = $miscService;
}
@ -74,31 +73,37 @@ class ConfigService {
*
* @return string
*/
public function getAppValue($key) {
$defaultValue = null;
if (array_key_exists($key, $this->defaults)) {
$defaultValue = $this->defaults[$key];
public function getAppValue(string $key): string {
if (($value = $this->config->getAppValue(Application::APP_ID, $key, '')) !== '') {
return $value;
}
return $this->config->getAppValue(Application::APP_ID, $key, $defaultValue);
if (($value = $this->config->getSystemValue(Application::APP_ID . '.' . $key, '')) !== '') {
return $value;
}
return $this->get($key, $this->defaults);
}
/**
* 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);
return (int)$this->getAppValue($key);
}
/**
* @param string $key
*
* @return bool
*/
public function getAppValueBool(string $key): bool {
return ($this->getAppValueInt($key) === 1);
}
/**
* Set a value by key
*
@ -107,19 +112,41 @@ class ConfigService {
*
* @return void
*/
public function setAppValue($key, $value) {
public function setAppValue(string $key, string $value): void {
$this->config->setAppValue(Application::APP_ID, $key, $value);
}
/**
*
*/
public function unsetAppConfig(): void {
$this->config->deleteAppValues(Application::APP_ID);
}
/**
* @param $key
*
* @return mixed
* @return string
*/
public function getSystemValue($key) {
public function getSystemValue($key): string {
return $this->config->getSystemValue($key, '');
}
/**
* @param NC23Request $request
*/
public function configureRequest(NC23Request $request): void {
$request->setVerifyPeer($this->getAppValue(self::SELF_SIGNED_CERT) !== '1');
$request->setProtocols(['https', 'http']);
$request->setHttpErrorsAllowed(true);
$request->setLocalAddressAllowed(true);
$request->setFollowLocation(true);
$request->setTimeout(5);
}
}

Просмотреть файл

@ -0,0 +1,218 @@
<?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 ArtificialOwl\MySmallPhpTools\ActivityPub\Nextcloud\nc23\NC23Signature;
use ArtificialOwl\MySmallPhpTools\Exceptions\RequestNetworkException;
use ArtificialOwl\MySmallPhpTools\Exceptions\SignatoryException;
use ArtificialOwl\MySmallPhpTools\Exceptions\SignatureException;
use ArtificialOwl\MySmallPhpTools\Exceptions\WellKnownLinkNotFoundException;
use ArtificialOwl\MySmallPhpTools\Model\Nextcloud\nc23\NC23Request;
use ArtificialOwl\MySmallPhpTools\Model\Nextcloud\nc23\NC23Signatory;
use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc23\TNC23Deserialize;
use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc23\TNC23LocalSignatory;
use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc23\TNC23WellKnown;
use ArtificialOwl\MySmallPhpTools\Traits\TStringTools;
use OCA\Backup\AppInfo\Application;
use OCA\Backup\Db\RemoteRequest;
use OCA\Backup\Exceptions\RemoteInstanceNotFoundException;
use OCA\Backup\Model\RemoteInstance;
use OCP\IURLGenerator;
/**
* Class RemoteStreamService
*
* @package OCA\Backup\Service
*/
class RemoteStreamService extends NC23Signature {
use TNC23Deserialize;
use TNC23LocalSignatory;
use TStringTools;
use TNC23WellKnown;
/** @var IURLGenerator */
private $urlGenerator;
/** @var RemoteRequest */
private $remoteRequest;
/** @var ConfigService */
private $configService;
/**
* RemoteStreamService constructor.
*
* @param IURLGenerator $urlGenerator
* @param ConfigService $configService
*/
public function __construct(
IURLGenerator $urlGenerator,
RemoteRequest $remoteRequest,
ConfigService $configService
) {
$this->urlGenerator = $urlGenerator;
$this->remoteRequest = $remoteRequest;
$this->configService = $configService;
$this->setup('app', 'backup');
}
/**
* Returns the Signatory model for the Backup app.
* Can be signed with a confirmKey.
*
* @param bool $generate
* @param string $confirmKey
*
* @return RemoteInstance
* @throws SignatoryException
*/
public function getAppSignatory(bool $generate = true, string $confirmKey = ''): RemoteInstance {
$app = new RemoteInstance($this->urlGenerator->linkToRouteAbsolute('backup.Remote.appService'));
$this->fillSimpleSignatory($app, $generate);
$app->setUidFromKey();
if ($confirmKey !== '') {
$app->setAuthSigned($this->signString($confirmKey, $app));
}
$app->setRoot($this->urlGenerator->linkToRouteAbsolute('backup.Remote.test'));
$app->setTest($this->urlGenerator->linkToRouteAbsolute('backup.Remote.test'));
$app->setOrigData($this->serialize($app));
return $app;
}
/**
* Reset the Signatory (and the Identity) for the Circles app.
*/
public function resetAppSignatory(): void {
try {
$app = $this->getAppSignatory();
$this->removeSimpleSignatory($app);
} catch (SignatoryException $e) {
}
}
/**
* Add a remote instance, based on the address
*
* @param string $instance
*
* @return RemoteInstance
* @throws RequestNetworkException
* @throws SignatoryException
* @throws WellKnownLinkNotFoundException
*/
public function retrieveRemoteInstance(string $instance): RemoteInstance {
$resource = $this->getResourceData($instance, Application::APP_SUBJECT, Application::APP_REL);
/** @var RemoteInstance $remoteInstance */
$remoteInstance = $this->retrieveSignatory($resource->g('id'), true);
$remoteInstance->setInstance($instance);
return $remoteInstance;
}
/**
* retrieve Signatory.
*
* @param string $keyId
* @param bool $refresh
*
* @return NC23Signatory
* @throws SignatoryException
* @throws SignatureException
*/
public function retrieveSignatory(string $keyId, bool $refresh = true): NC23Signatory {
if (!$refresh) {
try {
return $this->remoteRequest->getFromHref(NC23Signatory::removeFragment($keyId));
} catch (RemoteInstanceNotFoundException $e) {
throw new SignatoryException();
}
}
$remoteInstance = new RemoteInstance($keyId);
$confirm = $this->uuid();
$request = new NC23Request();
$this->configService->configureRequest($request);
$this->downloadSignatory($remoteInstance, $keyId, ['auth' => $confirm], $request);
$remoteInstance->setUidFromKey();
$this->confirmAuth($remoteInstance, $confirm);
return $remoteInstance;
}
/**
* Confirm the Auth of a RemoteInstance, based on the result from a request
*
* @param RemoteInstance $remote
* @param string $auth
*
* @throws SignatureException
*/
private function confirmAuth(RemoteInstance $remote, string $auth): void {
[$algo, $signed] = explode(':', $this->get('auth-signed', $remote->getOrigData()));
try {
if ($signed === null) {
throw new SignatureException('invalid auth-signed');
}
$this->verifyString($auth, base64_decode($signed), $remote->getPublicKey(), $algo);
$remote->setIdentityAuthed(true);
} catch (SignatureException $e) {
$this->e(
$e,
['auth' => $auth, 'signed' => $signed, 'signatory' => $remote, 'msg' => 'auth not confirmed']
);
throw new SignatureException('auth not confirmed');
}
}
}

Просмотреть файл

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);