diff --git a/.github/workflows/shared_workflow.yml b/.github/workflows/shared_workflow.yml
index 9facfd4f1..49e1f52a6 100644
--- a/.github/workflows/shared_workflow.yml
+++ b/.github/workflows/shared_workflow.yml
@@ -14,8 +14,6 @@ jobs:
nextcloudVersion: [ stable30 ]
phpVersion: [ 8.1, 8.2, 8.3 ]
include:
- - nextcloudVersion: stable26
- phpVersion: 8.0
- nextcloudVersion: stable27
phpVersion: 8.0
- nextcloudVersion: stable28
@@ -192,11 +190,6 @@ jobs:
phpVersionMajor: 8
phpVersionMinor: 1
database: pgsql
- # Each oldServer with the oldest PHP version and one database
- - nextcloudVersion: stable26
- phpVersionMajor: 8
- phpVersionMinor: 0
- database: mysql
- nextcloudVersion: stable27
phpVersionMajor: 8
phpVersionMinor: 0
@@ -303,10 +296,6 @@ jobs:
- name: API Tests
env:
NEXTCLOUD_BASE_URL: http://nextcloud
- BEHAT_FILTER_TAGS: ${{
- matrix.nextcloudVersion == 'stable26' && '~@skipOnStable26' ||
- ''
- }}
run: |
# The following if block can be removed once Nextcloud no longer supports PHP 8.0
if [ "${{matrix.phpVersionMajor}}" -eq 8 ] && [ "${{matrix.phpVersionMinor}}" -eq 0 ]; then
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9ed5750a4..64de5ff60 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Fix random deactivation of automatically managed project folder
- Fix avatar not found in openproject
- Enhance project search when creating workpackages from Nextcloud
+- Drop application's support for Nextcloud 26
- Fix issue preventing direct uploading of resources in Nextcloud that are managed by app `Files Access Control`
+- Hash or encrypt `client_secret` for different Nextcloud versions
## 2.6.4 - 2024-08-15
### Changed
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 5b700bc32..6afe609ab 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -41,7 +41,7 @@ For more information on how to set up and use the OpenProject application, pleas
https://github.com/nextcloud/integration_openproject/raw/master/img/screenshot1.png
https://github.com/nextcloud/integration_openproject/raw/master/img/screenshot2.png
-
+
OCA\OpenProject\BackgroundJob\RemoveExpiredDirectUploadTokens
diff --git a/lib/Service/OauthService.php b/lib/Service/OauthService.php
index e5357ddd0..21c25000e 100644
--- a/lib/Service/OauthService.php
+++ b/lib/Service/OauthService.php
@@ -47,6 +47,29 @@ public function __construct(ClientMapper $clientMapper,
$this->crypto = $crypto;
}
+ /**
+ * @param string $secret
+ * @param string $nextcloudVersion
+ * @return string
+ */
+ public function hashOrEncryptSecretBasedOnNextcloudVersion(string $secret, string $nextcloudVersion): string {
+ switch (true) {
+ case version_compare($nextcloudVersion, '30.0.0') >= 0:
+ case version_compare($nextcloudVersion, '29.0.7') >= 0 && version_compare($nextcloudVersion, '30.0.0') < 0:
+ case version_compare($nextcloudVersion, '28.0.10') >= 0 && version_compare($nextcloudVersion, '29.0.0') < 0:
+ case version_compare($nextcloudVersion, '27.1.11.8') >= 0 && version_compare($nextcloudVersion, '28.0.0') < 0:
+ $encryptedSecret = bin2hex($this->crypto->calculateHMAC($secret));
+ break;
+ case version_compare($nextcloudVersion, '27.0.0') === 0:
+ $encryptedSecret = $secret;
+ break;
+ default:
+ $encryptedSecret = $this->crypto->encrypt($secret);
+ break;
+ }
+ return $encryptedSecret;
+ }
+
/**
* @param string $name
* @param string $redirectUri
@@ -58,16 +81,8 @@ public function createNcOauthClient(string $name, string $redirectUri): array {
$client->setName($name);
$client->setRedirectUri(sprintf($redirectUri, $clientId));
$secret = $this->secureRandom->generate(64, self::validChars);
- if (version_compare(OC_Util::getVersionString(), '27.0.1') >= 0) {
- $encryptedSecret = $this->crypto->encrypt($secret);
- } elseif (version_compare(OC_Util::getVersionString(), '26.0.4') >= 0 && version_compare(OC_Util::getVersionString(), '27.0.0') < 0) {
- $encryptedSecret = $this->crypto->encrypt($secret);
- } elseif (version_compare(OC_Util::getVersionString(), '25.0.8') >= 0 && version_compare(OC_Util::getVersionString(), '26.0.0') < 0) {
- $encryptedSecret = $this->crypto->encrypt($secret);
- } else {
- $encryptedSecret = $secret;
- }
- $client->setSecret($encryptedSecret);
+ $nextcloudVersion = OC_Util::getVersionString();
+ $client->setSecret($this->hashOrEncryptSecretBasedOnNextcloudVersion($secret, $nextcloudVersion));
$client->setClientIdentifier($clientId);
$client = $this->clientMapper->insert($client);
@@ -91,8 +106,7 @@ public function getClientInfo(int $id): ?array {
'id' => $client->getId(),
'nextcloud_oauth_client_name' => $client->getName(),
'openproject_redirect_uri' => $client->getRedirectUri(),
- 'nextcloud_client_id' => $client->getClientIdentifier(),
- 'nextcloud_client_secret' => $this->crypto->decrypt($client->getSecret()),
+ 'nextcloud_client_id' => $client->getClientIdentifier()
];
} catch (ClientNotFoundException $e) {
return null;
diff --git a/tests/acceptance/features/api/setup.feature b/tests/acceptance/features/api/setup.feature
index 842e1fca4..40f165560 100644
--- a/tests/acceptance/features/api/setup.feature
+++ b/tests/acceptance/features/api/setup.feature
@@ -656,14 +656,12 @@ Feature: setup the integration through an API
"required": [
"nextcloud_oauth_client_name",
"openproject_redirect_uri",
- "nextcloud_client_id",
- "nextcloud_client_secret"
+ "nextcloud_client_id"
],
"properties": {
"nextcloud_oauth_client_name": {"type": "string", "pattern": "^OpenProject client$"},
"openproject_redirect_uri": {"type": "string", "pattern": "^http:\/\/some-host.de\/oauth_clients\/[A-Za-z0-9]+\/callback$"},
"nextcloud_client_id": {"type": "string", "pattern": "[A-Za-z0-9]+"},
- "nextcloud_client_secret": {"type": "string", "pattern": "[A-Za-z0-9]+"},
"openproject_user_app_password": {"type": "string", "pattern": "[A-Za-z0-9]+"}
}
}
@@ -678,9 +676,7 @@ Feature: setup the integration through an API
When user "OpenProject" sends a "PROPFIND" request to "/remote.php/webdav" using old app password
Then the HTTP status code should be "401"
- # to locally run this test the "project folder" needs to be setup already
- # issue of group folder https://github.com/nextcloud/groupfolders/issues/2718
- @skipOnStable25 @skipOnStable26
+
Scenario: check version of uploaded file inside a group folder
Given user "Carol" has been created
And user "Carol" has been added to the group "OpenProject"
@@ -693,9 +689,7 @@ Feature: setup the integration through an API
When user "Carol" deletes folder "/OpenProject/OpenProject/project-demo"
Then the HTTP status code should be 204
- # to locally run this test the "project folder" needs to be setup already
- # issue of group folder https://github.com/nextcloud/groupfolders/issues/2718
- @skipOnStable25 @skipOnStable26
+
Scenario: check version of uploaded file after an update inside a group folder
Given user "Carol" has been created
And user "Carol" has been added to the group "OpenProject"
diff --git a/tests/lib/Reference/WorkPackageReferenceProviderTest.php b/tests/lib/Reference/WorkPackageReferenceProviderTest.php
index b17ff704a..c7cfa16d3 100644
--- a/tests/lib/Reference/WorkPackageReferenceProviderTest.php
+++ b/tests/lib/Reference/WorkPackageReferenceProviderTest.php
@@ -24,7 +24,6 @@
namespace OCA\OpenProject\Reference;
use OC\Collaboration\Reference\ReferenceManager;
-use OC_Util;
use OCA\OpenProject\AppInfo\Application;
use OCA\OpenProject\Service\OpenProjectAPIService;
use OCP\IConfig;
@@ -34,12 +33,6 @@
use PHPUnit\Framework\TestCase;
class WorkPackageReferenceProviderTest extends TestCase {
- protected function setUp(): void {
- if (version_compare(OC_Util::getVersionString(), '26') < 0) {
- $this->markTestSkipped('WorkPackageReferenceProvider is only available from nextcloud 26 so skip the tests on versions below');
- }
- }
-
/**
*
* @param array $onlyMethods
diff --git a/tests/lib/Service/OauthSeviceTest.php b/tests/lib/Service/OauthSeviceTest.php
new file mode 100644
index 000000000..e49242989
--- /dev/null
+++ b/tests/lib/Service/OauthSeviceTest.php
@@ -0,0 +1,123 @@
+
+ *
+ * @author Your name
+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\OpenProject\Service;
+
+use OCA\OAuth2\Db\ClientMapper;
+use OCP\Security\ICrypto;
+use OCP\Security\ISecureRandom;
+use PHPUnit\Framework\TestCase;
+
+class OauthServiceTest extends TestCase {
+ protected function getOauthServiceMock(
+ $clientMapperMock = null,
+ $iSecureRandomMock = null,
+ $iCryptoMock = null,
+ ): OauthService {
+
+ if ($clientMapperMock === null) {
+ $clientMapperMock = $this->getMockBuilder(ClientMapper::class)->disableOriginalConstructor()->getMock();
+ }
+ if ($iSecureRandomMock === null) {
+ $iSecureRandomMock = $this->getMockBuilder(ISecureRandom::class)->getMock();
+ }
+ if ($iCryptoMock === null) {
+ $iCryptoMock = $this->getMockBuilder(ICrypto::class)->getMock();
+ }
+
+ return new OauthService(
+ $clientMapperMock,
+ $iSecureRandomMock,
+ $iCryptoMock
+ );
+ }
+
+
+ /**
+ * @return array
+ */
+ public function gethashOrEncryptSecretBasedOnNextcloudVersion(): array {
+ return [
+ [
+ "30.0.0",
+ "calculateHMAC"
+ ],
+ [
+ "29.0.7",
+ "calculateHMAC"
+ ],
+ [
+ "29.1.0",
+ "calculateHMAC"
+ ],
+ [
+ "29.0.6",
+ "encrypt"
+ ],
+ [
+ "28.0.10",
+ "calculateHMAC"
+ ],
+ [
+ "28.2.0",
+ "calculateHMAC"
+ ],
+ [
+ "28.0.0",
+ "encrypt"
+ ],
+ [
+ "29.0.0",
+ "encrypt"
+ ],
+ [
+ "27.1.11.8",
+ "calculateHMAC"
+ ],
+ [
+ "27.1.12.0",
+ "calculateHMAC"
+ ],
+ [
+ "27.1.1.0",
+ "encrypt"
+ ]
+ ];
+ }
+
+
+ /**
+ * @dataProvider gethashOrEncryptSecretBasedOnNextcloudVersion
+ * @param string $nextcloudVersion
+ * @param string $hashOrEncryptFunction
+ *
+ * @return void
+ *
+ */
+ public function testGetHashedOrEncryptedClientSecretBasedOnNextcloudVersions(string $nextcloudVersion, string $hashOrEncryptFunction) {
+ $iCryptoMock = $this->getMockBuilder(ICrypto::class)->getMock();
+ $oAuthService = $this->getOauthServiceMock(null, null, $iCryptoMock);
+ $iCryptoMock->expects($this->once())->method($hashOrEncryptFunction);
+ $oAuthService->hashOrEncryptSecretBasedOnNextcloudVersion("client_secret", $nextcloudVersion);
+ }
+}
diff --git a/tests/lib/Service/OpenProjectAPIServiceTest.php b/tests/lib/Service/OpenProjectAPIServiceTest.php
index 68ce11d77..50f0d5906 100644
--- a/tests/lib/Service/OpenProjectAPIServiceTest.php
+++ b/tests/lib/Service/OpenProjectAPIServiceTest.php
@@ -19,7 +19,6 @@
use OC\Authentication\Token\IToken;
use OC\Avatar\GuestAvatar;
use OC\Http\Client\Client;
-use OC_Util;
use OCA\GroupFolders\Folder\FolderManager;
use OCA\OpenProject\AppInfo\Application;
use OCA\OpenProject\Exception\OpenprojectErrorException;
@@ -639,53 +638,37 @@ private function getOpenProjectAPIService(
$ocClient = null;
$client = new GuzzleClient();
$clientConfigMock = $this->getMockBuilder(IConfig::class)->getMock();
-
- if (version_compare(OC_Util::getVersionString(), '27') >= 0) {
- $clientConfigMock
- ->method('getSystemValueBool')
- ->withConsecutive(
- ['allow_local_remote_servers', false],
- ['installed', false],
- ['allow_local_remote_servers', false],
- ['allow_local_remote_servers', false],
- ['installed', false],
- ['allow_local_remote_servers', false],
- ['allow_local_remote_servers', false],
- ['installed', false],
- ['allow_local_remote_servers', false]
- )
- ->willReturnOnConsecutiveCalls(
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true
- );
- //changed from nextcloud 26
- $ocClient = new Client(
- $clientConfigMock,
- $certificateManager,
- $client,
- $this->createMock(IRemoteHostValidator::class),
- $this->createMock(LoggerInterface::class));
- } elseif (version_compare(OC_Util::getVersionString(), '26') >= 0) {
- $clientConfigMock
+ $clientConfigMock
->method('getSystemValueBool')
- ->with('allow_local_remote_servers', false)
- ->willReturn(true);
-
- //changed from nextcloud 26
- $ocClient = new Client(
- $clientConfigMock,
- $certificateManager,
- $client,
- $this->createMock(IRemoteHostValidator::class)
+ ->withConsecutive(
+ ['allow_local_remote_servers', false],
+ ['installed', false],
+ ['allow_local_remote_servers', false],
+ ['allow_local_remote_servers', false],
+ ['installed', false],
+ ['allow_local_remote_servers', false],
+ ['allow_local_remote_servers', false],
+ ['installed', false],
+ ['allow_local_remote_servers', false]
+ )
+ ->willReturnOnConsecutiveCalls(
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
);
- }
+ //changed from nextcloud 26
+ $ocClient = new Client(
+ $clientConfigMock,
+ $certificateManager,
+ $client,
+ $this->createMock(IRemoteHostValidator::class),
+ $this->createMock(LoggerInterface::class));
$clientService = $this->getMockBuilder('\OCP\Http\Client\IClientService')->getMock();
$clientService->method('newClient')->willReturn($ocClient);