diff --git a/LICENSES/AGPL-3.0-only.txt b/LICENSES/AGPL-3.0-only.txt index 0c97efd2..95012857 100644 --- a/LICENSES/AGPL-3.0-only.txt +++ b/LICENSES/AGPL-3.0-only.txt @@ -23,7 +23,7 @@ An older license, called the Affero General Public License and published by Affe The precise terms and conditions for copying, distribution and modification follow. - TERMS AND CONDITIONS + TERMS AND CONDITIONS 0. Definitions. @@ -219,14 +219,14 @@ If you develop a new program, and you want it to be of the greatest possible use To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + + Copyright (C) - 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 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. + 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 . + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt index 0e259d42..d242f293 100644 --- a/LICENSES/CC0-1.0.txt +++ b/LICENSES/CC0-1.0.txt @@ -43,22 +43,22 @@ Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; + communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; + likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; + subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; + in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. + world based on applicable law or treaty, and any national + implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, diff --git a/Makefile b/Makefile index 64b897f9..6ebbb1c0 100644 --- a/Makefile +++ b/Makefile @@ -129,6 +129,7 @@ appstore: build --exclude="$(source_build_directory)/psalm.xml" \ --exclude="$(source_build_directory)/webpack.config.json" \ --exclude="$(source_build_directory)/stylelint.config.json" \ + --exclude="$(source_build_directory)/empty-skeleton.config.php" \ --exclude="$(source_build_directory)/scoper.inc.php" \ --exclude="$(source_build_directory)/renovate.json" \ --exclude="$(source_build_directory)/renovate.json.license" \ diff --git a/appinfo/routes.php b/appinfo/routes.php index 0eef46a7..0d0741d2 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -26,6 +26,7 @@ ['name' => 'settings#getSendMailSummaryOfMaliciousFiles', 'url' => '/getSendMailSummaryOfMaliciousFiles', 'verb' => 'GET'], ['name' => 'settings#setSendMailSummaryOfMaliciousFiles', 'url' - => '/setSendMailSummaryOfMaliciousFiles', 'verb' => 'POST'] + => '/setSendMailSummaryOfMaliciousFiles', 'verb' => 'POST'], + ['name' => 'settings#testsettings', 'url' => '/testsettings', 'verb' => 'POST'] ] ]; diff --git a/composer.json b/composer.json index 0e1b7989..1f99715d 100644 --- a/composer.json +++ b/composer.json @@ -30,12 +30,12 @@ }, "scripts": { "lint": "find . -name \\*.php -not -path './vendor/*' -not -path './nextcloud-server/*' -not -path './node_modules/*' -print0 | xargs -0 -n1 php -l", - "cs:check": "rm -rf node_modules/ nextcloud-server/ || true && ./vendor/bin/php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.dist.php .", - "cs:fix": "rm -rf node_modules/ nextcloud-server/ || true && ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php .", - "psalm": "rm -rf node_modules/ || true && vendor/psalm/phar/psalm.phar", - "psalm:check": "rm -rf node_modules/ || true && composer run psalm -- --threads=1 --monochrome --no-progress --output-format=github --show-info=true", - "psalm:fix": "rm -rf node_modules/ || true && composer run psalm -- --alter --issues=MissingOverrideAttribute,ClassMustBeFinal,PossiblyUnusedMethod,MissingParamType", - "psalm:clear": "vendor/psalm/phar/psalm.phar --clear-cache && vendor/psalm/phar/psalm.phar --clear-global-cache" + "cs:check": "./vendor/bin/php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.dist.php .", + "cs:fix": "./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php .", + "psalm": "./vendor/psalm/phar/psalm.phar", + "psalm:check": "composer run psalm -- --threads=1 --monochrome --no-progress --output-format=github --show-info=true", + "psalm:fix": "composer run psalm -- --alter --issues=MissingOverrideAttribute,ClassMustBeFinal,PossiblyUnusedMethod,MissingParamType", + "psalm:clear": "./vendor/psalm/phar/psalm.phar --clear-cache && vendor/psalm/phar/psalm.phar --clear-global-cache" }, "config": { "allow-plugins": { diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index f28a7e4a..6ed5d532 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -7,17 +7,23 @@ namespace OCA\GDataVaas\Controller; use OCA\GDataVaas\Service\TagService; +use OCA\GDataVaas\Service\VerdictService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\JSONResponse; use OCP\DB\Exception; use OCP\IAppConfig; use OCP\IRequest; use OCP\Mail\IMailer; +use VaasSdk\Exceptions\VaasAuthenticationException; +use VaasSdk\Options\VaasOptions; +use VaasSdk\Vaas; +use VaasSdk\Verdict; class SettingsController extends Controller { private IAppConfig $config; private TagService $tagService; private IMailer $mailer; + private VerdictService $verdictService; public function __construct( $appName, @@ -25,11 +31,13 @@ public function __construct( IAppConfig $config, TagService $tagService, IMailer $mailer, + VerdictService $verdictService, ) { parent::__construct($appName, $request); $this->config = $config; $this->tagService = $tagService; $this->mailer = $mailer; + $this->verdictService = $verdictService; } public function setconfig( @@ -154,4 +162,28 @@ public function setSendMailSummaryOfMaliciousFiles(bool $sendMailSummaryOfMalici $this->config->setValueBool($this->appName, 'notifyAdminEnabled', $sendMailSummaryOfMaliciousFiles); return new JSONResponse(['status' => 'success']); } + + public function testSettings(string $tokenEndpoint, string $vaasUrl): JSONResponse { + try { + $authenticator = $this->verdictService->getAuthenticator($this->verdictService->authMethod, $tokenEndpoint); + $options = new VaasOptions(true, true, $vaasUrl); + $vaas = Vaas::builder() + ->withAuthenticator($authenticator) + ->withOptions($options) + ->build(); + $verdict = $vaas->forUrlAsync('https://www.gdata.de')->await(); + if ($verdict->verdict === Verdict::CLEAN) { + return new JSONResponse(['status' => 'success']); + } + return new JSONResponse(['status' => 'error', 'message' => 'Test URL verdict: ' . $verdict->verdict->value]); + } catch (VaasAuthenticationException $e) { + return new JSONResponse([ + 'status' => 'error', + 'message' => 'Authentication failed. Please also check your login details above and save them before + taking the test. ' . $e->getMessage() + ]); + } catch (\Exception $e) { + return new JSONResponse(['status' => 'error', 'message' => $e->getMessage()]); + } + } } diff --git a/lib/Service/VerdictService.php b/lib/Service/VerdictService.php index 5c5f06a5..5a14dd1a 100644 --- a/lib/Service/VerdictService.php +++ b/lib/Service/VerdictService.php @@ -28,7 +28,7 @@ class VerdictService { private string $password; private string $clientId; private string $clientSecret; - private string $authMethod; + public string $authMethod; private string $tokenEndpoint; private string $vaasUrl; private IAppConfig $appConfig; @@ -212,31 +212,33 @@ public function createAndConnectVaas(): Vaas { } $options = new VaasOptions(true, true, $this->vaasUrl); return Vaas::builder() - ->withAuthenticator($this->getAuthenticator($this->authMethod)) + ->withAuthenticator($this->getAuthenticator($this->authMethod, $this->tokenEndpoint)) ->withOptions($options) ->build(); } /** * @param string $authMethod + * @param string $tokenEndpoint * @return ClientCredentialsGrantAuthenticator|ResourceOwnerPasswordGrantAuthenticator * @throws VaasAuthenticationException */ public function getAuthenticator( string $authMethod, + string $tokenEndpoint, ): ClientCredentialsGrantAuthenticator|ResourceOwnerPasswordGrantAuthenticator { if ($authMethod === 'ResourceOwnerPassword') { return new ResourceOwnerPasswordGrantAuthenticator( 'nextcloud-customer', $this->username, $this->password, - $this->tokenEndpoint + $tokenEndpoint ); } elseif ($authMethod === 'ClientCredentials') { return new ClientCredentialsGrantAuthenticator( $this->clientId, $this->clientSecret, - $this->tokenEndpoint + $tokenEndpoint ); } else { throw new VaasAuthenticationException('Invalid auth method: ' . $authMethod); diff --git a/lib/Settings/VaasAdminSection.php b/lib/Settings/VaasAdminSection.php index 4db67608..98b0920a 100644 --- a/lib/Settings/VaasAdminSection.php +++ b/lib/Settings/VaasAdminSection.php @@ -17,7 +17,7 @@ public function __construct( #[\Override] public function getName(): string { - return 'Verdict-as-a-Service'; + return 'G DATA Antivirus'; } #[\Override] diff --git a/psalm.xml b/psalm.xml index fe3720ea..abf986aa 100644 --- a/psalm.xml +++ b/psalm.xml @@ -19,6 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later + diff --git a/src/admin-settings.js b/src/admin-settings.js index 9aa44260..56a0a494 100644 --- a/src/admin-settings.js +++ b/src/admin-settings.js @@ -38,6 +38,7 @@ document.addEventListener('DOMContentLoaded', async () => { const authSubmit = document.querySelector('#auth_submit'); const authSubmitAdvanced = document.querySelector('#auth_submit_advanced'); + const testSettings = document.querySelector('#test-settings'); const resetAllTags = document.querySelector('#reset'); const autoScanFiles = document.querySelector('#auto_scan_files'); const prefixMalicious = document.querySelector('#prefixMalicious'); @@ -91,6 +92,24 @@ document.addEventListener('DOMContentLoaded', async () => { } }); + testSettings.addEventListener('click', async (e) => { + e.preventDefault(); + const tokenEndpoint = document.querySelector('#token_endpoint').value; + const vaasUrl = document.querySelector('#vaas_url').value; + + const response = await postData(OC.generateUrl('apps/gdatavaas/testsettings'), { + tokenEndpoint, + vaasUrl + }); + const msgElement = document.querySelector('#auth_save_msg_advanced'); + + if (response.status === "success") { + msgElement.textContent = 'Authentication successful and VaaS backend reachable.'; + } else { + msgElement.textContent = response.message || 'An error occurred during the test.'; + } + }); + authSubmitAdvanced.addEventListener('click', async (e) => { e.preventDefault(); const tokenEndpoint = document.querySelector('#token_endpoint').value; diff --git a/templates/admin.php b/templates/admin.php index 3895cb15..095bb5e2 100644 --- a/templates/admin.php +++ b/templates/admin.php @@ -15,8 +15,8 @@
-

G DATA Verdict-as-a-Service

-

You may use self registration and create a new username and password by yourself here for free.

+

G DATA Antivirus

+
You may use self registration and create a new username and password by yourself here for free.
@@ -73,8 +73,8 @@ Caution: The use of the "Scan only this" and "Do not scan this" settings should be approached with caution. Using these settings allows malicious users to upload and distribute malicious content via the Nextcloud instance. It is recommended that you carefully consider the implications of these settings and use them in a way that does not jeopardize the security of your system and data.
-

t('Advanced Settings'));?>

-

t('If you are not sure about this, you can just leave it blank.'));?>

+

t('Advanced Settings'));?>

+
t('If you are not sure about this, you can just leave it blank.'));?>
" class="visible">
@@ -87,11 +87,12 @@
+ -
+
diff --git a/tests/unittests/VerdictServiceTest.php b/tests/unittests/VerdictServiceTest.php index 1c389285..636966a6 100644 --- a/tests/unittests/VerdictServiceTest.php +++ b/tests/unittests/VerdictServiceTest.php @@ -211,7 +211,10 @@ public function testAuthenticator(): void { $this->createMock(FileService::class), $this->createMock(TagService::class)); - $authenticator = $verdictService->getAuthenticator('ResourceOwnerPassword'); + $authenticator = $verdictService->getAuthenticator( + 'ResourceOwnerPassword', + 'https://account-staging.gdata.de/realms/vaas-staging/protocol/openid-connect/token' + ); $this->assertInstanceOf(ResourceOwnerPasswordGrantAuthenticator::class, $authenticator); } }