diff --git a/composer.json b/composer.json index 41119da..892adb9 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,8 @@ "license": "MIT", "require": { "php": "^8.2", - "keboola/kbc-project-backup": "^1.13", + "google/apiclient": "^2.18", + "keboola/kbc-project-backup": "dev-PST-2374-ondra", "keboola/php-component": "^10.1", "keboola/php-file-storage-utils": "^0.2.6", "microsoft/azure-storage-blob": "^1.5" diff --git a/composer.lock b/composer.lock index e70a36e..a980c0f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "47d78d9aac0d0465e861af0b379c523d", + "content-hash": "c2bc9454cad7592a8009707cd6ebcaf8", "packages": [ { "name": "aws/aws-crt-php", @@ -281,6 +281,119 @@ }, "time": "2024-05-18T18:05:11+00:00" }, + { + "name": "google/apiclient", + "version": "v2.18.2", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client.git", + "reference": "d8d201ba8a189a3cd7fb34e4da569f2ed440eee7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/d8d201ba8a189a3cd7fb34e4da569f2ed440eee7", + "reference": "d8d201ba8a189a3cd7fb34e4da569f2ed440eee7", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "^6.0", + "google/apiclient-services": "~0.350", + "google/auth": "^1.37", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.6", + "monolog/monolog": "^2.9||^3.0", + "php": "^8.0", + "phpseclib/phpseclib": "^3.0.36" + }, + "require-dev": { + "cache/filesystem-adapter": "^1.1", + "composer/composer": "^1.10.23", + "phpcompatibility/php-compatibility": "^9.2", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.8", + "symfony/css-selector": "~2.1", + "symfony/dom-crawler": "~2.1" + }, + "suggest": { + "cache/filesystem-adapter": "For caching certs and tokens (using Google\\Client::setCache)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/aliases.php" + ], + "psr-4": { + "Google\\": "src/" + }, + "classmap": [ + "src/aliases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client/issues", + "source": "https://github.com/googleapis/google-api-php-client/tree/v2.18.2" + }, + "time": "2024-12-16T22:52:40+00:00" + }, + { + "name": "google/apiclient-services", + "version": "v0.390.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client-services.git", + "reference": "2c1ff37aea15dd9e7a434c4fcbec777d9421385c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/2c1ff37aea15dd9e7a434c4fcbec777d9421385c", + "reference": "2c1ff37aea15dd9e7a434c4fcbec777d9421385c", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "Google\\Service\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client-services/issues", + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.390.0" + }, + "time": "2025-01-12T01:00:53+00:00" + }, { "name": "google/auth", "version": "v1.42.0", @@ -1216,16 +1329,16 @@ }, { "name": "keboola/kbc-project-backup", - "version": "1.13.0", + "version": "dev-PST-2374-ondra", "source": { "type": "git", "url": "https://github.com/keboola/php-kbc-project-backup.git", - "reference": "38a5214a202e3c3a7214c198a64797326cb9a8ee" + "reference": "006c52efa0089a40be57b8f02f8117d90a73d7c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/keboola/php-kbc-project-backup/zipball/38a5214a202e3c3a7214c198a64797326cb9a8ee", - "reference": "38a5214a202e3c3a7214c198a64797326cb9a8ee", + "url": "https://api.github.com/repos/keboola/php-kbc-project-backup/zipball/006c52efa0089a40be57b8f02f8117d90a73d7c8", + "reference": "006c52efa0089a40be57b8f02f8117d90a73d7c8", "shasum": "" }, "require": { @@ -1271,9 +1384,9 @@ "description": "Backup KBC project", "support": { "issues": "https://github.com/keboola/php-kbc-project-backup/issues", - "source": "https://github.com/keboola/php-kbc-project-backup/tree/1.13.0" + "source": "https://github.com/keboola/php-kbc-project-backup/tree/PST-2374-ondra" }, - "time": "2025-01-11T21:27:54+00:00" + "time": "2025-01-13T20:32:02+00:00" }, { "name": "keboola/notification-api-php-client", @@ -1947,6 +2060,233 @@ ], "time": "2022-08-04T09:53:51+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2024-05-08T12:36:18+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.43", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.43" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2024-12-14T21:12:59+00:00" + }, { "name": "psr/cache", "version": "3.0.0", @@ -3214,16 +3554,16 @@ }, { "name": "symfony/process", - "version": "v6.4.8", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5" + "reference": "3cb242f059c14ae08591c5c4087d1fe443564392" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/8d92dd79149f29e89ee0f480254db595f6a6a2c5", - "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5", + "url": "https://api.github.com/repos/symfony/process/zipball/3cb242f059c14ae08591c5c4087d1fe443564392", + "reference": "3cb242f059c14ae08591c5c4087d1fe443564392", "shasum": "" }, "require": { @@ -3255,7 +3595,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.8" + "source": "https://github.com/symfony/process/tree/v6.4.15" }, "funding": [ { @@ -3271,7 +3611,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-06T14:19:14+00:00" }, { "name": "symfony/property-access", @@ -6086,7 +6426,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "keboola/kbc-project-backup": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/Application.php b/src/Application.php index da7b076..573784e 100644 --- a/src/Application.php +++ b/src/Application.php @@ -8,8 +8,10 @@ use Keboola\App\ProjectBackup\Config\Config; use Keboola\App\ProjectBackup\Storages\AwsS3Storage; use Keboola\App\ProjectBackup\Storages\AzureBlobStorage; +use Keboola\App\ProjectBackup\Storages\GoogleCloudStorage; use Keboola\App\ProjectBackup\Storages\IStorage; use Keboola\Component\UserException; +use Keboola\ProjectBackup\GcsBackup; use Keboola\StorageApi\Client as StorageApi; use Psr\Log\LoggerInterface; @@ -37,6 +39,9 @@ public function __construct(Config $config, LoggerInterface $logger) case Config::STORAGE_BACKEND_ABS: $this->storageBackend = new AzureBlobStorage($config->getAbsConfig(), $logger); break; + case Config::STORAGE_BACKEND_GCS: + $this->storageBackend = new GoogleCloudStorage($config->getGcsConfig(), $logger); + break; default: throw new UserException(sprintf( 'Unknown storage backend type "%s".', @@ -73,6 +78,10 @@ public function run(): void $backup->backupTriggers(); $backup->backupNotifications(); $backup->backupPermanentFiles(); + + if ($backup instanceof GcsBackup && !$this->config->isUserDefinedCredentials()) { + $backup->backupSignedUrls(); + } } public function generateReadCredentials(): array diff --git a/src/Config/Config.php b/src/Config/Config.php index 48da2bd..4ea6b91 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -12,6 +12,8 @@ class Config extends BaseConfig public const STORAGE_BACKEND_ABS = 'abs'; + public const STORAGE_BACKEND_GCS = 'gcs'; + public function getBackupId(): string { return $this->getStringValue(['parameters', 'backupId'], ''); @@ -71,4 +73,9 @@ public function getAbsConfig(): AbsConfig { return new AbsConfig($this->getCredentialsParameters()); } + + public function getGcsConfig(): GcsConfig + { + return new GcsConfig($this->getCredentialsParameters(), $this->isUserDefinedCredentials()); + } } diff --git a/src/Config/GcsConfig.php b/src/Config/GcsConfig.php new file mode 100644 index 0000000..c367b13 --- /dev/null +++ b/src/Config/GcsConfig.php @@ -0,0 +1,39 @@ +jsonKey = $params['#jsonKey']; + $this->bucket = $params['bucket']; + $this->region = $params['region']; + } + + public function getJsonKey(): string + { + return $this->jsonKey; + } + + public function getBucket(): string + { + return $this->bucket; + } + + public function getRegion(): string + { + return $this->region; + } + + public function isUserDefinedCredentials(): bool + { + return $this->isUserDefinedCredentials; + } +} diff --git a/src/Storages/GoogleCloudStorage.php b/src/Storages/GoogleCloudStorage.php new file mode 100644 index 0000000..c52ddd7 --- /dev/null +++ b/src/Storages/GoogleCloudStorage.php @@ -0,0 +1,46 @@ + json_decode($this->config->getJsonKey(), true), + ]); + + return new GcsBackup( + sapiClient: $sapi, + storageClient: $storageClient, + bucketName: $this->config->getBucket(), + path: $path, + generateSignedUrls: $this->config->isUserDefinedCredentials(), + logger: $this->logger, + ); + } +}