and again more work on backup-storages

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann
2023-09-05 11:03:39 +02:00
parent 9d2077ddee
commit 4fcf0606c7
13 changed files with 429 additions and 36 deletions

View File

@@ -35,6 +35,9 @@ use Froxlor\Settings;
use Froxlor\UI\Response;
use Froxlor\Validate\Validate;
use PDO;
use phpseclib3\Crypt\Common\PublicKey;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Exception\NoKeyLoadedException;
/**
* @since 2.1.0
@@ -73,7 +76,7 @@ class BackupStorages extends ApiCommand implements ResourceEntity
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list backup storages");
$query_fields = [];
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "` ". $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit()
SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit()
);
Database::pexecute($result_stmt, $query_fields, true, true);
$result = [];
@@ -133,7 +136,7 @@ class BackupStorages extends ApiCommand implements ResourceEntity
* @param string $pgp_public_key
* optional, pgp public key for backup storage
* @param string $retention
* optional, retention for backup storage (default 3)
* optional, retention for backup storage (default {backup.default_retention})
*
* @access admin
* @return string json-encoded array
@@ -177,10 +180,36 @@ class BackupStorages extends ApiCommand implements ResourceEntity
$username = $this->getParam('username', $optional_flags['username']);
$password = $this->getParam('password', $optional_flags['password']);
$pgp_public_key = $this->getParam('pgp_public_key', true, null);
$retention = $this->getParam('retention', true, 3);
$retention = $this->getParam('retention', true, Settings::Get('backup.default_retention'));
// validation
$destination_path = FileDir::makeCorrectDir(Validate::validate($destination_path, 'destination_path', Validate::REGEX_DIR, '', [], true));
if ($type != 'local') {
if (!Validate::validateUrl($hostname)) {
Response::standardError('invalidhostname', '', true);
}
// check whether password is an ssh public key
$pwd_is_ssh_key = false;
try {
$key = PublicKeyLoader::loadPublicKey($password);
if ($key instanceof PublicKey) {
$pwd_is_ssh_key = true;
}
} catch (NoKeyLoadedException $e) {
/* nothing to do */
}
if (!$pwd_is_ssh_key) {
// normal password
$password = Validate::validate($password, 'password', '', '', [], true);
}
}
if ($type == 's3') {
$region = Validate::validate($region, 'region', '', '', [], true);
$bucket = Validate::validate($bucket, 'bucket', '/(?!(^xn--|.+-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/', '', [], true);
}
if ($retention <= 0) {
$retention = Settings::Get('backup.default_retention');
}
// TODO: add more validation
// pgp public key validation
@@ -303,7 +332,7 @@ class BackupStorages extends ApiCommand implements ResourceEntity
* @param string $pgp_public_key
* optional, pgp public key for backup storage
* @param string $retention
* optional, retention for backup storage (default 3)
* optional, retention for backup storage (default {backup.default_retention})
*
* @access admin
* @return string json-encoded array
@@ -342,7 +371,23 @@ class BackupStorages extends ApiCommand implements ResourceEntity
if (empty($username)) {
throw new Exception("Field 'username' cannot be empty", 406);
}
$password = Validate::validate($password, 'password', '', '', [], true);
// password change
if (!empty($password)) {
// check whether password is an ssh public key
$pwd_is_ssh_key = false;
try {
$key = PublicKeyLoader::loadPublicKey($password);
if ($key instanceof PublicKey) {
$pwd_is_ssh_key = true;
}
} catch (NoKeyLoadedException $e) {
/* nothing to do */
}
if (!$pwd_is_ssh_key) {
// normal password
$password = Validate::validate($password, 'password', '', '', [], true);
}
}
}
if ($type == 's3') {
if (empty($region)) {
@@ -355,6 +400,16 @@ class BackupStorages extends ApiCommand implements ResourceEntity
// validation
$destination_path = FileDir::makeCorrectDir(Validate::validate($destination_path, 'destination_path', Validate::REGEX_DIR, '', [], true));
if ($type != 'local' && !Validate::validateUrl($hostname)) {
Response::standardError('invalidhostname', '', true);
}
if ($type == 's3') {
$region = Validate::validate($region, 'region', '', '', [], true);
$bucket = Validate::validate($bucket, 'bucket', '/(?!(^xn--|.+-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/', '', [], true);
}
if ($retention <= 0) {
$retention = Settings::Get('backup.default_retention');
}
// TODO: add more validation
// pgp public key validation

View File

@@ -35,13 +35,16 @@ class S3 extends Storage
* @param string $filename
* @param string $tmp_source_directory
* @return string
* @throws \Exception
*/
protected function putFile(string $filename, string $tmp_source_directory): string
{
$source = FileDir::makeCorrectFile($tmp_source_directory . "/" . $filename);
$target = FileDir::makeCorrectFile($this->getDestinationDirectory() . "/" . $filename);
$this->s3_client->putObject([
'Bucket' => $this->sData['storage']['bucket'],
'Key' => $filename,
'SourceFile' => FileDir::makeCorrectFile($tmp_source_directory . '/' . $filename),
'Key' => $target,
'SourceFile' => $source,
]);
}

View File

@@ -2,15 +2,34 @@
namespace Froxlor\Backup\Storages;
use Exception;
use Froxlor\FileDir;
use phpseclib3\Net\SFTP as secSFTP;
class Sftp extends Storage
{
private secSFTP $sftp_client;
/**
* @return bool
*/
public function init(): bool
{
// TODO: Implement init() method.
$hostname = $this->sData['storage']['hostname'] ?? '';
$username = $this->sData['storage']['username'] ?? '';
$password = $this->sData['storage']['password'] ?? '';
if (!empty($hostname) && !empty($username) && !empty($password)) {
$tmp = explode(":", $hostname);
$hostname = $tmp[0];
$port = $tmp[1] ?? 22;
$this->sftp_client = new secSFTP($hostname, $port);
if ($this->sftp_client->isConnected()) {
// @todo login by either user/passwd or user/ssh-key
return true;
}
return false;
}
throw new Exception('Empty hostname for FTP backup storage');
}
/**
@@ -20,19 +39,27 @@ class Sftp extends Storage
* @param string $filename
* @param string $tmp_source_directory
* @return string
* @throws Exception
*/
protected function putFile(string $filename, string $tmp_source_directory): string
{
return "";
$source = FileDir::makeCorrectFile($tmp_source_directory . "/" . $filename);
$target = FileDir::makeCorrectFile($this->getDestinationDirectory() . "/" . $filename);
$this->sftp_client->put($target, $source, secSFTP::SOURCE_LOCAL_FILE);
}
/**
* @param string $filename
* @return bool
* @throws Exception
*/
protected function rmFile(string $filename): bool
{
// TODO: Implement removeOld() method.
$target = FileDir::makeCorrectFile($this->getDestinationDirectory() . "/" . $filename);
if ($this->sftp_client->file_exists($target)) {
return $this->sftp_client->delete($target);
}
return false;
}
/**
@@ -40,6 +67,7 @@ class Sftp extends Storage
*/
public function shutdown(): bool
{
$this->sftp_client->disconnect();
return true;
}
}